QGIS API Documentation  2.18.21-Las Palmas (9fba24a)
qgslegendmodel.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgslegendmodel.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 
18 #include "qgslegendmodel.h"
19 #include "qgscomposerlegenditem.h"
20 #include "qgsfield.h"
21 #include "qgslayertree.h"
22 #include "qgsmaplayer.h"
23 #include "qgsmaplayerregistry.h"
24 #include "qgsrasterlayer.h"
25 #include "qgsrendererv2.h"
26 #include "qgssymbollayerv2utils.h"
27 #include "qgsvectordataprovider.h"
28 #include "qgsvectorlayer.h"
29 #include <QApplication>
30 #include <QDomDocument>
31 #include <QDomElement>
32 #include <QMimeData>
33 #include <QSettings>
34 #include <QMessageBox>
35 
37 {
38  setColumnCount( 2 );
39 
41  {
42  connect( QgsMapLayerRegistry::instance(), SIGNAL( layerWillBeRemoved( QString ) ), this, SLOT( removeLayer( const QString& ) ) );
43  connect( QgsMapLayerRegistry::instance(), SIGNAL( layerWasAdded( QgsMapLayer* ) ), this, SLOT( addLayer( QgsMapLayer* ) ) );
44  }
45 
46  QWidgetList topLevelWidgets = QApplication::topLevelWidgets();
47  mHasTopLevelWindow = ( !topLevelWidgets.isEmpty() );
48 }
49 
51 {
52 }
53 
55 {
56  clear();
57  addGroupFromLayerTree( rootGroup, invisibleRootItem() );
58 }
59 
60 void QgsLegendModel::addGroupFromLayerTree( QgsLayerTreeGroup* parentGroup, QStandardItem* parentItem )
61 {
62  Q_FOREACH ( QgsLayerTreeNode* node, parentGroup->children() )
63  {
64  if ( QgsLayerTree::isGroup( node ) )
65  {
66  QgsLayerTreeGroup* nodeGroup = QgsLayerTree::toGroup( node );
67  QStandardItem* groupItem = addGroup( nodeGroup->name(), -1, parentItem );
68  addGroupFromLayerTree( nodeGroup, groupItem );
69  }
70  else if ( QgsLayerTree::isLayer( node ) )
71  {
72  QgsLayerTreeLayer* nodeLayer = QgsLayerTree::toLayer( node );
73  if ( nodeLayer->layer() )
74  addLayer( nodeLayer->layer(), -1, QString(), parentItem );
75  }
76  }
77 }
78 
80 {
81  setLayerSet( layerIds );
82 
83  QStandardItem* currentItem = nullptr;
84  QStandardItem* currentGroupItem = nullptr;
85  int i = 0;
86 
88  for ( ; infoIt != groupInfo.constEnd() && i < invisibleRootItem()->rowCount(); )
89  {
90  currentItem = invisibleRootItem()->child( i, 0 );
91  QString infoKey = infoIt->first;
92  if ( infoKey.isNull() ) //a toplevel layer
93  {
94  ++i;
95  }
96  else //a group
97  {
98  currentGroupItem = addGroup( infoKey, i );
99  ++i;
100  QList<QString> layerList = infoIt->second;
101  QList<QString>::const_iterator groupLayerIt = layerList.constBegin();
102  for ( ; currentItem && ( groupLayerIt != layerList.constEnd() ); ++groupLayerIt )
103  {
104  //check if current item is contained in this group
105  QgsComposerLayerItem* layerItem = dynamic_cast<QgsComposerLayerItem*>( currentItem );
106  if ( !layerItem )
107  {
108  return; //should never happen
109  }
110  QString layerID = layerItem->layerID();
111  if ( layerList.contains( layerID ) )
112  {
113  takeRow( i );
114  currentGroupItem->setChild( currentGroupItem->rowCount(), 0, currentItem );
115  }
116  else
117  {
118  ++i;
119  }
120  currentItem = invisibleRootItem()->child( i, 0 );
121  }
122  }
123  ++infoIt;
124  }
125 }
126 
127 void QgsLegendModel::setLayerSet( const QStringList& layerIds, double scaleDenominator, const QString& rule )
128 {
129  mLayerIds = layerIds;
130 
131  //for now clear the model and add the new entries
132  clear();
133 
135  QgsMapLayer* currentLayer = nullptr;
136 
137  for ( ; idIter != mLayerIds.constEnd(); ++idIter )
138  {
139  currentLayer = QgsMapLayerRegistry::instance()->mapLayer( *idIter );
140  addLayer( currentLayer, scaleDenominator, rule );
141  }
142 }
143 
144 QStandardItem* QgsLegendModel::addGroup( QString text, int position, QStandardItem* parentItem )
145 {
146  if ( text.isNull() )
147  text = tr( "Group" );
148 
149  if ( !parentItem )
150  parentItem = invisibleRootItem();
151 
152  QgsComposerGroupItem* groupItem = new QgsComposerGroupItem( text );
153  groupItem->setUserText( text );
154 
155  if ( position == -1 )
156  {
157  position = parentItem->rowCount();
158  }
159  QList<QStandardItem *> itemsList;
160  itemsList << groupItem << new QgsComposerStyleItem( groupItem );
161  parentItem->insertRow( position, itemsList );
162 
163  emit layersChanged();
164  return groupItem;
165 }
166 
167 int QgsLegendModel::addVectorLayerItemsV2( QStandardItem* layerItem, QgsVectorLayer* vlayer, double scaleDenominator, const QString& rule )
168 {
169  QgsComposerLayerItem* lItem = dynamic_cast<QgsComposerLayerItem*>( layerItem );
170 
171  if ( !layerItem || !lItem || !vlayer )
172  {
173  return 1;
174  }
175 
176  QgsFeatureRendererV2* renderer = vlayer->rendererV2();
177  if ( !renderer )
178  {
179  return 2;
180  }
181 
182  if ( lItem->showFeatureCount() )
183  {
184  if ( !vlayer->countSymbolFeatures() )
185  {
186  QgsDebugMsg( "Cannot get feature counts" );
187  }
188  }
189 
190  QgsLegendSymbolList lst = renderer->legendSymbolItems( scaleDenominator, rule );
192  int row = 0;
193  for ( ; symbolIt != lst.constEnd(); ++symbolIt )
194  {
195  if ( qgsDoubleNear( scaleDenominator, -1 ) && rule.isEmpty() )
196  {
197  QgsComposerSymbolV2Item* currentSymbolItem = new QgsComposerSymbolV2Item( "" );
198 
199  // Get userText from old item if exists
200  QgsComposerSymbolV2Item* oldSymbolItem = dynamic_cast<QgsComposerSymbolV2Item*>( layerItem->child( row, 0 ) );
201  if ( oldSymbolItem )
202  {
203  currentSymbolItem->setUserText( oldSymbolItem->userText() );
204  }
205 
206  currentSymbolItem->setFlags( Qt::ItemIsEnabled | Qt::ItemIsSelectable );
207  if ( symbolIt->second )
208  {
209  if ( mHasTopLevelWindow ) //only use QIcon / QPixmap if we have a running x-server
210  {
211  currentSymbolItem->setIcon( QgsSymbolLayerV2Utils::symbolPreviewIcon( symbolIt->second, QSize( 30, 30 ) ) );
212  }
213  currentSymbolItem->setSymbolV2( symbolIt->second->clone() );
214  }
215  layerItem->setChild( row, 0, currentSymbolItem );
216 
217  // updateSymbolV2ItemText needs layer set
218  updateSymbolV2ItemText( currentSymbolItem );
219  }
220  else
221  {
222  QgsComposerSymbolV2Item* currentSymbolItem = new QgsComposerSymbolV2Item( "" );
223  if ( mHasTopLevelWindow ) //only use QIcon / QPixmap if we have a running x-server
224  {
225  currentSymbolItem->setIcon( QgsSymbolLayerV2Utils::symbolPreviewIcon( symbolIt->second, QSize( 30, 30 ) ) );
226  }
227  currentSymbolItem->setSymbolV2( symbolIt->second->clone() );
228  layerItem->setChild( row, 0, currentSymbolItem );
229  currentSymbolItem->setText( symbolIt->first );
230  }
231 
232  row++;
233  }
234 
235  // Don't remove row on getLegendGraphic (read only with filter)
236  if ( qgsDoubleNear( scaleDenominator, -1 ) && rule.isEmpty() )
237  {
238  // Delete following old items (if current number of items decreased)
239  for ( int i = layerItem->rowCount() - 1; i >= row; --i )
240  {
241  layerItem->removeRow( i );
242  }
243  }
244 
245  return 0;
246 }
247 
248 int QgsLegendModel::addRasterLayerItems( QStandardItem* layerItem, QgsMapLayer* rlayer )
249 {
250  if ( !layerItem || !rlayer )
251  {
252  return 1;
253  }
254 
255  QgsRasterLayer* rasterLayer = qobject_cast<QgsRasterLayer *>( rlayer );
256  if ( !rasterLayer )
257  {
258  return 2;
259  }
260 
261  QgsDebugMsg( QString( "layer providertype:: %1" ).arg( rasterLayer->providerType() ) );
262  if ( rasterLayer->dataProvider()->supportsLegendGraphic() )
263  {
264  QgsComposerRasterSymbolItem* currentSymbolItem = new QgsComposerRasterSymbolItem( "" );
265  // GetLegendGraphics in case of WMS service... image can return null if GetLegendGraphics
266  // is not supported by the server
267  // double currentScale = legend()->canvas()->scale();
268  // BEWARE getLegendGraphic() COULD BE USED WITHOUT SCALE PARAMETER IF IT WAS ALREADY CALLED WITH
269  // THIS PARAMETER FROM A COMPONENT THAT CAN RECOVER CURRENT SCALE => LEGEND IN THE DESKTOP
270  // OTHERWISE IT RETURN A INVALID PIXMAP (QPixmap().isNull() == False)
271  QImage legendGraphic = rasterLayer->dataProvider()->getLegendGraphic();
272  if ( !legendGraphic.isNull() )
273  {
274  QgsDebugMsg( QString( "downloaded legend with dimension width:" ) + QString::number( legendGraphic.width() ) + QString( " and Height:" ) + QString::number( legendGraphic.height() ) );
275  if ( mHasTopLevelWindow )
276  {
277  currentSymbolItem->setIcon( QIcon( QPixmap::fromImage( legendGraphic ) ) );
278  }
279  }
280  else
281  {
282  currentSymbolItem->setText( tr( "No Legend Available" ) );
283  }
284 
285  currentSymbolItem->setLayerID( rasterLayer->id() );
286  currentSymbolItem->setColor( QColor() );
287  layerItem->removeRows( 0, layerItem->rowCount() );
288  layerItem->setChild( layerItem->rowCount(), 0, currentSymbolItem );
289  }
290  else
291  {
292  QList< QPair< QString, QColor > > rasterItemList = rasterLayer->legendSymbologyItems();
293  QList< QPair< QString, QColor > >::const_iterator itemIt = rasterItemList.constBegin();
294  int row = 0;
295  for ( ; itemIt != rasterItemList.constEnd(); ++itemIt )
296  {
297  QgsComposerRasterSymbolItem* currentSymbolItem = new QgsComposerRasterSymbolItem( itemIt->first );
298 
299  QgsComposerRasterSymbolItem* oldSymbolItem = dynamic_cast<QgsComposerRasterSymbolItem*>( layerItem->child( row, 0 ) );
300  if ( oldSymbolItem )
301  {
302  currentSymbolItem->setUserText( oldSymbolItem->userText() );
303  currentSymbolItem->setText( currentSymbolItem->userText() );
304  }
305 
306  if ( mHasTopLevelWindow )
307  {
308  QPixmap itemPixmap( 20, 20 );
309  itemPixmap.fill( itemIt->second );
310  currentSymbolItem->setIcon( QIcon( itemPixmap ) );
311  }
312  currentSymbolItem->setLayerID( rasterLayer->id() );
313 
314  QColor itemColor = itemIt->second;
315 
316  //determine raster layer opacity, and adjust item color opacity to match
317  QgsRasterRenderer* rasterRenderer = rasterLayer->renderer();
318  int opacity = 255;
319  if ( rasterRenderer )
320  {
321  opacity = rasterRenderer->opacity() * 255.0;
322  }
323  itemColor.setAlpha( opacity );
324 
325  currentSymbolItem->setColor( itemColor );
326 
327  int currentRowCount = layerItem->rowCount();
328  layerItem->setChild( currentRowCount, 0, currentSymbolItem );
329  row++;
330  }
331 
332  // Delete following old items (if current number of items decreased)
333  for ( int i = layerItem->rowCount() - 1; i >= row; --i )
334  {
335  layerItem->removeRow( i );
336  }
337  }
338 
339  return 0;
340 }
341 
342 void QgsLegendModel::updateSymbolV2ItemText( QStandardItem* symbolItem )
343 {
344  QgsComposerSymbolV2Item* sv2Item = dynamic_cast<QgsComposerSymbolV2Item*>( symbolItem );
345  if ( !sv2Item ) return;
346 
347  QgsComposerLayerItem* lItem = dynamic_cast<QgsComposerLayerItem*>( sv2Item->parent() );
348  if ( !lItem ) return;
349 
350  QgsMapLayer* mapLayer = QgsMapLayerRegistry::instance()->mapLayer( lItem->layerID() );
351  if ( !mapLayer ) return;
352 
353  QgsVectorLayer* vLayer = qobject_cast<QgsVectorLayer*>( mapLayer );
354  if ( !vLayer ) return;
355 
356  QgsFeatureRendererV2* renderer = vLayer->rendererV2();
357  if ( !renderer ) return;
358 
359  if ( lItem->showFeatureCount() ) vLayer->countSymbolFeatures();
360 
361  QgsLegendSymbolList symbolList = renderer->legendSymbolItems();
362 
363  QPair<QString, QgsSymbolV2*> symbol = symbolList.value( symbolItem->row() );
364 
365  QString label = sv2Item->userText().isEmpty() ? symbol.first : sv2Item->userText();
366 
367  if ( renderer->type() == "singleSymbol" )
368  {
369  if ( !sv2Item->userText().isEmpty() )
370  {
371  label = sv2Item->userText();
372  }
373  else if ( !lItem->userText().isEmpty() )
374  {
375  label = lItem->userText();
376  }
377  else if ( !vLayer->title().isEmpty() )
378  {
379  label = vLayer->title();
380  }
381  else
382  {
383  label = vLayer->name();
384  }
385  }
386 
387  if ( lItem->showFeatureCount() )
388  {
389  // Add counts to multi symbols layers only or labeled single symbols,
390  // so that single symbol layers are still drawn on single line
391  if ( symbolList.size() > 1 || !label.isEmpty() )
392  {
393  label += QString( " [%1]" ).arg( vLayer->featureCount( symbol.second ) );
394  }
395  }
396  symbolItem->setText( label );
397 }
398 
399 void QgsLegendModel::updateRasterSymbolItemText( QStandardItem* symbolItem )
400 {
401  QgsComposerRasterSymbolItem* rItem = dynamic_cast<QgsComposerRasterSymbolItem*>( symbolItem );
402  if ( !rItem ) return;
403 
404  QgsComposerLayerItem* lItem = dynamic_cast<QgsComposerLayerItem*>( rItem->parent() );
405  if ( !lItem ) return;
406 
407  QgsMapLayer* mapLayer = QgsMapLayerRegistry::instance()->mapLayer( lItem->layerID() );
408  if ( !mapLayer ) return;
409 
410  QgsRasterLayer* rLayer = qobject_cast<QgsRasterLayer*>( mapLayer );
411  if ( !rLayer ) return;
412 
413  QPair< QString, QColor> symbol = rLayer->legendSymbologyItems().value( symbolItem->row() );
414 
415  QString label = rItem->userText().isEmpty() ? symbol.first : rItem->userText();
416 
417  symbolItem->setText( label );
418 }
419 
421 {
422  if ( !item )
423  {
424  return;
425  }
426 
427  //only layer items are supported for update
428  QgsComposerLegendItem* cItem = dynamic_cast<QgsComposerLegendItem*>( item );
429  if ( ! cItem )
430  {
431  return;
432  }
433 
435  if ( type == QgsComposerLegendItem::LayerItem )
436  {
437  updateLayer( cItem );
438  }
439 }
440 
442 {
443  if ( !item )
444  {
445  return;
446  }
447 
448  //only layer items are supported for update
449  QgsComposerLegendItem* cItem = dynamic_cast<QgsComposerLegendItem*>( item );
450  if ( ! cItem )
451  {
452  return;
453  }
454 
455  QgsComposerLayerItem* lItem = dynamic_cast<QgsComposerLayerItem*>( cItem );
456  if ( lItem )
457  {
458  updateLayerItemText( lItem );
459  return;
460  }
461 
462  QgsComposerSymbolV2Item* sv2Item = dynamic_cast<QgsComposerSymbolV2Item*>( cItem );
463  if ( sv2Item )
464  {
465  updateSymbolV2ItemText( sv2Item );
466  return;
467  }
468 
469  QgsComposerRasterSymbolItem* rItem = dynamic_cast<QgsComposerRasterSymbolItem*>( cItem );
470  if ( rItem )
471  {
472  updateRasterSymbolItemText( rItem );
473  return;
474  }
475 
476  // group
477  cItem->setText( cItem->userText() );
478 }
479 
481 {
482  QgsDebugMsg( "Entered." );
483  QgsComposerLayerItem* lItem = dynamic_cast<QgsComposerLayerItem*>( layerItem );
484  if ( lItem )
485  {
486  QgsMapLayer* mapLayer = QgsMapLayerRegistry::instance()->mapLayer( lItem->layerID() );
487  if ( mapLayer )
488  {
489  updateLayerItemText( lItem );
490 
491  QgsVectorLayer* vLayer = qobject_cast<QgsVectorLayer*>( mapLayer );
492  if ( vLayer )
493  {
494  addVectorLayerItemsV2( lItem, vLayer );
495  }
496 
497  QgsRasterLayer* rLayer = qobject_cast<QgsRasterLayer*>( mapLayer );
498  if ( rLayer )
499  {
500  addRasterLayerItems( lItem, rLayer );
501  }
502  }
503  }
504 }
505 
506 void QgsLegendModel::updateLayerItemText( QStandardItem* layerItem )
507 {
508  QgsComposerLayerItem* lItem = dynamic_cast<QgsComposerLayerItem*>( layerItem );
509  if ( !lItem ) return;
510 
511  QgsMapLayer* mapLayer = QgsMapLayerRegistry::instance()->mapLayer( lItem->layerID() );
512  if ( !mapLayer ) return;
513 
514  QString label = lItem->userText().isEmpty() ? mapLayer->name() : lItem->userText();
515 
516  QgsVectorLayer* vLayer = qobject_cast<QgsVectorLayer*>( mapLayer );
517  if ( vLayer )
518  {
519  addVectorLayerItemsV2( lItem, vLayer );
520  if ( lItem->showFeatureCount() )
521  {
522  label += QString( " [%1]" ).arg( vLayer->featureCount() );
523  }
524  }
525  lItem->setText( label );
526 }
527 
528 void QgsLegendModel::removeLayer( const QString& layerId )
529 {
530  int numRootItems = rowCount();
531  for ( int i = 0; i < numRootItems ; ++i )
532  {
533  QgsComposerLayerItem* lItem = dynamic_cast<QgsComposerLayerItem*>( item( i ) );
534  if ( !lItem )
535  {
536  continue;
537  }
538 
539  if ( layerId == lItem->layerID() )
540  {
542  {
544  if ( layer )
545  {
546  disconnect( layer, SIGNAL( rendererChanged() ), this, SLOT( updateLayer() ) );
547  }
548  }
549  removeRow( i ); //todo: also remove the subitems and their symbols...
550  emit layersChanged();
551  return;
552  }
553  }
554 }
555 
556 void QgsLegendModel::addLayer( QgsMapLayer* theMapLayer, double scaleDenominator, const QString& rule, QStandardItem* parentItem )
557 {
558  if ( !theMapLayer )
559  {
560  return;
561  }
562 
563  if ( !parentItem )
564  parentItem = invisibleRootItem();
565 
566  QgsComposerLayerItem* layerItem = new QgsComposerLayerItem( theMapLayer->name() );
567  if ( theMapLayer->title() != "" )
568  {
569  layerItem->setText( theMapLayer->title() );
570  layerItem->setUserText( theMapLayer->title() );
571  }
572  layerItem->setLayerID( theMapLayer->id() );
573  layerItem->setDefaultStyle( scaleDenominator, rule );
574  layerItem->setFlags( Qt::ItemIsEnabled | Qt::ItemIsSelectable );
575 
576  QList<QStandardItem *> itemsList;
577  itemsList << layerItem << new QgsComposerStyleItem( layerItem );
578  parentItem->appendRow( itemsList );
579 
580  switch ( theMapLayer->type() )
581  {
583  {
584  QgsVectorLayer* vl = dynamic_cast<QgsVectorLayer*>( theMapLayer );
585  if ( vl )
586  {
587  addVectorLayerItemsV2( layerItem, vl, scaleDenominator, rule );
588  }
589  break;
590  }
592  addRasterLayerItems( layerItem, theMapLayer );
593  break;
594  default:
595  break;
596  }
597 
598  if ( mAutoUpdate )
599  {
600  connect( theMapLayer, SIGNAL( rendererChanged() ), this, SLOT( updateLayer() ) );
601  }
602 
603  emit layersChanged();
604 }
605 
607 {
608  QString layerId = qobject_cast<QgsMapLayer*>( QObject::sender() )->id();
609 
610  for ( int i = 0, n = rowCount(); i < n ; ++i )
611  {
612  QgsComposerLayerItem* lItem = dynamic_cast<QgsComposerLayerItem*>( item( i ) );
613  if ( lItem && layerId == lItem->layerID() )
614  {
615  updateLayer( lItem );
616  emit layersChanged();
617  return;
618  }
619  }
620 }
621 
622 bool QgsLegendModel::writeXML( QDomElement& composerLegendElem, QDomDocument& doc ) const
623 {
624  if ( composerLegendElem.isNull() )
625  {
626  return false;
627  }
628 
629  QDomElement legendModelElem = doc.createElement( "Model" );
630  legendModelElem.setAttribute( "autoUpdate", mAutoUpdate );
631  int nTopLevelItems = invisibleRootItem()->rowCount();
632  QStandardItem* currentItem = nullptr;
633  QgsComposerLegendItem* currentLegendItem = nullptr;
634 
635  for ( int i = 0; i < nTopLevelItems; ++i )
636  {
637  currentItem = invisibleRootItem()->child( i, 0 );
638  currentLegendItem = dynamic_cast<QgsComposerLegendItem*>( currentItem );
639  if ( currentLegendItem )
640  {
641  currentLegendItem->writeXML( legendModelElem, doc );
642  }
643  }
644 
645  composerLegendElem.appendChild( legendModelElem );
646  return true;
647 }
648 
649 bool QgsLegendModel::readXML( const QDomElement& legendModelElem, const QDomDocument& doc )
650 {
651  Q_UNUSED( doc );
652 
653  if ( legendModelElem.isNull() )
654  {
655  return false;
656  }
657 
658  clear();
659  //disable autoupdates here in order to have a setAutoUpdate(true)
660  //below connect the rendererChanged signals to the layers
661  setAutoUpdate( false );
662 
663  QDomNodeList topLevelItemList = legendModelElem.childNodes();
664  QDomElement currentElem;
665 
666  int nTopLevelItems = topLevelItemList.size();
667  for ( int i = 0; i < nTopLevelItems; ++i )
668  {
669  currentElem = topLevelItemList.at( i ).toElement();
670  if ( currentElem.isNull() )
671  {
672  continue;
673  }
674 
675  //toplevel items can be groups or layers
676  QgsComposerLegendItem* currentItem = nullptr;
677  if ( currentElem.tagName() == "LayerItem" )
678  {
679  currentItem = new QgsComposerLayerItem();
680  }
681  else if ( currentElem.tagName() == "GroupItem" )
682  {
683  currentItem = new QgsComposerGroupItem();
684  }
685 
686  if ( !currentItem )
687  continue;
688 
689  currentItem->readXML( currentElem, mHasTopLevelWindow );
690 
691  QList<QStandardItem *> itemsList;
692  itemsList << currentItem << new QgsComposerStyleItem( currentItem );
693  appendRow( itemsList );
694  }
695 
696  setAutoUpdate( legendModelElem.attribute( "autoUpdate", "1" ).toInt() );
697  return true;
698 }
699 
701 {
702  return Qt::MoveAction;
703 }
704 
706 {
707  Qt::ItemFlags flags = Qt::ItemIsEnabled | Qt::ItemIsSelectable;
708  if ( !index.isValid() )
709  {
710  flags |= Qt::ItemIsDropEnabled;
711  return flags;
712  }
713 
714  QStandardItem* item = itemFromIndex( index );
715  QgsComposerLegendItem* cItem = dynamic_cast<QgsComposerLegendItem*>( item );
716 
717  if ( cItem )
718  {
720  if ( type == QgsComposerLegendItem::GroupItem )
721  {
722  flags |= Qt::ItemIsDragEnabled;
723  flags |= Qt::ItemIsDropEnabled;
724  }
725  else if ( type == QgsComposerLegendItem::LayerItem )
726  {
727  flags |= Qt::ItemIsDragEnabled;
728  }
729  }
730  if ( index.column() == 1 && item )
731  {
732  // Style
733  QStandardItem* firstColumnItem = nullptr;
734  if ( item->parent() )
735  {
736  firstColumnItem = item->parent()->child( index.row(), 0 );
737  }
738  else
739  {
740  firstColumnItem = QgsLegendModel::item( index.row(), 0 );
741  }
742  cItem = dynamic_cast<QgsComposerLegendItem*>( firstColumnItem );
743 
744  if ( cItem )
745  {
746  if ( cItem->itemType() == QgsComposerLegendItem::GroupItem ||
747  cItem->itemType() == QgsComposerLegendItem::LayerItem )
748  {
749  flags |= Qt::ItemIsEditable;
750  }
751  }
752  }
753  return flags;
754 }
755 
756 bool QgsLegendModel::removeRows( int row, int count, const QModelIndex & parent )
757 {
758  if ( count < 1 )
759  {
760  return false;
761  }
762 
763  if ( parent.isValid() )
764  {
765  for ( int i = row + count - 1; i >= row; --i )
766  {
767  QStandardItem* item = itemFromIndex( parent );
768  if ( item )
769  {
770  item->takeRow( i );
771  }
772  }
773  }
774  else
775  {
776  for ( int i = row + count - 1; i >= row; --i )
777  {
778  takeRow( i );
779  }
780  }
781  return true;
782 }
783 
784 QMimeData* QgsLegendModel::mimeData( const QModelIndexList &indexes ) const
785 {
786  QMimeData* mimeData = new QMimeData();
787  QDomDocument xmlDoc;
788  QDomElement xmlRootElement = xmlDoc.createElement( "LegendModelDragData" );
789  xmlDoc.appendChild( xmlRootElement );
790 
791  QModelIndexList::const_iterator indexIt = indexes.constBegin();
792  for ( ; indexIt != indexes.constEnd(); ++indexIt )
793  {
794  QStandardItem* sItem = itemFromIndex( *indexIt );
795  if ( sItem )
796  {
797  QgsComposerLegendItem* mItem = dynamic_cast<QgsComposerLegendItem*>( sItem );
798  if ( mItem )
799  {
800  mItem->writeXML( xmlRootElement, xmlDoc );
801  }
802  }
803  }
804  mimeData->setData( "text/xml", xmlDoc.toByteArray() );
805  return mimeData;
806 }
807 
809 {
810  QStringList types;
811  types << "text/xml";
812  return types;
813 }
814 
815 bool QgsLegendModel::dropMimeData( const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent )
816 {
817  Q_UNUSED( action );
818  Q_UNUSED( column );
819 
820  if ( !data->hasFormat( "text/xml" ) )
821  {
822  return false;
823  }
824 
825  QStandardItem* dropIntoItem = nullptr;
826  if ( parent.isValid() )
827  {
828  dropIntoItem = itemFromIndex( parent );
829  }
830  else
831  {
832  dropIntoItem = invisibleRootItem();
833  }
834 
835  //get XML doc
836  QByteArray encodedData = data->data( "text/xml" );
837  QDomDocument xmlDoc;
838  xmlDoc.setContent( encodedData );
839 
840  QDomElement dragDataElem = xmlDoc.documentElement();
841  if ( dragDataElem.tagName() != "LegendModelDragData" )
842  {
843  return false;
844  }
845 
846  QDomNodeList nodeList = dragDataElem.childNodes();
847  int nChildNodes = nodeList.size();
848  QDomElement currentElem;
849  QString currentTagName;
850  QgsComposerLegendItem* currentItem = nullptr;
851 
852  for ( int i = 0; i < nChildNodes; ++i )
853  {
854  currentElem = nodeList.at( i ).toElement();
855  if ( currentElem.isNull() )
856  {
857  continue;
858  }
859  currentTagName = currentElem.tagName();
860  if ( currentTagName == "LayerItem" )
861  {
862  currentItem = new QgsComposerLayerItem();
863  }
864  else if ( currentTagName == "GroupItem" )
865  {
866  currentItem = new QgsComposerGroupItem();
867  }
868  else
869  {
870  continue;
871  }
872  currentItem->readXML( currentElem );
873  int index;
874  if ( row < 0 )
875  {
876  index = dropIntoItem->rowCount();
877  }
878  else
879  {
880  index = row + i;
881  }
882  QList<QStandardItem *> itemsList;
883  itemsList << currentItem << new QgsComposerStyleItem( currentItem );
884  dropIntoItem->insertRow( index, itemsList );
885  }
886  emit layersChanged();
887  return true;
888 }
889 
891 {
892  if ( mAutoUpdate == autoUpdate ) //prevent multiple signal/slot connections
893  {
894  return;
895  }
896 
898  if ( autoUpdate )
899  {
901  {
902  connect( QgsMapLayerRegistry::instance(), SIGNAL( layerWillBeRemoved( QString ) ), this, SLOT( removeLayer( const QString& ) ) );
903  connect( QgsMapLayerRegistry::instance(), SIGNAL( layerWasAdded( QgsMapLayer* ) ), this, SLOT( addLayer( QgsMapLayer* ) ) );
904 
905  for ( int i = 0, n = rowCount(); i < n ; ++i )
906  {
907  QgsComposerLayerItem* lItem = dynamic_cast<QgsComposerLayerItem*>( item( i ) );
908  if ( lItem )
909  {
911  if ( layer )
912  {
913  connect( layer, SIGNAL( rendererChanged() ), this, SLOT( updateLayer() ) );
914  }
915  }
916  }
917  }
918  }
919  else
920  {
922  {
923  disconnect( QgsMapLayerRegistry::instance(), SIGNAL( layerWillBeRemoved( QString ) ), this, SLOT( removeLayer( const QString& ) ) );
924  disconnect( QgsMapLayerRegistry::instance(), SIGNAL( layerWasAdded( QgsMapLayer* ) ), this, SLOT( addLayer( QgsMapLayer* ) ) );
925 
926  for ( int i = 0, n = rowCount(); i < n ; ++i )
927  {
928  QgsComposerLayerItem* lItem = dynamic_cast<QgsComposerLayerItem*>( item( i ) );
929  if ( lItem )
930  {
932  if ( layer )
933  {
934  disconnect( layer, SIGNAL( rendererChanged() ), this, SLOT( updateLayer() ) );
935  }
936  }
937  }
938  }
939  }
940 }
void removeLayer(const QString &layerId)
Layer tree group node serves as a container for layers and further groups.
virtual void readXML(const QDomElement &itemElem, bool xServerAvailable=true)=0
Read item content from xml.
virtual QModelIndex index(int row, int column, const QModelIndex &parent) const
Base class for all map layer types.
Definition: qgsmaplayer.h:49
QByteArray data(const QString &mimeType) const
void setIcon(const QIcon &icon)
void setLayerID(const QString &id)
void updateItemText(QStandardItem *item)
Update single item text using item userText and other properties like showFeatureCount.
bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) override
Implements the drop operation.
QStringList mimeTypes() const override
virtual QVariant data(const QModelIndex &index, int role) const
QDomNode appendChild(const QDomNode &newChild)
QStandardItem * invisibleRootItem() const
void fill(const QColor &color)
QList< QStandardItem * > takeRow(int row)
QStringList mLayerIds
QString attribute(const QString &name, const QString &defValue) const
double opacity() const
bool mHasTopLevelWindow
True if this application has toplevel windows (normally true).
#define QgsDebugMsg(str)
Definition: qgslogger.h:33
This class provides qgis with the ability to render raster datasets onto the mapcanvas.
virtual bool hasFormat(const QString &mimeType) const
QObject * sender() const
QgsMapLayer * mapLayer(const QString &theLayerId) const
Retrieve a pointer to a registered layer by layer ID.
bool removeRow(int row, const QModelIndex &parent)
QStandardItem * addGroup(QString text=QString::null, int position=-1, QStandardItem *parentItem=nullptr)
Adds a group.
bool writeXML(QDomElement &composerLegendElem, QDomDocument &doc) const
void updateItem(QStandardItem *item)
Tries to automatically update a model entry (e.g.
void setLayerSetAndGroups(QgsLayerTreeGroup *rootGroup)
Set layers and groups from a layer tree.
void removeRow(int row)
Qt::ItemFlags flags(const QModelIndex &index) const override
virtual QImage getLegendGraphic(double scale=0, bool forceRefresh=false, const QgsRectangle *visibleExtent=nullptr)
Returns the legend rendered as pixmap.
QPixmap fromImage(const QImage &image, QFlags< Qt::ImageConversionFlag > flags)
void setAlpha(int alpha)
virtual bool supportsLegendGraphic() const
Returns whether the provider supplies a legend graphic.
QDomElement documentElement() const
QgsRasterRenderer * renderer() const
bool isNull() const
bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *method)
QDomNodeList childNodes() const
QgsMapLayer::LayerType type() const
Get the type of the layer.
Definition: qgsmaplayer.cpp:99
QString tr(const char *sourceText, const char *disambiguation, int n)
virtual bool removeRows(int row, int count, const QModelIndex &parent=QModelIndex()) override
Implemented to support drag operations.
void setLayerID(const QString &id)
bool qgsDoubleNear(double a, double b, double epsilon=4 *DBL_EPSILON)
Compare two doubles (but allow some difference)
Definition: qgis.h:353
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
int size() const
bool isNull() const
T value(int i) const
QDomElement toElement() const
long featureCount(QgsSymbolV2 *symbol)
Number of features rendered with specified symbol.
bool isValid() const
QgsFeatureRendererV2 * rendererV2()
Return renderer V2.
QString number(int n, int base)
static QIcon symbolPreviewIcon(QgsSymbolV2 *symbol, QSize size)
void setColumnCount(int columns)
QString id() const
Get this layer&#39;s unique ID, this ID is used to access this layer from map layer registry.
virtual QgsLegendSymbolList legendSymbolItems(double scaleDenominator=-1, const QString &rule="")
return a list of item text / symbol
int width() const
void setAttribute(const QString &name, const QString &value)
QString providerType() const
[ data provider interface ] Which provider is being used for this Raster Layer?
void appendRow(const QList< QStandardItem * > &items)
int toInt(bool *ok, int base) const
void setFlags(QFlags< Qt::ItemFlag > flags)
QString type() const
Definition: qgsrendererv2.h:92
bool isEmpty() const
void setAutoUpdate(bool autoUpdate)
QStandardItem * parent() const
int row() const
virtual QString userText() const
virtual void writeXML(QDomElement &elem, QDomDocument &doc) const =0
This class is a base class for nodes in a layer tree.
Qt::DropActions supportedDropActions() const override
T & first()
void removeRows(int row, int count)
void setChild(int row, int column, QStandardItem *item)
QList< QgsLayerTreeNode * > children()
Get list of children of the node. Children are owned by the parent.
bool isLayer(QgsLayerTreeNode *node)
Check whether the node is a valid layer node.
Definition: qgslayertree.h:40
void setSymbolV2(QgsSymbolV2 *s)
Set symbol (takes ownership)
QStandardItem * child(int row, int column) const
bool mAutoUpdate
True if the legend is auto updated when layers are added or removed from the map canvas.
Abstract base class for the legend item types.
QStandardItem * item(int row, int column) const
QString title() const
Get the title of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:126
bool readXML(const QDomElement &legendModelElem, const QDomDocument &doc)
bool contains(const T &value) const
bool countSymbolFeatures(bool showProgress=true)
Count features for symbols.
bool isNull() const
QList< QStandardItem * > takeRow(int row)
QgsMapLayer * layer() const
void setText(const QString &text)
void layersChanged()
static QgsMapLayerRegistry * instance()
Returns the instance pointer, creating the object on the first call.
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
typedef DropActions
QStandardItem * itemFromIndex(const QModelIndex &index) const
void addLayer(QgsMapLayer *theMapLayer, double scaleDenominator=-1, const QString &rule="", QStandardItem *parentItem=nullptr)
virtual ItemType itemType() const =0
virtual int rowCount(const QModelIndex &parent) const
int column() const
int rowCount() const
int height() const
QString name
Read property of QString layerName.
Definition: qgsmaplayer.h:53
void setLayerSet(const QStringList &layerIds, double scaleDenominator=-1, const QString &rule="")
QgsRasterDataProvider * dataProvider()
Returns the data provider.
QString name() const override
Get group&#39;s name.
QString tagName() const
void setData(const QString &mimeType, const QByteArray &data)
int size() const
const_iterator constEnd() const
QDomElement createElement(const QString &tagName)
const_iterator constBegin() const
void updateLayer(QStandardItem *layerItem)
Updates the whole symbology of a layer.
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QObject * parent() const
QgsLegendColorList legendSymbologyItems() const
Returns a list with classification items (Text and color)
Represents a vector layer which manages a vector based data sets.
void setDefaultStyle(double scaleDenominator=-1, const QString &rule="")
bool isGroup(QgsLayerTreeNode *node)
Check whether the node is a valid group node.
Definition: qgslayertree.h:34
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
virtual void setUserText(const QString &text)
int row() const
void appendRow(const QList< QStandardItem * > &items)
Raster renderer pipe that applies colors to a raster.
QMimeData * mimeData(const QModelIndexList &indexes) const override
For the drag operation.
void insertRow(int row, const QList< QStandardItem * > &items)
QWidgetList topLevelWidgets()
QByteArray toByteArray(int indent) const
Layer tree node points to a map layer.
bool setContent(const QByteArray &data, bool namespaceProcessing, QString *errorMsg, int *errorLine, int *errorColumn)
QDomNode at(int index) const
typedef ItemFlags