QGIS API Documentation  2.7.0-Master
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
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 
36 QgsLegendModel::QgsLegendModel(): QStandardItemModel(), mAutoUpdate( true )
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.size() > 0 );
48 }
49 
51 {
52 }
53 
55 {
56  clear();
57  addGroupFromLayerTree( rootGroup, invisibleRootItem() );
58 }
59 
60 void QgsLegendModel::addGroupFromLayerTree( QgsLayerTreeGroup* parentGroup, QStandardItem* parentItem )
61 {
62  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 
79 void QgsLegendModel::setLayerSetAndGroups( const QStringList& layerIds, const QList< GroupLayerInfo >& groupInfo )
80 {
81  setLayerSet( layerIds );
82 
83  QStandardItem* currentItem = 0;
84  QStandardItem* currentGroupItem = 0;
85  int i = 0;
86 
87  QList< GroupLayerInfo >::const_iterator infoIt = groupInfo.constBegin();
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, QString rule )
128 {
129  mLayerIds = layerIds;
130 
131  //for now clear the model and add the new entries
132  clear();
133 
134  QStringList::const_iterator idIter = mLayerIds.constBegin();
135  QgsMapLayer* currentLayer = 0;
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, 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 );
191  QgsLegendSymbolList::const_iterator symbolIt = lst.constBegin();
192  int row = 0;
193  for ( ; symbolIt != lst.constEnd(); ++symbolIt )
194  {
195  if ( 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 ( 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->providerType() == "wms" )
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 
420 void QgsLegendModel::updateItem( QStandardItem* item )
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 
441 void QgsLegendModel::updateItemText( QStandardItem* item )
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 
480 void QgsLegendModel::updateLayer( QStandardItem* layerItem )
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, 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 
606 void QgsLegendModel::updateLayer()
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 = 0;
633  QgsComposerLegendItem* currentLegendItem = 0;
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  QgsComposerLegendItem* currentItem = 0;
666 
667  int nTopLevelItems = topLevelItemList.size();
668  for ( int i = 0; i < nTopLevelItems; ++i )
669  {
670  currentElem = topLevelItemList.at( i ).toElement();
671  if ( currentElem.isNull() )
672  {
673  continue;
674  }
675 
676  //toplevel items can be groups or layers
677  if ( currentElem.tagName() == "LayerItem" )
678  {
679  currentItem = new QgsComposerLayerItem();
680  }
681  else if ( currentElem.tagName() == "GroupItem" )
682  {
683  currentItem = new QgsComposerGroupItem();
684  }
685  currentItem->readXML( currentElem, mHasTopLevelWindow );
686 
687  QList<QStandardItem *> itemsList;
688  itemsList << currentItem << new QgsComposerStyleItem( currentItem );
689  appendRow( itemsList );
690  }
691 
692  setAutoUpdate( legendModelElem.attribute( "autoUpdate", "1" ).toInt() );
693  return true;
694 }
695 
697 {
698  return Qt::MoveAction;
699 }
700 
701 Qt::ItemFlags QgsLegendModel::flags( const QModelIndex &index ) const
702 {
703  Qt::ItemFlags flags = Qt::ItemIsEnabled | Qt::ItemIsSelectable;
704  if ( !index.isValid() )
705  {
706  flags |= Qt::ItemIsDropEnabled;
707  return flags;
708  }
709 
710  QStandardItem* item = itemFromIndex( index );
711  QgsComposerLegendItem* cItem = dynamic_cast<QgsComposerLegendItem*>( item );
712 
713  if ( cItem )
714  {
716  if ( type == QgsComposerLegendItem::GroupItem )
717  {
718  flags |= Qt::ItemIsDragEnabled;
719  flags |= Qt::ItemIsDropEnabled;
720  }
721  else if ( type == QgsComposerLegendItem::LayerItem )
722  {
723  flags |= Qt::ItemIsDragEnabled;
724  }
725  }
726  if ( index.column() == 1 && item )
727  {
728  // Style
729  QStandardItem* firstColumnItem = 0;
730  if ( item->parent() )
731  {
732  firstColumnItem = item->parent()->child( index.row(), 0 );
733  }
734  else
735  {
736  firstColumnItem = QgsLegendModel::item( index.row(), 0 );
737  }
738  cItem = dynamic_cast<QgsComposerLegendItem*>( firstColumnItem );
739 
740  if ( cItem )
741  {
742  if ( cItem->itemType() == QgsComposerLegendItem::GroupItem ||
744  {
745  flags |= Qt::ItemIsEditable;
746  }
747  }
748  }
749  return flags;
750 }
751 
752 bool QgsLegendModel::removeRows( int row, int count, const QModelIndex & parent )
753 {
754  if ( count < 1 )
755  {
756  return false;
757  }
758 
759  if ( parent.isValid() )
760  {
761  for ( int i = row + count - 1; i >= row; --i )
762  {
763  QStandardItem* item = itemFromIndex( parent );
764  if ( item )
765  {
766  item->takeRow( i );
767  }
768  }
769  }
770  else
771  {
772  for ( int i = row + count - 1; i >= row; --i )
773  {
774  takeRow( i );
775  }
776  }
777  return true;
778 }
779 
780 QMimeData* QgsLegendModel::mimeData( const QModelIndexList &indexes ) const
781 {
782  QMimeData* mimeData = new QMimeData();
783  QByteArray encodedData;
784  QDomDocument xmlDoc;
785  QDomElement xmlRootElement = xmlDoc.createElement( "LegendModelDragData" );
786  xmlDoc.appendChild( xmlRootElement );
787 
788  QModelIndexList::const_iterator indexIt = indexes.constBegin();
789  for ( ; indexIt != indexes.constEnd(); ++indexIt )
790  {
791  QStandardItem* sItem = itemFromIndex( *indexIt );
792  if ( sItem )
793  {
794  QgsComposerLegendItem* mItem = dynamic_cast<QgsComposerLegendItem*>( sItem );
795  if ( mItem )
796  {
797  mItem->writeXML( xmlRootElement, xmlDoc );
798  }
799  }
800  }
801  mimeData->setData( "text/xml", xmlDoc.toByteArray() );
802  return mimeData;
803 }
804 
805 QStringList QgsLegendModel::mimeTypes() const
806 {
807  QStringList types;
808  types << "text/xml";
809  return types;
810 }
811 
812 bool QgsLegendModel::dropMimeData( const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent )
813 {
814  Q_UNUSED( action );
815  Q_UNUSED( column );
816 
817  if ( !data->hasFormat( "text/xml" ) )
818  {
819  return false;
820  }
821 
822  QStandardItem* dropIntoItem = 0;
823  if ( parent.isValid() )
824  {
825  dropIntoItem = itemFromIndex( parent );
826  }
827  else
828  {
829  dropIntoItem = invisibleRootItem();
830  }
831 
832  //get XML doc
833  QByteArray encodedData = data->data( "text/xml" );
834  QDomDocument xmlDoc;
835  xmlDoc.setContent( encodedData );
836 
837  QDomElement dragDataElem = xmlDoc.documentElement();
838  if ( dragDataElem.tagName() != "LegendModelDragData" )
839  {
840  return false;
841  }
842 
843  QDomNodeList nodeList = dragDataElem.childNodes();
844  int nChildNodes = nodeList.size();
845  QDomElement currentElem;
846  QString currentTagName;
847  QgsComposerLegendItem* currentItem = 0;
848 
849  for ( int i = 0; i < nChildNodes; ++i )
850  {
851  currentElem = nodeList.at( i ).toElement();
852  if ( currentElem.isNull() )
853  {
854  continue;
855  }
856  currentTagName = currentElem.tagName();
857  if ( currentTagName == "LayerItem" )
858  {
859  currentItem = new QgsComposerLayerItem();
860  }
861  else if ( currentTagName == "GroupItem" )
862  {
863  currentItem = new QgsComposerGroupItem();
864  }
865  else
866  {
867  continue;
868  }
869  currentItem->readXML( currentElem );
870  int index;
871  if ( row < 0 )
872  {
873  index = dropIntoItem->rowCount();
874  }
875  else
876  {
877  index = row + i;
878  }
879  QList<QStandardItem *> itemsList;
880  itemsList << currentItem << new QgsComposerStyleItem( currentItem );
881  dropIntoItem->insertRow( index, itemsList );
882  }
883  emit layersChanged();
884  return true;
885 }
886 
887 void QgsLegendModel::setAutoUpdate( bool autoUpdate )
888 {
889  if ( mAutoUpdate == autoUpdate ) //prevent multiple signal/slot connections
890  {
891  return;
892  }
893 
895  if ( autoUpdate )
896  {
898  {
899  connect( QgsMapLayerRegistry::instance(), SIGNAL( layerWillBeRemoved( QString ) ), this, SLOT( removeLayer( const QString& ) ) );
900  connect( QgsMapLayerRegistry::instance(), SIGNAL( layerWasAdded( QgsMapLayer* ) ), this, SLOT( addLayer( QgsMapLayer* ) ) );
901 
902  for ( int i = 0, n = rowCount(); i < n ; ++i )
903  {
904  QgsComposerLayerItem* lItem = dynamic_cast<QgsComposerLayerItem*>( item( i ) );
905  if ( lItem )
906  {
908  if ( layer )
909  {
910  connect( layer, SIGNAL( rendererChanged() ), this, SLOT( updateLayer() ) );
911  }
912  }
913  }
914  }
915  }
916  else
917  {
919  {
920  disconnect( QgsMapLayerRegistry::instance(), SIGNAL( layerWillBeRemoved( QString ) ), this, SLOT( removeLayer( const QString& ) ) );
921  disconnect( QgsMapLayerRegistry::instance(), SIGNAL( layerWasAdded( QgsMapLayer* ) ), this, SLOT( addLayer( QgsMapLayer* ) ) );
922 
923  for ( int i = 0, n = rowCount(); i < n ; ++i )
924  {
925  QgsComposerLayerItem* lItem = dynamic_cast<QgsComposerLayerItem*>( item( i ) );
926  if ( lItem )
927  {
929  if ( layer )
930  {
931  disconnect( layer, SIGNAL( rendererChanged() ), this, SLOT( updateLayer() ) );
932  }
933  }
934  }
935  }
936  }
937 }
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.
QgsFeatureRendererV2 * rendererV2()
Return renderer V2.
static unsigned index
Base class for all map layer types.
Definition: qgsmaplayer.h:48
QStandardItem * addGroup(QString text=QString::null, int position=-1, QStandardItem *parentItem=0)
Adds a group.
QgsMapLayer::LayerType type() const
Get the type of the layer.
Definition: qgsmaplayer.cpp:89
void setLayerID(const QString &id)
void updateItemText(QStandardItem *item)
Update single item text using item userText and other properties like showFeatureCount.
QStringList mLayerIds
QgsMapLayer * layer() 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.
Qt::DropActions supportedDropActions() const
void updateItem(QStandardItem *item)
Tries to automatically update a model entry (e.g.
static QgsMapLayerRegistry * instance()
Definition: qgssingleton.h:23
void setLayerSetAndGroups(QgsLayerTreeGroup *rootGroup)
Set layers and groups from a layer tree.
virtual QgsLegendSymbolList legendSymbolItems(double scaleDenominator=-1, QString rule="")
return a list of item text / symbol
virtual QString userText() const
double opacity() const
void setLayerID(const QString &id)
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
QString type() const
Definition: qgsrendererv2.h:81
const QString & name() const
Get the display name of the layer.
bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent)
Implements the drop operation.
static QIcon symbolPreviewIcon(QgsSymbolV2 *symbol, QSize size)
void setDefaultStyle(double scaleDenominator=-1, QString rule="")
void setLayerSet(const QStringList &layerIds, double scaleDenominator=-1, QString rule="")
QgsRasterRenderer * renderer() const
void setAutoUpdate(bool autoUpdate)
virtual void writeXML(QDomElement &elem, QDomDocument &doc) const =0
This class is a base class for nodes in a layer tree.
QString id() const
Get this layer's unique ID, this ID is used to access this layer from map layer registry.
Definition: qgsmaplayer.cpp:95
QString name() const
Get group's name.
bool writeXML(QDomElement &composerLegendElem, QDomDocument &doc) const
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)
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.
bool readXML(const QDomElement &legendModelElem, const QDomDocument &doc)
bool countSymbolFeatures(bool showProgress=true)
Count features for symbols.
void addLayer(QgsMapLayer *theMapLayer, double scaleDenominator=-1, QString rule="", QStandardItem *parentItem=0)
virtual QImage getLegendGraphic(double scale=0, bool forceRefresh=false)
Returns the legend rendered as pixmap useful for that layer that need to get legend layer remotly as ...
void layersChanged()
virtual long featureCount() const
Number of features in the layer.
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
QMimeData * mimeData(const QModelIndexList &indexes) const
For the drag operation.
virtual ItemType itemType() const =0
QStringList mimeTypes() const
QgsMapLayer * mapLayer(QString theLayerId)
Retrieve a pointer to a loaded layer by id.
QgsRasterDataProvider * dataProvider()
Returns the data provider.
QString providerType() const
[ data provider interface ] Which provider is being used for this Raster Layer?
void updateLayer(QStandardItem *layerItem)
Updates the whole symbology of a layer.
QgsLegendColorList legendSymbologyItems() const
Returns a list with classification items (Text and color)
Represents a vector layer which manages a vector based data sets.
QList< QPair< QString, QgsSymbolV2 * > > QgsLegendSymbolList
Definition: qgsrendererv2.h:42
bool isGroup(QgsLayerTreeNode *node)
Check whether the node is a valid group node.
Definition: qgslayertree.h:34
const QString & title() const
Definition: qgsmaplayer.h:93
virtual void setUserText(const QString &text)
Raster renderer pipe that applies colors to a raster.
Qt::ItemFlags flags(const QModelIndex &index) const
Layer tree node points to a map layer.
virtual bool removeRows(int row, int count, const QModelIndex &parent=QModelIndex())
Implemented to support drag operations.
#define tr(sourceText)