[QGIS Commit] r13476 - in trunk/qgis/src: app app/composer app/legend core core/composer gui ui

svn_qgis at osgeo.org svn_qgis at osgeo.org
Thu May 13 17:01:36 EDT 2010


Author: mhugent
Date: 2010-05-13 17:01:35 -0400 (Thu, 13 May 2010)
New Revision: 13476

Added:
   trunk/qgis/src/core/composer/qgscomposerlegenditem.cpp
   trunk/qgis/src/core/composer/qgscomposerlegenditem.h
Modified:
   trunk/qgis/src/app/composer/qgscomposerlegendwidget.cpp
   trunk/qgis/src/app/composer/qgscomposerlegendwidget.h
   trunk/qgis/src/app/legend/qgsapplegendinterface.cpp
   trunk/qgis/src/app/legend/qgsapplegendinterface.h
   trunk/qgis/src/app/legend/qgslegend.cpp
   trunk/qgis/src/app/legend/qgslegend.h
   trunk/qgis/src/app/qgisapp.h
   trunk/qgis/src/core/CMakeLists.txt
   trunk/qgis/src/core/composer/qgscomposerlegend.cpp
   trunk/qgis/src/core/composer/qgscomposerlegend.h
   trunk/qgis/src/core/composer/qgslegendmodel.cpp
   trunk/qgis/src/core/composer/qgslegendmodel.h
   trunk/qgis/src/gui/qgslegendinterface.h
   trunk/qgis/src/ui/qgscomposerlegendwidgetbase.ui
Log:
[FEATURE]: Export legend groups and layers with legendinterface and use this information to display groups in the composer legend. Todo: fix drag and frop in composer legend, readXML, cleanups in composer legend model

Modified: trunk/qgis/src/app/composer/qgscomposerlegendwidget.cpp
===================================================================
--- trunk/qgis/src/app/composer/qgscomposerlegendwidget.cpp	2010-05-13 16:51:23 UTC (rev 13475)
+++ trunk/qgis/src/app/composer/qgscomposerlegendwidget.cpp	2010-05-13 21:01:35 UTC (rev 13476)
@@ -21,6 +21,11 @@
 #include "qgscomposeritemwidget.h"
 #include <QFontDialog>
 
+#include "qgsapplegendinterface.h"
+#include "qgisapp.h"
+#include "qgsmapcanvas.h"
+#include "qgsmaprenderer.h"
+
 QgsComposerLegendWidget::QgsComposerLegendWidget( QgsComposerLegend* legend ): mLegend( legend )
 {
   setupUi( this );
@@ -34,6 +39,14 @@
     mItemTreeView->setModel( legend->model() );
   }
 
+  updateLegend();
+
+  mItemTreeView->setDragEnabled( true );
+  mItemTreeView->setAcceptDrops( true );
+  mItemTreeView->setDropIndicatorShown( true );
+  mItemTreeView->setDefaultDropAction( Qt::MoveAction );
+  mItemTreeView->setDragDropMode( QAbstractItemView::InternalMove );
+
   setGuiElements();
 }
 
@@ -147,6 +160,26 @@
   }
 }
 
+void QgsComposerLegendWidget::on_mGroupFontButton_clicked()
+{
+  if ( mLegend )
+  {
+    bool ok;
+#if defined(Q_WS_MAC) && QT_VERSION >= 0x040500 && !defined(__LP64__)
+    // Native Mac dialog works only for 64 bit Cocoa (observed in Qt 4.5.2, probably a Qt bug)
+    QFont newFont = QFontDialog::getFont( &ok, mLegend->groupFont(), this, QString(), QFontDialog::DontUseNativeDialog );
+#else
+    QFont newFont = QFontDialog::getFont( &ok, mLegend->groupFont() );
+#endif
+    if ( ok )
+    {
+      mLegend->setGroupFont( newFont );
+      mLegend->adjustBoxSize();
+      mLegend->update();
+    }
+  }
+}
+
 void QgsComposerLegendWidget::on_mLayerFontButton_clicked()
 {
   if ( mLegend )
@@ -388,8 +421,43 @@
 
 void QgsComposerLegendWidget::on_mUpdateAllPushButton_clicked()
 {
+  updateLegend();
+}
+
+void QgsComposerLegendWidget::on_mAddGroupButton_clicked()
+{
+  if ( mLegend && mLegend->model() )
+  {
+    mLegend->model()->addGroup();
+    mLegend->update();
+  }
+}
+
+void QgsComposerLegendWidget::updateLegend()
+{
   if ( mLegend )
   {
-    mLegend->updateLegend();
+    QgisApp* app = QgisApp::instance();
+    if ( !app )
+    {
+      return;
+    }
+
+    //get layer id list
+    QStringList layerIdList;
+    QgsMapCanvas* canvas = app->mapCanvas();
+    if ( canvas )
+    {
+      QgsMapRenderer* renderer = canvas->mapRenderer();
+      if ( renderer )
+      {
+        layerIdList = renderer->layerSet();
+      }
+    }
+
+    //and also group info
+    QgsAppLegendInterface legendIface( app->legend() );
+    QList< GroupLayerInfo > groupInfo = legendIface.groupLayerRelationship();
+    mLegend->model()->setLayerSetAndGroups( layerIdList, groupInfo );
   }
 }

Modified: trunk/qgis/src/app/composer/qgscomposerlegendwidget.h
===================================================================
--- trunk/qgis/src/app/composer/qgscomposerlegendwidget.h	2010-05-13 16:51:23 UTC (rev 13475)
+++ trunk/qgis/src/app/composer/qgscomposerlegendwidget.h	2010-05-13 21:01:35 UTC (rev 13476)
@@ -43,6 +43,7 @@
     void on_mSymbolSpaceSpinBox_valueChanged( double d );
     void on_mIconLabelSpaceSpinBox_valueChanged( double d );
     void on_mTitleFontButton_clicked();
+    void on_mGroupFontButton_clicked();
     void on_mLayerFontButton_clicked();
     void on_mItemFontButton_clicked();
     void on_mBoxSpaceSpinBox_valueChanged( double d );
@@ -54,11 +55,14 @@
     void on_mEditPushButton_clicked();
     void on_mUpdatePushButton_clicked();
     void on_mUpdateAllPushButton_clicked();
+    void on_mAddGroupButton_clicked();
 
   private:
     QgsComposerLegendWidget();
     /**Sets GUI according to state of mLegend*/
     void setGuiElements();
+    /**Updates the legend layers and groups*/
+    void updateLegend();
 
     QgsComposerLegend* mLegend;
 };

Modified: trunk/qgis/src/app/legend/qgsapplegendinterface.cpp
===================================================================
--- trunk/qgis/src/app/legend/qgsapplegendinterface.cpp	2010-05-13 16:51:23 UTC (rev 13475)
+++ trunk/qgis/src/app/legend/qgsapplegendinterface.cpp	2010-05-13 21:01:35 UTC (rev 13476)
@@ -80,6 +80,15 @@
   return mLegend->groups();
 }
 
+QList< GroupLayerInfo > QgsAppLegendInterface::groupLayerRelationship()
+{
+  if ( mLegend )
+  {
+    return mLegend->groupLayerRelationship();
+  }
+  return QList< GroupLayerInfo >();
+}
+
 bool QgsAppLegendInterface::groupExists( int groupIndex )
 {
   QModelIndex mi = mLegend->model()->index( groupIndex, 0 );

Modified: trunk/qgis/src/app/legend/qgsapplegendinterface.h
===================================================================
--- trunk/qgis/src/app/legend/qgsapplegendinterface.h	2010-05-13 16:51:23 UTC (rev 13475)
+++ trunk/qgis/src/app/legend/qgsapplegendinterface.h	2010-05-13 21:01:35 UTC (rev 13476)
@@ -44,6 +44,9 @@
     //! Return a string list of groups
     QStringList groups();
 
+    //! Return the relationship between groups and layers in the legend
+    QList< GroupLayerInfo > groupLayerRelationship();
+
     //! Return all layers in the project in legend order
     QList< QgsMapLayer * > layers() const;
 

Modified: trunk/qgis/src/app/legend/qgslegend.cpp
===================================================================
--- trunk/qgis/src/app/legend/qgslegend.cpp	2010-05-13 16:51:23 UTC (rev 13475)
+++ trunk/qgis/src/app/legend/qgslegend.cpp	2010-05-13 21:01:35 UTC (rev 13476)
@@ -1240,6 +1240,51 @@
   return groupList;
 }
 
+QList< GroupLayerInfo > QgsLegend::groupLayerRelationship()
+{
+  QList< GroupLayerInfo > groupLayerList;
+
+  int nTopLevelItems = topLevelItemCount();
+  QTreeWidgetItem* currentTopLevelItem = 0;
+
+  for ( int i = 0; i < nTopLevelItems; ++i )
+  {
+    currentTopLevelItem = topLevelItem( i );
+    //layer?
+    QgsLegendLayer* lLayer = dynamic_cast<QgsLegendLayer*>( currentTopLevelItem );
+    if ( lLayer )
+    {
+      if ( lLayer->layer() )
+      {
+        QList<QString> layerList;
+        layerList.push_back( lLayer->layer()->getLayerID() );
+        groupLayerList.push_back( qMakePair( QString(), layerList ) );
+      }
+    }
+    //group?
+    QgsLegendGroup* lGroup = dynamic_cast<QgsLegendGroup*>( currentTopLevelItem );
+    if ( lGroup )
+    {
+      int nLayers =  lGroup->childCount();
+      QList<QString> layerList;
+      for ( int i = 0; i < nLayers; ++i )
+      {
+        QgsLegendLayer* lLayer = dynamic_cast<QgsLegendLayer*>( lGroup->child( i ) );
+        if ( lLayer )
+        {
+          if ( lLayer->layer() )
+          {
+            layerList.push_back( lLayer->layer()->getLayerID() );
+          }
+        }
+      }
+      groupLayerList.push_back( qMakePair( lGroup->text( 0 ), layerList ) );
+    }
+  }
+
+  return groupLayerList;
+}
+
 /**Returns the first item in the hierarchy*/
 QTreeWidgetItem* QgsLegend::firstItem()
 {

Modified: trunk/qgis/src/app/legend/qgslegend.h
===================================================================
--- trunk/qgis/src/app/legend/qgslegend.h	2010-05-13 16:51:23 UTC (rev 13475)
+++ trunk/qgis/src/app/legend/qgslegend.h	2010-05-13 21:01:35 UTC (rev 13476)
@@ -36,6 +36,11 @@
 class QMouseEvent;
 class QTreeWidgetItem;
 
+//Information about relationship between groups and layers
+//key: group name (or null strings for single layers without groups)
+//value: containter with layer ids contained in the group
+typedef QPair< QString, QList<QString> > GroupLayerInfo;
+
 /**
    \class QgsLegend
    \brief A Legend treeview for QGIS
@@ -123,6 +128,9 @@
     /**Returns a string list of groups*/
     QStringList groups();
 
+    //! Return the relationship between groups and layers in the legend
+    QList< GroupLayerInfo > groupLayerRelationship();
+
     /**Returns the first item in the hierarchy*/
     QTreeWidgetItem* firstItem();
 

Modified: trunk/qgis/src/app/qgisapp.h
===================================================================
--- trunk/qgis/src/app/qgisapp.h	2010-05-13 16:51:23 UTC (rev 13475)
+++ trunk/qgis/src/app/qgisapp.h	2010-05-13 21:01:35 UTC (rev 13476)
@@ -155,6 +155,9 @@
     /** Get the mapcanvas object from the app */
     QgsMapCanvas * mapCanvas() { return mMapCanvas; };
 
+    //! returns pointer to map legend
+    QgsLegend *legend() { return mMapLegend; }
+
     //! Set theme (icons)
     void setTheme( QString themeName = "default" );
     //! Setup the toolbar popup menus for a given theme
@@ -586,8 +589,6 @@
 
     //! refresh map canvas
     void refreshMapCanvas();
-    //! returns pointer to map legend
-    QgsLegend *legend() { return mMapLegend; }
 
     //! starts/stops editing mode of the current layer
     void toggleEditing();

Modified: trunk/qgis/src/core/CMakeLists.txt
===================================================================
--- trunk/qgis/src/core/CMakeLists.txt	2010-05-13 16:51:23 UTC (rev 13475)
+++ trunk/qgis/src/core/CMakeLists.txt	2010-05-13 21:01:35 UTC (rev 13476)
@@ -94,6 +94,7 @@
   composer/qgscomposeritem.cpp
   composer/qgscomposeritemgroup.cpp
   composer/qgscomposerlabel.cpp
+  composer/qgscomposerlegenditem.cpp
   composer/qgscomposerpicture.cpp
   composer/qgscomposermap.cpp
   composer/qgscomposertable.cpp

Modified: trunk/qgis/src/core/composer/qgscomposerlegend.cpp
===================================================================
--- trunk/qgis/src/core/composer/qgscomposerlegend.cpp	2010-05-13 16:51:23 UTC (rev 13475)
+++ trunk/qgis/src/core/composer/qgscomposerlegend.cpp	2010-05-13 21:01:35 UTC (rev 13476)
@@ -16,6 +16,7 @@
  ***************************************************************************/
 
 #include "qgscomposerlegend.h"
+#include "qgscomposerlegenditem.h"
 #include "qgsmaplayer.h"
 #include "qgsmaplayerregistry.h"
 #include "qgsmaprenderer.h"
@@ -28,10 +29,11 @@
 
 QgsComposerLegend::QgsComposerLegend( QgsComposition* composition ): QgsComposerItem( composition ), mTitle( tr( "Legend" ) ), mBoxSpace( 2 ), mLayerSpace( 3 ), mSymbolSpace( 2 ), mIconLabelSpace( 2 )
 {
-  QStringList idList = layerIdList();
-  mLegendModel.setLayerSet( idList );
+  //QStringList idList = layerIdList();
+  //mLegendModel.setLayerSet( idList );
 
-  mTitleFont.setPointSizeF( 14.0 );
+  mTitleFont.setPointSizeF( 16.0 );
+  mGroupFont.setPointSizeF( 14.0 );
   mLayerFont.setPointSizeF( 12.0 );
   mItemFont.setPointSizeF( 12.0 );
 
@@ -95,48 +97,20 @@
 
   maxXCoord = 2 * mBoxSpace + textWidthMillimeters( mTitleFont, mTitle );
 
-  //draw only visible layer items
-  QgsMapRenderer* theMapRenderer = mComposition->mapRenderer();
-  QStringList visibleLayerIds;
-  if ( theMapRenderer )
-  {
-    visibleLayerIds = theMapRenderer->layerSet();
-  }
-
-
   for ( int i = 0; i < numLayerItems; ++i )
   {
     currentLayerItem = rootItem->child( i );
-    if ( currentLayerItem )
+    QgsComposerLegendItem* currentLegendItem = dynamic_cast<QgsComposerLegendItem*>( currentLayerItem );
+    if ( currentLegendItem )
     {
-      QString currentLayerId = currentLayerItem->data().toString();
-      int opacity = 255;
-      QgsMapLayer* currentLayer = QgsMapLayerRegistry::instance()->mapLayer( currentLayerId );
-      if ( currentLayer )
+      QgsComposerLegendItem::ItemType type = currentLegendItem->itemType();
+      if ( type == QgsComposerLegendItem::GroupItem )
       {
-        opacity = currentLayer->getTransparency();
+        drawGroupItem( painter, dynamic_cast<QgsComposerGroupItem*>( currentLegendItem ), currentYCoordinate, maxXCoord );
       }
-
-      if ( visibleLayerIds.contains( currentLayerId ) )
+      else if ( type == QgsComposerLegendItem::LayerItem )
       {
-        //Let the user omit the layer title item by having an empty layer title string
-        if ( !currentLayerItem->text().isEmpty() )
-        {
-          currentYCoordinate += mLayerSpace;
-          currentYCoordinate += fontAscentMillimeters( mLayerFont );
-
-          //draw layer Item
-          if ( painter )
-          {
-            painter->setPen( QColor( 0, 0, 0 ) );
-            drawText( painter, mBoxSpace, currentYCoordinate, currentLayerItem->text(), mLayerFont );
-          }
-        }
-
-        maxXCoord = std::max( maxXCoord, 2 * mBoxSpace + textWidthMillimeters( mLayerFont, currentLayerItem->text() ) );
-
-        //and child items
-        drawLayerChildItems( painter, currentLayerItem, currentYCoordinate, maxXCoord, opacity );
+        drawLayerItem( painter, dynamic_cast<QgsComposerLayerItem*>( currentLegendItem ), currentYCoordinate, maxXCoord );
       }
     }
   }
@@ -171,6 +145,74 @@
   return size;
 }
 
+void QgsComposerLegend::drawGroupItem( QPainter* p, QgsComposerGroupItem* groupItem, double& currentYCoord, double& maxXCoord )
+{
+  if ( !p || !groupItem )
+  {
+    return;
+  }
+
+  currentYCoord += mLayerSpace;
+  currentYCoord += fontAscentMillimeters( mGroupFont );
+
+  p->setPen( QColor( 0, 0, 0 ) );
+  drawText( p, mBoxSpace, currentYCoord, groupItem->text(), mGroupFont );
+  maxXCoord = std::max( maxXCoord, 2 * mBoxSpace + textWidthMillimeters( mGroupFont, groupItem->text() ) );
+
+  //children can be other group items or layer items
+  int numChildItems = groupItem->rowCount();
+  QStandardItem* currentChildItem = 0;
+
+  for ( int i = 0; i < numChildItems; ++i )
+  {
+    currentChildItem = groupItem->child( i );
+    QgsComposerLegendItem* currentLegendItem = dynamic_cast<QgsComposerLegendItem*>( currentChildItem );
+    QgsComposerLegendItem::ItemType type = currentLegendItem->itemType();
+    if ( type == QgsComposerLegendItem::GroupItem )
+    {
+      drawGroupItem( p, dynamic_cast<QgsComposerGroupItem*>( currentLegendItem ), currentYCoord, maxXCoord );
+    }
+    else if ( type == QgsComposerLegendItem::LayerItem )
+    {
+      drawLayerItem( p, dynamic_cast<QgsComposerLayerItem*>( currentLegendItem ), currentYCoord, maxXCoord );
+    }
+  }
+}
+
+void QgsComposerLegend::drawLayerItem( QPainter* p, QgsComposerLayerItem* layerItem, double& currentYCoord, double& maxXCoord )
+{
+  if ( !layerItem )
+  {
+    return;
+  }
+
+  int opacity = 255;
+  QgsMapLayer* currentLayer = QgsMapLayerRegistry::instance()->mapLayer( layerItem->layerID() );
+  if ( currentLayer )
+  {
+    opacity = currentLayer->getTransparency();
+  }
+
+  //Let the user omit the layer title item by having an empty layer title string
+  if ( !layerItem->text().isEmpty() )
+  {
+    currentYCoord += mLayerSpace;
+    currentYCoord += fontAscentMillimeters( mLayerFont );
+
+    //draw layer Item
+    if ( p )
+    {
+      p->setPen( QColor( 0, 0, 0 ) );
+      drawText( p, mBoxSpace, currentYCoord, layerItem->text(), mLayerFont );
+    }
+
+    maxXCoord = std::max( maxXCoord, 2 * mBoxSpace + textWidthMillimeters( mLayerFont, layerItem->text() ) );
+
+    //and child items
+    drawLayerChildItems( p, layerItem, currentYCoord, maxXCoord, opacity );
+  }
+}
+
 void QgsComposerLegend::adjustBoxSize()
 {
   QSizeF size = paintAndDetermineSize( 0 );
@@ -210,22 +252,18 @@
       continue;
     }
 
-    //take QgsSymbol* from user data
-    QVariant symbolVariant = currentItem->data();
     QgsSymbol* symbol = 0;
-    if ( symbolVariant.canConvert<void*>() )
+    QgsComposerSymbolItem* symbolItem = dynamic_cast<QgsComposerSymbolItem*>( currentItem );
+    if ( symbolItem )
     {
-      void* symbolData = symbolVariant.value<void*>();
-      symbol = ( QgsSymbol* )( symbolData );
+      symbol = symbolItem->symbol();
     }
 
-    //take QgsSymbolV2* from user data if there
-    QVariant symbolNgVariant = currentItem->data( Qt::UserRole + 2 );
     QgsSymbolV2* symbolNg = 0;
-    if ( symbolNgVariant.canConvert<void*>() )
+    QgsComposerSymbolV2Item* symbolV2Item = dynamic_cast<QgsComposerSymbolV2Item*>( currentItem );
+    if ( symbolV2Item )
     {
-      void* symbolNgData = symbolNgVariant.value<void*>();
-      symbolNg = ( QgsSymbolV2* )symbolNgData;
+      symbolNg = symbolV2Item->symbolV2();
     }
 
     if ( symbol )  //item with symbol?
@@ -416,16 +454,16 @@
 
 QStringList QgsComposerLegend::layerIdList() const
 {
-  QStringList layerIdList;
-  QMap<QString, QgsMapLayer*> layerMap =  QgsMapLayerRegistry::instance()->mapLayers();
-  QMap<QString, QgsMapLayer*>::const_iterator mapIt = layerMap.constBegin();
-
-  for ( ; mapIt != layerMap.constEnd(); ++mapIt )
+  //take layer list from map renderer (to have legend order)
+  if ( mComposition )
   {
-    layerIdList.push_back( mapIt.key() );
+    QgsMapRenderer* r = mComposition->mapRenderer();
+    if ( r )
+    {
+      return r->layerSet();
+    }
   }
-
-  return layerIdList;
+  return QStringList();
 }
 
 void QgsComposerLegend::synchronizeWithModel()
@@ -441,6 +479,13 @@
   update();
 }
 
+void QgsComposerLegend::setGroupFont( const QFont& f )
+{
+  mGroupFont = f;
+  adjustBoxSize();
+  update();
+}
+
 void QgsComposerLegend::setLayerFont( const QFont& f )
 {
   mLayerFont = f;
@@ -460,6 +505,11 @@
   return mTitleFont;
 }
 
+QFont QgsComposerLegend::groupFont() const
+{
+  return mGroupFont;
+}
+
 QFont QgsComposerLegend::layerFont() const
 {
   return mLayerFont;
@@ -489,6 +539,7 @@
   //write general properties
   composerLegendElem.setAttribute( "title", mTitle );
   composerLegendElem.setAttribute( "titleFont", mTitleFont.toString() );
+  composerLegendElem.setAttribute( "groupFont", mGroupFont.toString() );
   composerLegendElem.setAttribute( "layerFont", mLayerFont.toString() );
   composerLegendElem.setAttribute( "itemFont", mItemFont.toString() );
   composerLegendElem.setAttribute( "boxSpace", QString::number( mBoxSpace ) );
@@ -520,6 +571,13 @@
   {
     mTitleFont.fromString( titleFontString );
   }
+  //group font
+  QString groupFontString = itemElem.attribute( "groupFont" );
+  if ( !groupFontString.isEmpty() )
+  {
+    mGroupFont.fromString( groupFontString );
+  }
+
   //layer font
   QString layerFontString = itemElem.attribute( "layerFont" );
   if ( !layerFontString.isEmpty() )

Modified: trunk/qgis/src/core/composer/qgscomposerlegend.h
===================================================================
--- trunk/qgis/src/core/composer/qgscomposerlegend.h	2010-05-13 16:51:23 UTC (rev 13475)
+++ trunk/qgis/src/core/composer/qgscomposerlegend.h	2010-05-13 21:01:35 UTC (rev 13476)
@@ -23,6 +23,8 @@
 
 class QgsSymbol;
 class QgsSymbolV2;
+class QgsComposerGroupItem;
+class QgsComposerLayerItem;
 
 /** \ingroup MapComposer
  * A legend that can be placed onto a map composition
@@ -54,6 +56,9 @@
     QFont titleFont() const;
     void setTitleFont( const QFont& f );
 
+    QFont groupFont() const;
+    void setGroupFont( const QFont& f );
+
     QFont layerFont() const;
     void setLayerFont( const QFont& f );
 
@@ -101,6 +106,7 @@
 
     //different fonts for entries
     QFont mTitleFont;
+    QFont mGroupFont;
     QFont mLayerFont;
     QFont mItemFont;
 
@@ -123,6 +129,11 @@
   private:
     QgsComposerLegend(); //forbidden
 
+    /**Draws a group item and all subitems*/
+    void drawGroupItem( QPainter* p, QgsComposerGroupItem* groupItem, double& currentYCoord, double& maxXCoord );
+    /**Draws a layer item and all subitems*/
+    void drawLayerItem( QPainter* p, QgsComposerLayerItem* layerItem, double& currentYCoord, double& maxXCoord );
+
     /**Draws child items of a layer item
        @param layerItem parent model item (layer)
        @param currentYCoord in/out: current y position of legend item

Added: trunk/qgis/src/core/composer/qgscomposerlegenditem.cpp
===================================================================
--- trunk/qgis/src/core/composer/qgscomposerlegenditem.cpp	                        (rev 0)
+++ trunk/qgis/src/core/composer/qgscomposerlegenditem.cpp	2010-05-13 21:01:35 UTC (rev 13476)
@@ -0,0 +1,233 @@
+/***************************************************************************
+                         qgscomposerlegenditem.cpp  -  description
+                         -------------------------
+    begin                : May 2010
+    copyright            : (C) 2010 by Marco Hugentobler
+    email                : marco dot hugentobler at sourcepole dot ch
+ ***************************************************************************/
+
+/***************************************************************************
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ ***************************************************************************/
+
+#include "qgscomposerlegenditem.h"
+#include "qgssymbol.h"
+#include "qgssymbolv2.h"
+#include "qgssymbollayerv2utils.h"
+#include <QDomDocument>
+#include <QDomElement>
+
+QgsComposerLegendItem::QgsComposerLegendItem(): QStandardItem()
+{
+}
+
+QgsComposerLegendItem::QgsComposerLegendItem( const QString& text ): QStandardItem( text )
+{
+}
+
+QgsComposerLegendItem::QgsComposerLegendItem( const QIcon& icon, const QString& text ): QStandardItem( icon, text )
+{
+}
+
+QgsComposerLegendItem::~QgsComposerLegendItem()
+{
+}
+
+void QgsComposerLegendItem::writeXMLChildren( QDomElement& elem, QDomDocument& doc ) const
+{
+  int numRows = rowCount();
+  QgsComposerLegendItem* currentItem = 0;
+  for ( int i = 0; i < numRows; ++i )
+  {
+    currentItem = dynamic_cast<QgsComposerLegendItem*>( child( i, 0 ) );
+    if ( currentItem )
+    {
+      currentItem->writeXML( elem, doc );
+    }
+  }
+}
+
+//////////////////////////////QgsComposerSymbolItem
+
+QgsComposerSymbolItem::QgsComposerSymbolItem(): QgsComposerLegendItem(), mSymbol( 0 )
+{
+}
+
+QgsComposerSymbolItem::QgsComposerSymbolItem( const QString& text ): QgsComposerLegendItem( text ), mSymbol( 0 )
+{
+}
+
+QgsComposerSymbolItem::QgsComposerSymbolItem( const QIcon& icon, const QString& text ): QgsComposerLegendItem( icon, text ), mSymbol( 0 )
+{
+}
+
+QgsComposerSymbolItem::~QgsComposerSymbolItem()
+{
+  delete mSymbol;
+}
+
+void QgsComposerSymbolItem::setSymbol( QgsSymbol* s )
+{
+  delete mSymbol;
+  mSymbol = s;
+}
+
+QStandardItem* QgsComposerSymbolItem::clone() const
+{
+  qWarning( "QgsComposerSymbolItem::clone" );
+  QgsComposerSymbolItem* cloneItem = new QgsComposerSymbolItem();
+  *cloneItem = *this;
+  if ( mSymbol )
+  {
+    cloneItem->setSymbol( new QgsSymbol( *mSymbol ) );
+  }
+  return cloneItem;
+}
+
+void QgsComposerSymbolItem::writeXML( QDomElement& elem, QDomDocument& doc ) const
+{
+  QDomElement vectorClassElem = doc.createElement( "VectorClassificationItem" );
+  if ( mSymbol )
+  {
+    mSymbol->writeXML( vectorClassElem, doc, 0 );
+  }
+  vectorClassElem.setAttribute( "text", text() );
+  elem.appendChild( vectorClassElem );
+}
+
+void QgsComposerSymbolItem::readXML( const QDomElement& itemElem )
+{
+  //soon...
+}
+
+////////////////QgsComposerSymbolV2Item
+
+#include "qgssymbolv2.h"
+
+QgsComposerSymbolV2Item::QgsComposerSymbolV2Item(): QgsComposerLegendItem(), mSymbolV2( 0 )
+{
+}
+
+QgsComposerSymbolV2Item::QgsComposerSymbolV2Item( const QString& text ): QgsComposerLegendItem( text ), mSymbolV2( 0 )
+{
+}
+
+QgsComposerSymbolV2Item::QgsComposerSymbolV2Item( const QIcon& icon, const QString& text ): QgsComposerLegendItem( icon, text ), mSymbolV2( 0 )
+{
+}
+
+QgsComposerSymbolV2Item::~QgsComposerSymbolV2Item()
+{
+  delete mSymbolV2;
+}
+
+QStandardItem* QgsComposerSymbolV2Item::clone() const
+{
+  QgsComposerSymbolV2Item* cloneItem = new QgsComposerSymbolV2Item();
+  *cloneItem = *this;
+  if ( mSymbolV2 )
+  {
+    cloneItem->setSymbolV2( mSymbolV2->clone() );
+  }
+  return cloneItem;
+}
+
+void QgsComposerSymbolV2Item::writeXML( QDomElement& elem, QDomDocument& doc ) const
+{
+  QDomElement vectorClassElem = doc.createElement( "VectorClassificationItemNg" );
+  if ( mSymbolV2 )
+  {
+    QgsSymbolV2Map saveSymbolMap;
+    saveSymbolMap.insert( "classificationSymbol", mSymbolV2 );
+    QDomElement symbolsElem = QgsSymbolLayerV2Utils::saveSymbols( saveSymbolMap, "symbols", doc );
+    vectorClassElem.appendChild( symbolsElem );
+  }
+  vectorClassElem.setAttribute( "text", text() );
+  elem.appendChild( vectorClassElem );
+}
+
+void QgsComposerSymbolV2Item::readXML( const QDomElement& itemElem )
+{
+  //soon...
+}
+
+void QgsComposerSymbolV2Item::setSymbolV2( QgsSymbolV2* s )
+{
+  delete mSymbolV2;
+  mSymbolV2 = s;
+}
+
+////////////////////QgsComposerLayerItem
+
+QgsComposerLayerItem::QgsComposerLayerItem(): QgsComposerLegendItem()
+{
+}
+
+QgsComposerLayerItem::QgsComposerLayerItem( const QString& text ): QgsComposerLegendItem( text )
+{
+}
+
+QgsComposerLayerItem::~QgsComposerLayerItem()
+{
+}
+
+QStandardItem* QgsComposerLayerItem::clone() const
+{
+  QgsComposerLayerItem* cloneItem  = new QgsComposerLayerItem();
+  *cloneItem = *this;
+  cloneItem->setLayerID( mLayerID );
+  return cloneItem;
+}
+
+void QgsComposerLayerItem::writeXML( QDomElement& elem, QDomDocument& doc ) const
+{
+  QDomElement layerItemElem = doc.createElement( "LayerItem" );
+  layerItemElem.setAttribute( "layerId", mLayerID );
+  layerItemElem.setAttribute( "text", text() );
+  writeXMLChildren( layerItemElem, doc );
+  elem.appendChild( layerItemElem );
+}
+
+void QgsComposerLayerItem::readXML( const QDomElement& itemElem )
+{
+  //soon...
+}
+
+////////////////////QgsComposerGroupItem
+
+QgsComposerGroupItem::QgsComposerGroupItem(): QgsComposerLegendItem()
+{
+}
+
+QgsComposerGroupItem::QgsComposerGroupItem( const QString& text ): QgsComposerLegendItem( text )
+{
+}
+
+QgsComposerGroupItem::~QgsComposerGroupItem()
+{
+}
+
+QStandardItem* QgsComposerGroupItem::clone() const
+{
+  QgsComposerGroupItem* cloneItem = new QgsComposerGroupItem();
+  *cloneItem = *this;
+  return cloneItem;
+}
+
+void QgsComposerGroupItem::writeXML( QDomElement& elem, QDomDocument& doc ) const
+{
+  QDomElement layerGroupElem = doc.createElement( "GroupItem" );
+  layerGroupElem.setAttribute( "text", text() );
+  writeXMLChildren( layerGroupElem, doc );
+  elem.appendChild( layerGroupElem );
+}
+
+void QgsComposerGroupItem::readXML( const QDomElement& itemElem )
+{
+  //soon...
+}

Added: trunk/qgis/src/core/composer/qgscomposerlegenditem.h
===================================================================
--- trunk/qgis/src/core/composer/qgscomposerlegenditem.h	                        (rev 0)
+++ trunk/qgis/src/core/composer/qgscomposerlegenditem.h	2010-05-13 21:01:35 UTC (rev 13476)
@@ -0,0 +1,137 @@
+/***************************************************************************
+                         qgscomposerlegenditem.h  -  description
+                         ------------------------
+    begin                : May 2010
+    copyright            : (C) 2010 by Marco Hugentobler
+    email                : marco dot hugentobler at sourcepole dot ch
+ ***************************************************************************/
+
+/***************************************************************************
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ ***************************************************************************/
+
+#ifndef QGSCOMPOSERLEGENDITEM_H
+#define QGSCOMPOSERLEGENDITEM_H
+
+#include <QStandardItem>
+class QDomDocument;
+class QDomElement;
+
+/**Abstract base class for the legend item types*/
+class CORE_EXPORT QgsComposerLegendItem: public QStandardItem
+{
+  public:
+
+    QgsComposerLegendItem();
+    QgsComposerLegendItem( const QString& text );
+    QgsComposerLegendItem( const QIcon& icon, const QString& text );
+    virtual ~QgsComposerLegendItem();
+
+    enum ItemType
+    {
+      GroupItem = QStandardItem::UserType,
+      LayerItem,
+      SymbologyItem,
+      SymbologyV2Item
+    };
+
+    virtual void writeXML( QDomElement& elem, QDomDocument& doc ) const = 0;
+    virtual void readXML( const QDomElement& itemElem ) = 0;
+
+    virtual ItemType itemType() const = 0;
+    virtual QStandardItem* clone() const = 0;
+
+  protected:
+    void writeXMLChildren( QDomElement& elem, QDomDocument& doc ) const;
+};
+
+class QgsSymbol;
+
+class CORE_EXPORT QgsComposerSymbolItem: public QgsComposerLegendItem
+{
+  public:
+    QgsComposerSymbolItem();
+    QgsComposerSymbolItem( const QString& text );
+    QgsComposerSymbolItem( const QIcon& icon, const QString& text );
+    virtual ~QgsComposerSymbolItem();
+
+    virtual QStandardItem* clone() const;
+
+    virtual void writeXML( QDomElement& elem, QDomDocument& doc ) const;
+    virtual void readXML( const QDomElement& itemElem );
+
+    /**Set symbol (takes ownership)*/
+    void setSymbol( QgsSymbol* s );
+    QgsSymbol* symbol() {return mSymbol;}
+
+    ItemType itemType() const { return SymbologyItem; }
+
+  private:
+    QgsSymbol* mSymbol;
+};
+
+class QgsSymbolV2;
+
+class CORE_EXPORT QgsComposerSymbolV2Item: public QgsComposerLegendItem
+{
+  public:
+    QgsComposerSymbolV2Item();
+    QgsComposerSymbolV2Item( const QString& text );
+    QgsComposerSymbolV2Item( const QIcon& icon, const QString& text );
+    virtual ~QgsComposerSymbolV2Item();
+
+    virtual QStandardItem* clone() const;
+
+    virtual void writeXML( QDomElement& elem, QDomDocument& doc ) const;
+    virtual void readXML( const QDomElement& itemElem );
+
+    /**Set symbol (takes ownership)*/
+    void setSymbolV2( QgsSymbolV2* s );
+    QgsSymbolV2* symbolV2() {return mSymbolV2;}
+
+    ItemType itemType() const { return SymbologyV2Item; }
+
+  private:
+    QgsSymbolV2* mSymbolV2;
+};
+
+class CORE_EXPORT QgsComposerLayerItem: public QgsComposerLegendItem
+{
+  public:
+    QgsComposerLayerItem();
+    QgsComposerLayerItem( const QString& text );
+    virtual ~QgsComposerLayerItem();
+    virtual QStandardItem* clone() const;
+
+    virtual void writeXML( QDomElement& elem, QDomDocument& doc ) const;
+    virtual void readXML( const QDomElement& itemElem );
+
+    ItemType itemType() const { return LayerItem; }
+
+    void setLayerID( const QString& id ) { mLayerID = id; }
+    QString layerID() const { return mLayerID; }
+
+  private:
+    QString mLayerID;
+};
+
+class CORE_EXPORT QgsComposerGroupItem: public QgsComposerLegendItem
+{
+  public:
+    QgsComposerGroupItem();
+    QgsComposerGroupItem( const QString& text );
+    virtual ~QgsComposerGroupItem();
+    virtual QStandardItem* clone() const;
+
+    virtual void writeXML( QDomElement& elem, QDomDocument& doc ) const;
+    virtual void readXML( const QDomElement& itemElem );
+
+    ItemType itemType() const { return GroupItem; }
+};
+
+#endif // QGSCOMPOSERLEGENDITEM_H

Modified: trunk/qgis/src/core/composer/qgslegendmodel.cpp
===================================================================
--- trunk/qgis/src/core/composer/qgslegendmodel.cpp	2010-05-13 16:51:23 UTC (rev 13475)
+++ trunk/qgis/src/core/composer/qgslegendmodel.cpp	2010-05-13 21:01:35 UTC (rev 13476)
@@ -16,6 +16,7 @@
  ***************************************************************************/
 
 #include "qgslegendmodel.h"
+#include "qgscomposerlegenditem.h"
 #include "qgsfield.h"
 #include "qgsmaplayer.h"
 #include "qgsmaplayerregistry.h"
@@ -37,22 +38,68 @@
     connect( QgsMapLayerRegistry::instance(), SIGNAL( layerWillBeRemoved( QString ) ), this, SLOT( removeLayer( const QString& ) ) );
     connect( QgsMapLayerRegistry::instance(), SIGNAL( layerWasAdded( QgsMapLayer* ) ), this, SLOT( addLayer( QgsMapLayer* ) ) );
   }
+  setItemPrototype( new QgsComposerSymbolItem() );
 }
 
 QgsLegendModel::~QgsLegendModel()
 {
-  removeAllSymbols();
-  removeAllSymbolsV2();
 }
 
+void QgsLegendModel::setLayerSetAndGroups( const QStringList& layerIds, const QList< GroupLayerInfo >& groupInfo )
+{
+  setLayerSet( layerIds );
+
+  QStandardItem* currentItem = 0;
+  QStandardItem* currentGroupItem = 0;
+  int i = 0;
+
+  QList< GroupLayerInfo >::const_iterator infoIt = groupInfo.constBegin();
+  for ( ; infoIt != groupInfo.constEnd() && i < invisibleRootItem()->rowCount(); )
+  {
+    currentItem = invisibleRootItem()->child( i, 0 );
+    QString infoKey = infoIt->first;
+    if ( infoKey.isNull() ) //a toplevel layer
+    {
+      ++i;
+    }
+    else //a group
+    {
+      currentGroupItem = addGroup( infoKey, i );
+      ++i;
+      QList<QString> layerList = infoIt->second;
+      QList<QString>::const_iterator groupLayerIt = layerList.constBegin();
+      for ( ; currentItem && ( groupLayerIt != layerList.constEnd() ); ++groupLayerIt )
+      {
+        //check if current item is contained in this group
+        QgsComposerLayerItem* layerItem = dynamic_cast<QgsComposerLayerItem*>( currentItem );
+        if ( !layerItem )
+        {
+          return; //should never happen
+        }
+        //QString layerID = currentItem->data(Qt::UserRole + 2).toString();
+        QString layerID = layerItem->layerID();
+        if ( layerList.contains( layerID ) )
+        {
+          takeRow( i );
+          currentGroupItem->setChild( currentGroupItem->rowCount(), 0, currentItem );
+        }
+        else
+        {
+          ++i;
+        }
+        currentItem = invisibleRootItem()->child( i, 0 );
+      }
+    }
+    ++infoIt;
+  }
+}
+
 void QgsLegendModel::setLayerSet( const QStringList& layerIds )
 {
   mLayerIds = layerIds;
 
   //for now clear the model and add the new entries
   clear();
-  removeAllSymbols();
-  removeAllSymbolsV2();
 
   QStringList::const_iterator idIter = mLayerIds.constBegin();
   QgsMapLayer* currentLayer = 0;
@@ -62,9 +109,8 @@
     currentLayer = QgsMapLayerRegistry::instance()->mapLayer( *idIter );
 
     //addItem for layer
-    QStandardItem* layerItem = new QStandardItem( currentLayer->name() );
-    //set layer id as user data into the item
-    layerItem->setData( QVariant( currentLayer->getLayerID() ) );
+    QgsComposerLayerItem* layerItem = new QgsComposerLayerItem( currentLayer->name() );
+    layerItem->setLayerID( currentLayer->getLayerID() );
     layerItem->setFlags( Qt::ItemIsEnabled | Qt::ItemIsSelectable );
 
     invisibleRootItem()->setChild( invisibleRootItem()->rowCount(), layerItem );
@@ -97,6 +143,20 @@
 
 }
 
+QStandardItem* QgsLegendModel::addGroup( QString text, int position )
+{
+  QgsComposerGroupItem* groupItem = new QgsComposerGroupItem( text );
+  if ( position == -1 )
+  {
+    invisibleRootItem()->insertRow( invisibleRootItem()->rowCount(), groupItem );
+  }
+  else
+  {
+    invisibleRootItem()->insertRow( position, groupItem );
+  }
+  return groupItem;
+}
+
 int QgsLegendModel::addVectorLayerItemsV2( QStandardItem* layerItem, QgsVectorLayer* vlayer )
 {
   if ( !layerItem || !vlayer )
@@ -114,16 +174,13 @@
   QgsLegendSymbolList::const_iterator symbolIt = lst.constBegin();
   for ( ; symbolIt != lst.constEnd(); ++symbolIt )
   {
-    QStandardItem* currentSymbolItem = new QStandardItem( symbolIt->first );
+    QgsComposerSymbolV2Item* currentSymbolItem = new QgsComposerSymbolV2Item( symbolIt->first );
+    currentSymbolItem->setFlags( Qt::ItemIsEnabled | Qt::ItemIsSelectable );
     if ( symbolIt->second )
     {
       currentSymbolItem->setIcon( QgsSymbolLayerV2Utils::symbolPreviewIcon( symbolIt->second, QSize( 30, 30 ) ) );
-      //reserve Qt::UserRole + 2 for symbology-ng
-      QgsSymbolV2* newSymbol = symbolIt->second->clone();
-      insertSymbolV2( newSymbol );
-      currentSymbolItem->setData( QVariant::fromValue(( void* )( newSymbol ) ), Qt::UserRole + 2 );
+      currentSymbolItem->setSymbolV2( symbolIt->second->clone() );
     }
-    currentSymbolItem->setFlags( Qt::ItemIsEnabled | Qt::ItemIsSelectable );
     layerItem->setChild( layerItem->rowCount(), 0, currentSymbolItem );
   }
 
@@ -159,6 +216,8 @@
       {
         QString attributeName = vlayer->attributeDisplayName( fieldIt.key() );
         QStandardItem* attributeItem = new QStandardItem( attributeName );
+        attributeItem->setData( QgsLegendModel::ClassificationItem, Qt::UserRole + 1 ); //first user data stores the item type
+        attributeItem->setFlags( Qt::ItemIsEnabled | Qt::ItemIsSelectable );
         layerItem->setChild( layerItem->rowCount(), 0, attributeItem );
       }
     }
@@ -201,6 +260,7 @@
   }
 
   QStandardItem* currentSymbolItem = new QStandardItem( QIcon( rasterLayer->legendAsPixmap( true ) ), "" );
+  currentSymbolItem->setData( QgsLegendModel::ClassificationItem, Qt::UserRole + 1 ); //first user data stores the item type
 
   int currentRowCount = layerItem->rowCount();
   layerItem->setChild( currentRowCount, 0, currentSymbolItem );
@@ -208,58 +268,9 @@
   return 0;
 }
 
-void QgsLegendModel::insertSymbol( QgsSymbol* s )
-{
-  QSet<QgsSymbol*>::iterator it = mSymbols.find( s );
-  if ( it != mSymbols.end() )
-  {
-    delete( *it ); //very unlikely
-  }
-  mSymbols.insert( s );
-}
-
-void QgsLegendModel::insertSymbolV2( QgsSymbolV2* s )
-{
-  QSet<QgsSymbolV2*>::iterator it = mSymbolsV2.find( s );
-  if ( it != mSymbolsV2.end() )
-  {
-    delete( *it ); //very unlikely
-  }
-  mSymbolsV2.insert( s );
-}
-
-void QgsLegendModel::removeSymbol( QgsSymbol* s )
-{
-  mSymbols.remove( s );
-}
-
-void QgsLegendModel::removeSymbolV2( QgsSymbolV2* s )
-{
-  mSymbolsV2.remove( s );
-}
-
-void QgsLegendModel::removeAllSymbols()
-{
-  QSet<QgsSymbol*>::iterator it = mSymbols.begin();
-  for ( ; it != mSymbols.end(); ++it )
-  {
-    delete *it;
-  }
-  mSymbols.clear();
-}
-
-void QgsLegendModel::removeAllSymbolsV2()
-{
-  QSet<QgsSymbolV2*>::iterator it = mSymbolsV2.begin();
-  for ( ; it != mSymbolsV2.end(); ++it )
-  {
-    delete *it;
-  }
-  mSymbolsV2.clear();
-}
-
 void QgsLegendModel::updateItem( QStandardItem* item )
 {
+#if 0
   if ( !item )
   {
     return;
@@ -274,7 +285,7 @@
   }
 
   //take QgsSymbol* from user data
-  QVariant symbolVariant = item->data();
+  QVariant symbolVariant = item->data( Qt::UserRole + 2 );
   QgsSymbol* symbol = 0;
   if ( symbolVariant.canConvert<void*>() )
   {
@@ -282,7 +293,7 @@
     symbol = ( QgsSymbol* )( symbolData );
   }
 
-  QVariant symbolNgVariant = item->data( Qt::UserRole + 2 );
+  QVariant symbolNgVariant = item->data( Qt::UserRole + 3 );
   QgsSymbolV2* symbolNg = 0;
   if ( symbolNgVariant.canConvert<void*>() )
   {
@@ -302,16 +313,18 @@
   {
     updateRasterClassificationItem( item );
   }
+#endif //0
 }
 
 void QgsLegendModel::updateLayer( QStandardItem* layerItem )
 {
+#if 0
   if ( !layerItem )
   {
     return;
   }
 
-  QString layerId = layerItem->data().toString();
+  QString layerId = layerItem->data( Qt::UserRole + 2 ).toString();
   QgsMapLayer* mapLayer = QgsMapLayerRegistry::instance()->mapLayer( layerId );
   if ( mapLayer )
   {
@@ -348,10 +361,12 @@
         break;
     }
   }
+#endif //0
 }
 
 void QgsLegendModel::updateVectorClassificationItem( QStandardItem* classificationItem, QgsSymbol* symbol, QString itemText )
 {
+#if 0
   //this function uses the following logic to find a classification match:
   //first test if there is a symbol where lowerbound - upperbound equels itemText
   //if no match found, test if there is a symbol where label equals itemText
@@ -365,7 +380,7 @@
   }
 
   //get maplayer object from parent item
-  QgsMapLayer* ml = QgsMapLayerRegistry::instance()->mapLayer( parentItem->data().toString() );
+  QgsMapLayer* ml = QgsMapLayerRegistry::instance()->mapLayer( parentItem->data( Qt::UserRole + 2 ).toString() );
   if ( !ml )
   {
     return;
@@ -394,7 +409,6 @@
     currentSymbol = *symbolIt;
     if ( currentSymbol->lowerValue() + " - " + currentSymbol->upperValue() == itemText )
     {
-      removeSymbol( symbol );
       parentItem->insertRow( classificationItem->row(), itemFromSymbol( currentSymbol, opacity ) );
       parentItem->removeRow( classificationItem->row() );
       return;
@@ -408,7 +422,6 @@
     currentSymbol = *symbolIt;
     if ( currentSymbol->lowerValue() == itemText )
     {
-      removeSymbol( symbol );
       parentItem->insertRow( classificationItem->row(), itemFromSymbol( currentSymbol, opacity ) );
       parentItem->removeRow( classificationItem->row() );
       return;
@@ -428,6 +441,7 @@
       return;
     }
   }
+#endif //0
 }
 
 void QgsLegendModel::updateVectorV2ClassificationItem( QStandardItem* classificationItem, QgsSymbolV2* symbol, QString itemText )
@@ -438,6 +452,7 @@
 
 void QgsLegendModel::updateRasterClassificationItem( QStandardItem* classificationItem )
 {
+#if 0
   if ( !classificationItem )
   {
     return;
@@ -449,7 +464,7 @@
     return;
   }
 
-  QgsMapLayer* ml = QgsMapLayerRegistry::instance()->mapLayer( parentItem->data().toString() );
+  QgsMapLayer* ml = QgsMapLayerRegistry::instance()->mapLayer( parentItem->data( Qt::UserRole + 2 ).toString() );
   if ( !ml )
   {
     return;
@@ -462,8 +477,10 @@
   }
 
   QStandardItem* currentSymbolItem = new QStandardItem( QIcon( rl->legendAsPixmap( true ) ), "" );
+  currentSymbolItem->setData( QgsLegendModel::ClassificationItem, Qt::UserRole + 1 ); //first user data stores the item type
   parentItem->insertRow( 0, currentSymbolItem );
   parentItem->removeRow( 1 );
+#endif //0
 }
 
 void QgsLegendModel::removeLayer( const QString& layerId )
@@ -479,7 +496,7 @@
       continue;
     }
 
-    QString currentId = currentLayerItem->data().toString();
+    QString currentId = currentLayerItem->data( Qt::UserRole + 2 ).toString();
     if ( currentId == layerId )
     {
       removeRow( i ); //todo: also remove the subitems and their symbols...
@@ -498,8 +515,8 @@
 
   //append new layer item
   QStandardItem* layerItem = new QStandardItem( theMapLayer->name() );
-  //set layer id as user data into the item
-  layerItem->setData( QVariant( theMapLayer->getLayerID() ) );
+  layerItem->setData( QgsLegendModel::LayerItem, Qt::UserRole + 1 ); //first user data stores the item type
+  layerItem->setData( QVariant( theMapLayer->getLayerID() ), Qt::UserRole + 2 );
   layerItem->setFlags( Qt::ItemIsEnabled | Qt::ItemIsSelectable );
   invisibleRootItem()->setChild( invisibleRootItem()->rowCount(), layerItem );
 
@@ -533,7 +550,7 @@
 
 QStandardItem* QgsLegendModel::itemFromSymbol( QgsSymbol* s, int opacity )
 {
-  QStandardItem* currentSymbolItem = 0;
+  QgsComposerSymbolItem* currentSymbolItem = 0;
 
   //label
   QString itemText;
@@ -591,18 +608,17 @@
     }
   }
 
-  currentSymbolItem = new QStandardItem( QIcon( QPixmap::fromImage( symbolImage ) ), itemText );
+  currentSymbolItem = new QgsComposerSymbolItem( QIcon( QPixmap::fromImage( symbolImage ) ), itemText );
 
   if ( !currentSymbolItem )
   {
     return 0;
   }
+  currentSymbolItem->setData( QgsLegendModel::ClassificationItem, Qt::UserRole + 1 ); //first user data stores the item type
 
   //Pass deep copy of QgsSymbol as user data. Cast to void* necessary such that QMetaType handles it
   QgsSymbol* symbolCopy = new QgsSymbol( *s );
-  currentSymbolItem->setData( QVariant::fromValue(( void* )symbolCopy ) );
-  insertSymbol( symbolCopy );
-
+  currentSymbolItem->setSymbol( symbolCopy );
   currentSymbolItem->setFlags( Qt::ItemIsEnabled | Qt::ItemIsSelectable );
   return currentSymbolItem;
 }
@@ -615,81 +631,18 @@
   }
 
   QDomElement legendModelElem = doc.createElement( "Model" );
+  int nTopLevelItems = invisibleRootItem()->rowCount();
+  QStandardItem* currentItem = 0;
+  QgsComposerLegendItem* currentLegendItem = 0;
 
-  //iterate over all items...
-  QStandardItem* currentLayerItem = 0;
-  QStandardItem* currentClassificationItem = 0;
-  int numRootItems = rowCount();
-
-  for ( int i = 0; i < numRootItems; ++i )
+  for ( int i = 0; i < nTopLevelItems; ++i )
   {
-    currentLayerItem = item( i );
-    QDomElement newLayerItem = doc.createElement( "LayerItem" );
-    newLayerItem.setAttribute( "layerId", currentLayerItem->data().toString() );
-    newLayerItem.setAttribute( "text", currentLayerItem->text() );
-
-    //add layer/classification items
-    int numClassItems = currentLayerItem->rowCount();
-    for ( int j = 0; j < numClassItems; ++j )
+    currentItem = invisibleRootItem()->child( i, 0 );
+    currentLegendItem = dynamic_cast<QgsComposerLegendItem*>( currentItem );
+    if ( currentItem )
     {
-      currentClassificationItem = currentLayerItem->child( j );
-
-      //store text and QgsSymbol for vector classification items
-      QVariant symbolVariant = currentClassificationItem->data();
-      QVariant symbolNgVariant = currentClassificationItem->data( Qt::UserRole + 2 );
-      QgsSymbol* symbol = 0;
-      QgsSymbolV2* symbolNg = 0;
-
-      if ( symbolVariant.canConvert<void*>() )
-      {
-        void* symbolData = symbolVariant.value<void*>();
-        symbol = ( QgsSymbol* )symbolData;
-      }
-      else if ( symbolNgVariant.canConvert<void*>() )
-      {
-        void* symbolNgData = symbolNgVariant.value<void*>();
-        symbolNg = ( QgsSymbolV2* )symbolNgData;
-      }
-
-      if ( symbol || symbolNg )
-      {
-        QDomElement vectorClassElem;
-        if ( symbol )
-        {
-          vectorClassElem = doc.createElement( "VectorClassificationItem" );
-          symbol->writeXML( vectorClassElem, doc, 0 );
-        }
-        else if ( symbolNg )
-        {
-          vectorClassElem = doc.createElement( "VectorClassificationItemNg" );
-          QgsSymbolV2Map saveSymbolMap;
-          saveSymbolMap.insert( "classificationSymbol", symbolNg );
-          QDomElement symbolsElem = QgsSymbolLayerV2Utils::saveSymbols( saveSymbolMap, "symbols", doc );
-          vectorClassElem.appendChild( symbolsElem );
-        }
-        vectorClassElem.setAttribute( "text", currentClassificationItem->text() );
-        newLayerItem.appendChild( vectorClassElem );
-        continue;
-      }
-
-      //a text item
-      if ( currentClassificationItem->icon().isNull() )
-      {
-        QDomElement textItemElem = doc.createElement( "TextItem" );
-        textItemElem.setAttribute( "text", currentClassificationItem->text() );
-        newLayerItem.appendChild( textItemElem );
-      }
-      else //else it can only be a raster item
-      {
-        QDomElement rasterClassElem = doc.createElement( "RasterItem" );
-        rasterClassElem.setAttribute( "text", currentClassificationItem->text() );
-        //storing the layer id also in the raster item makes parsing easier
-        rasterClassElem.setAttribute( "layerId", currentLayerItem->data().toString() );
-        newLayerItem.appendChild( rasterClassElem );
-      }
+      currentLegendItem->writeXML( legendModelElem, doc );
     }
-
-    legendModelElem.appendChild( newLayerItem );
   }
 
   composerLegendElem.appendChild( legendModelElem );
@@ -703,109 +656,169 @@
     return false;
   }
 
-  //delete all stored symbols first
-  removeAllSymbols();
+  return false;
+  //todo: adapt to new legend item structure
+  /*
+    //iterate over layer items
+    QDomNodeList layerItemList = legendModelElem.elementsByTagName( "LayerItem" );
+    QgsMapLayer* currentLayer = 0; //store current layer to get
 
-  //iterate over layer items
-  QDomNodeList layerItemList = legendModelElem.elementsByTagName( "LayerItem" );
-  QgsMapLayer* currentLayer = 0; //store current layer to get
+    for ( int i = 0; i < layerItemList.size(); ++i )
+    {
+      QDomElement layerItemElem = layerItemList.at( i ).toElement();
+      QString layerId = layerItemElem.attribute( "layerId" );
 
-  for ( int i = 0; i < layerItemList.size(); ++i )
-  {
-    QDomElement layerItemElem = layerItemList.at( i ).toElement();
-    QString layerId = layerItemElem.attribute( "layerId" );
+      QStandardItem* layerItem = new QStandardItem( layerItemElem.attribute( "text" ) );
 
-    QStandardItem* layerItem = new QStandardItem( layerItemElem.attribute( "text" ) );
+      //set layer id as user data into the item
+      layerItem->setData( QVariant( layerId ) );
+      layerItem->setFlags( Qt::ItemIsEnabled | Qt::ItemIsSelectable );
 
-    //set layer id as user data into the item
-    layerItem->setData( QVariant( layerId ) );
-    layerItem->setFlags( Qt::ItemIsEnabled | Qt::ItemIsSelectable );
+      currentLayer = QgsMapLayerRegistry::instance()->mapLayer( layerId );
 
-    currentLayer = QgsMapLayerRegistry::instance()->mapLayer( layerId );
-
-    //go through all children of layerItemElem
-    QDomElement currentChildElement = layerItemElem.firstChildElement();
-    while ( !currentChildElement.isNull() )
-    {
-      QStandardItem* childItem = new QStandardItem( currentChildElement.attribute( "text" ) );
-      if ( currentChildElement.tagName() == "RasterItem" )
+      //go through all children of layerItemElem
+      QDomElement currentChildElement = layerItemElem.firstChildElement();
+      while ( !currentChildElement.isNull() )
       {
-        //get icon from current layer
-        QgsRasterLayer* rasterLayer = qobject_cast<QgsRasterLayer *>( currentLayer );
-        if ( rasterLayer )
+        QStandardItem* childItem = new QStandardItem( currentChildElement.attribute( "text" ) );
+        if ( currentChildElement.tagName() == "RasterItem" )
         {
-          childItem->setIcon( QIcon( rasterLayer->legendAsPixmap( true ) ) );
+          //get icon from current layer
+          QgsRasterLayer* rasterLayer = qobject_cast<QgsRasterLayer *>( currentLayer );
+          if ( rasterLayer )
+          {
+            childItem->setIcon( QIcon( rasterLayer->legendAsPixmap( true ) ) );
+          }
+          layerItem->setChild( layerItem->rowCount(), 0, childItem );
         }
-        layerItem->setChild( layerItem->rowCount(), 0, childItem );
-      }
-      else if ( currentChildElement.tagName() == "VectorClassificationItem" )
-      {
-        //read QgsSymbol from xml and get icon
-        QgsVectorLayer* vectorLayer = qobject_cast<QgsVectorLayer *>( currentLayer );
-        if ( vectorLayer )
+        else if ( currentChildElement.tagName() == "VectorClassificationItem" )
         {
-          //look for symbol
-          QDomNodeList symbolNodeList = currentChildElement.elementsByTagName( "symbol" );
-          if ( symbolNodeList.size() > 0 )
+          //read QgsSymbol from xml and get icon
+          QgsVectorLayer* vectorLayer = qobject_cast<QgsVectorLayer *>( currentLayer );
+          if ( vectorLayer )
           {
-            QgsSymbol* symbol = new QgsSymbol( vectorLayer->geometryType() );
-            QDomNode symbolNode = symbolNodeList.at( 0 );
-            symbol->readXML( symbolNode, vectorLayer );
-            childItem->setData( QVariant::fromValue(( void* )symbol ) );
+            //look for symbol
+            QDomNodeList symbolNodeList = currentChildElement.elementsByTagName( "symbol" );
+            if ( symbolNodeList.size() > 0 )
+            {
+              QgsSymbol* symbol = new QgsSymbol( vectorLayer->geometryType() );
+              QDomNode symbolNode = symbolNodeList.at( 0 );
+              symbol->readXML( symbolNode, vectorLayer );
+              childItem->setData( QVariant::fromValue(( void* )symbol ) );
 
-            //add icon
-            switch ( symbol->type() )
-            {
-              case QGis::Point:
-                childItem->setIcon( QIcon( QPixmap::fromImage( symbol->getPointSymbolAsImage() ) ) );
-                break;
-              case QGis::Line:
-                childItem->setIcon( QIcon( QPixmap::fromImage( symbol->getLineSymbolAsImage() ) ) );
-                break;
-              case QGis::Polygon:
-                childItem->setIcon( QIcon( QPixmap::fromImage( symbol->getPolygonSymbolAsImage() ) ) );
-                break;
-              case QGis::UnknownGeometry:
-                // should not occur
-                break;
+              //add icon
+              switch ( symbol->type() )
+              {
+                case QGis::Point:
+                  childItem->setIcon( QIcon( QPixmap::fromImage( symbol->getPointSymbolAsImage() ) ) );
+                  break;
+                case QGis::Line:
+                  childItem->setIcon( QIcon( QPixmap::fromImage( symbol->getLineSymbolAsImage() ) ) );
+                  break;
+                case QGis::Polygon:
+                  childItem->setIcon( QIcon( QPixmap::fromImage( symbol->getPolygonSymbolAsImage() ) ) );
+                  break;
+                case QGis::UnknownGeometry:
+                  // should not occur
+                  break;
+              }
+              insertSymbol( symbol );
             }
-            insertSymbol( symbol );
           }
+          layerItem->setChild( layerItem->rowCount(), 0, childItem );
         }
-        layerItem->setChild( layerItem->rowCount(), 0, childItem );
-      }
-      else if ( currentChildElement.tagName() == "VectorClassificationItemNg" )
-      {
-        QDomElement symbolNgElem = currentChildElement.firstChildElement( "symbols" );
-        if ( !symbolNgElem.isNull() )
+        else if ( currentChildElement.tagName() == "VectorClassificationItemNg" )
         {
-          QgsSymbolV2Map loadSymbolMap = QgsSymbolLayerV2Utils::loadSymbols( symbolNgElem );
-          //we assume there is only one symbol in the map...
-          QgsSymbolV2Map::iterator mapIt = loadSymbolMap.begin();
-          if ( mapIt != loadSymbolMap.end() )
+          QDomElement symbolNgElem = currentChildElement.firstChildElement( "symbols" );
+          if ( !symbolNgElem.isNull() )
           {
-            QgsSymbolV2* symbolNg = mapIt.value();
-            insertSymbolV2( symbolNg );
-            childItem->setData( QVariant::fromValue(( void* )symbolNg ), Qt::UserRole + 2 );
-            childItem->setIcon( QgsSymbolLayerV2Utils::symbolPreviewIcon( symbolNg, QSize( 30, 30 ) ) );
+            QgsSymbolV2Map loadSymbolMap = QgsSymbolLayerV2Utils::loadSymbols( symbolNgElem );
+            //we assume there is only one symbol in the map...
+            QgsSymbolV2Map::iterator mapIt = loadSymbolMap.begin();
+            if ( mapIt != loadSymbolMap.end() )
+            {
+              QgsSymbolV2* symbolNg = mapIt.value();
+              insertSymbolV2( symbolNg );
+              childItem->setData( QVariant::fromValue(( void* )symbolNg ), Qt::UserRole + 2 );
+              childItem->setIcon( QgsSymbolLayerV2Utils::symbolPreviewIcon( symbolNg, QSize( 30, 30 ) ) );
+            }
+            layerItem->setChild( layerItem->rowCount(), 0, childItem );
           }
+        }
+        else if ( currentChildElement.tagName() == "TextItem" )
+        {
           layerItem->setChild( layerItem->rowCount(), 0, childItem );
         }
+        else //unknown tag name, don't add item
+        {
+          delete childItem;
+        }
+
+        currentChildElement = currentChildElement.nextSiblingElement();
       }
-      else if ( currentChildElement.tagName() == "TextItem" )
-      {
-        layerItem->setChild( layerItem->rowCount(), 0, childItem );
-      }
-      else //unknown tag name, don't add item
-      {
-        delete childItem;
-      }
 
-      currentChildElement = currentChildElement.nextSiblingElement();
+      invisibleRootItem()->setChild( invisibleRootItem()->rowCount(), layerItem );
     }
 
-    invisibleRootItem()->setChild( invisibleRootItem()->rowCount(), layerItem );
+    return true;
+    */
+}
+
+Qt::DropActions QgsLegendModel::supportedDropActions() const
+{
+  return Qt::MoveAction;
+}
+
+Qt::ItemFlags QgsLegendModel::flags( const QModelIndex &index ) const
+{
+  Qt::ItemFlags flags = QStandardItemModel::flags( index );
+
+  QStandardItem* item = itemFromIndex( index );
+  if ( item )
+  {
+    ItemType type = itemType( *item );
+    if ( type == QgsLegendModel::GroupItem )
+    {
+      flags |= Qt::ItemIsDragEnabled;
+      flags |= Qt::ItemIsDropEnabled;
+    }
+    else if ( type == QgsLegendModel::LayerItem )
+    {
+      flags |= Qt::ItemIsDragEnabled;
+    }
   }
+  return flags;
+}
 
+bool QgsLegendModel::removeRows( int row, int count, const QModelIndex & parent )
+{
+  if ( count < 1 )
+  {
+    return false;
+  }
+
+  if ( parent.isValid() )
+  {
+    for ( int i = row + count - 1; i >= row; --i )
+    {
+      QStandardItem* item = itemFromIndex( parent );
+      if ( item )
+      {
+        item->takeRow( i );
+      }
+    }
+  }
+  else
+  {
+    for ( int i = row + count - 1; i >= row; --i )
+    {
+      takeRow( i );
+    }
+  }
   return true;
 }
+
+QgsLegendModel::ItemType QgsLegendModel::itemType( const QStandardItem& item ) const
+{
+  return ( QgsLegendModel::ItemType )item.data( Qt::UserRole + 1 ).toInt();
+}

Modified: trunk/qgis/src/core/composer/qgslegendmodel.h
===================================================================
--- trunk/qgis/src/core/composer/qgslegendmodel.h	2010-05-13 16:51:23 UTC (rev 13475)
+++ trunk/qgis/src/core/composer/qgslegendmodel.h	2010-05-13 21:01:35 UTC (rev 13476)
@@ -29,19 +29,35 @@
 class QgsSymbolV2;
 class QgsVectorLayer;
 
+//Information about relationship between groups and layers
+//key: group name (or null strings for single layers without groups)
+//value: containter with layer ids contained in the group
+typedef QPair< QString, QList<QString> > GroupLayerInfo;
+
 /** \ingroup MapComposer
- * A model that provides layers as root items. The classification items are
- * children of the layer items.
+ * A model that provides group, layer and classification items.
  */
 class CORE_EXPORT QgsLegendModel: public QStandardItemModel
 {
     Q_OBJECT
 
   public:
+
+    enum ItemType
+    {
+      GroupItem = 0,
+      LayerItem,
+      ClassificationItem
+    };
+
     QgsLegendModel();
     ~QgsLegendModel();
 
+    /**Sets layer set and groups*/
+    void setLayerSetAndGroups( const QStringList& layerIds, const QList< GroupLayerInfo >& groupInfo );
     void setLayerSet( const QStringList& layerIds );
+    /**Adds a group to a toplevel position (or -1 if it should be placed at the end of the legend). Returns a pointer to the added group*/
+    QStandardItem* addGroup( QString text = tr( "Group" ), int position = -1 );
 
     /**Tries to automatically update a model entry (e.g. a whole layer or only a single item)*/
     void updateItem( QStandardItem* item );
@@ -55,6 +71,14 @@
     bool writeXML( QDomElement& composerLegendElem, QDomDocument& doc ) const;
     bool readXML( const QDomElement& legendModelElem, const QDomDocument& doc );
 
+    Qt::DropActions supportedDropActions() const;
+    Qt::ItemFlags flags( const QModelIndex &index ) const;
+
+    /**Implemented to support drag operations*/
+    virtual bool removeRows( int row, int count, const QModelIndex & parent = QModelIndex() );
+
+    QgsLegendModel::ItemType itemType( const QStandardItem& item ) const;
+
   public slots:
     void removeLayer( const QString& layerId );
     void addLayer( QgsMapLayer* theMapLayer );
@@ -74,24 +98,9 @@
      @return 0 in case of success*/
     int addRasterLayerItem( QStandardItem* layerItem, QgsMapLayer* rlayer );
 
-    /**Insert a symbol into QgsLegendModel symbol storage*/
-    void insertSymbol( QgsSymbol* s );
-    void insertSymbolV2( QgsSymbolV2* s );
-    /**Removes and deletes a symbol*/
-    void removeSymbol( QgsSymbol* s );
-    void removeSymbolV2( QgsSymbolV2* s );
-    /**Removes and deletes all stored symbols*/
-    void removeAllSymbols();
-    void removeAllSymbolsV2();
-
     /**Creates a model item for a vector symbol. The calling function takes ownership*/
     QStandardItem* itemFromSymbol( QgsSymbol* s, int opacity );
 
-    /**Keep track of copied symbols to delete them if not used anymore*/
-    QSet<QgsSymbol*> mSymbols;
-    /**Keep track of copied symbols v2*/
-    QSet<QgsSymbolV2*> mSymbolsV2;
-
   protected:
     QStringList mLayerIds;
 };

Modified: trunk/qgis/src/gui/qgslegendinterface.h
===================================================================
--- trunk/qgis/src/gui/qgslegendinterface.h	2010-05-13 16:51:23 UTC (rev 13475)
+++ trunk/qgis/src/gui/qgslegendinterface.h	2010-05-13 21:01:35 UTC (rev 13476)
@@ -19,10 +19,16 @@
 #define QGSLEGENDINTERFACE_H
 
 #include <QObject>
+#include <QPair>
 #include <QStringList>
 
 class QgsMapLayer;
 
+//Information about relationship between groups and layers
+//key: group name (or null strings for single layers without groups)
+//value: containter with layer ids contained in the group
+typedef QPair< QString, QList<QString> > GroupLayerInfo;
+
 /** \ingroup gui
  * QgsLegendInterface
  * Abstract base class to make QgsLegend available to plugins.
@@ -44,6 +50,9 @@
     //! Return a string list of groups
     virtual QStringList groups() = 0;
 
+    //! Return the relationship between groups and layers in the legend
+    virtual QList< GroupLayerInfo > groupLayerRelationship() {}
+
     //! Return all layers in the project in legend order
     //! @note added in 1.5
     virtual QList< QgsMapLayer * > layers() const = 0;

Modified: trunk/qgis/src/ui/qgscomposerlegendwidgetbase.ui
===================================================================
--- trunk/qgis/src/ui/qgscomposerlegendwidgetbase.ui	2010-05-13 16:51:23 UTC (rev 13475)
+++ trunk/qgis/src/ui/qgscomposerlegendwidgetbase.ui	2010-05-13 21:01:35 UTC (rev 13476)
@@ -6,8 +6,8 @@
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>354</width>
-    <height>474</height>
+    <width>369</width>
+    <height>471</height>
    </rect>
   </property>
   <property name="sizePolicy">
@@ -33,8 +33,8 @@
        <rect>
         <x>0</x>
         <y>0</y>
-        <width>348</width>
-        <height>468</height>
+        <width>365</width>
+        <height>467</height>
        </rect>
       </property>
       <layout class="QGridLayout" name="gridLayout_3">
@@ -48,8 +48,8 @@
            <rect>
             <x>0</x>
             <y>0</y>
-            <width>180</width>
-            <height>347</height>
+            <width>347</width>
+            <height>393</height>
            </rect>
           </property>
           <attribute name="label">
@@ -83,20 +83,27 @@
             </widget>
            </item>
            <item row="3" column="0">
+            <widget class="QPushButton" name="mGroupFontButton">
+             <property name="text">
+              <string>Group Font...</string>
+             </property>
+            </widget>
+           </item>
+           <item row="4" column="0">
             <widget class="QPushButton" name="mLayerFontButton">
              <property name="text">
               <string>Layer Font...</string>
              </property>
             </widget>
            </item>
-           <item row="4" column="0">
+           <item row="5" column="0">
             <widget class="QPushButton" name="mItemFontButton">
              <property name="text">
               <string>Item Font...</string>
              </property>
             </widget>
            </item>
-           <item row="5" column="0">
+           <item row="6" column="0">
             <widget class="QDoubleSpinBox" name="mSymbolWidthSpinBox">
              <property name="prefix">
               <string>Symbol width </string>
@@ -106,7 +113,7 @@
              </property>
             </widget>
            </item>
-           <item row="6" column="0">
+           <item row="7" column="0">
             <widget class="QDoubleSpinBox" name="mSymbolHeightSpinBox">
              <property name="prefix">
               <string>Symbol height </string>
@@ -116,7 +123,7 @@
              </property>
             </widget>
            </item>
-           <item row="7" column="0">
+           <item row="8" column="0">
             <widget class="QDoubleSpinBox" name="mLayerSpaceSpinBox">
              <property name="prefix">
               <string>Layer space </string>
@@ -126,7 +133,7 @@
              </property>
             </widget>
            </item>
-           <item row="8" column="0">
+           <item row="9" column="0">
             <widget class="QDoubleSpinBox" name="mSymbolSpaceSpinBox">
              <property name="prefix">
               <string>Symbol space </string>
@@ -136,7 +143,7 @@
              </property>
             </widget>
            </item>
-           <item row="9" column="0">
+           <item row="10" column="0">
             <widget class="QDoubleSpinBox" name="mIconLabelSpaceSpinBox">
              <property name="prefix">
               <string>Icon label space </string>
@@ -146,7 +153,7 @@
              </property>
             </widget>
            </item>
-           <item row="10" column="0">
+           <item row="11" column="0">
             <widget class="QDoubleSpinBox" name="mBoxSpaceSpinBox">
              <property name="prefix">
               <string>Box space </string>
@@ -156,7 +163,7 @@
              </property>
             </widget>
            </item>
-           <item row="11" column="0">
+           <item row="12" column="0">
             <spacer name="verticalSpacer">
              <property name="orientation">
               <enum>Qt::Vertical</enum>
@@ -176,15 +183,15 @@
            <rect>
             <x>0</x>
             <y>0</y>
-            <width>330</width>
-            <height>390</height>
+            <width>347</width>
+            <height>393</height>
            </rect>
           </property>
           <attribute name="label">
            <string>Legend items</string>
           </attribute>
           <layout class="QGridLayout" name="gridLayout_2">
-           <item row="0" column="0" colspan="6">
+           <item row="0" column="0" colspan="7">
             <widget class="QTreeView" name="mItemTreeView">
              <property name="sizePolicy">
               <sizepolicy hsizetype="Minimum" vsizetype="Expanding">
@@ -239,6 +246,13 @@
              </property>
             </widget>
            </item>
+           <item row="1" column="6">
+            <widget class="QToolButton" name="mAddGroupButton">
+             <property name="text">
+              <string>Add group</string>
+             </property>
+            </widget>
+           </item>
           </layout>
          </widget>
         </widget>



More information about the QGIS-commit mailing list