[QGIS Commit] r14714 - in trunk/qgis/src: app/legend core/renderer core/symbology-ng

svn_qgis at osgeo.org svn_qgis at osgeo.org
Fri Nov 19 08:24:20 EST 2010


Author: mhugent
Date: 2010-11-19 05:24:20 -0800 (Fri, 19 Nov 2010)
New Revision: 14714

Modified:
   trunk/qgis/src/app/legend/qgslegend.cpp
   trunk/qgis/src/app/legend/qgslegendlayer.cpp
   trunk/qgis/src/app/legend/qgslegendlayer.h
   trunk/qgis/src/core/renderer/qgsgraduatedsymbolrenderer.h
   trunk/qgis/src/core/renderer/qgsrenderer.h
   trunk/qgis/src/core/renderer/qgssinglesymbolrenderer.h
   trunk/qgis/src/core/renderer/qgsuniquevaluerenderer.h
   trunk/qgis/src/core/symbology-ng/qgscategorizedsymbolrendererv2.cpp
   trunk/qgis/src/core/symbology-ng/qgsgraduatedsymbolrendererv2.cpp
   trunk/qgis/src/core/symbology-ng/qgssinglesymbolrendererv2.cpp
Log:
[FEATURE]: Add possibility to show number of features in legend classes. Accessible via right click legend menu

Modified: trunk/qgis/src/app/legend/qgslegend.cpp
===================================================================
--- trunk/qgis/src/app/legend/qgslegend.cpp	2010-11-19 07:51:19 UTC (rev 14713)
+++ trunk/qgis/src/app/legend/qgslegend.cpp	2010-11-19 13:24:20 UTC (rev 14714)
@@ -849,6 +849,7 @@
     {
       QDomElement legendlayernode = document.createElement( "legendlayer" );
       legendlayernode.setAttribute( "open", isItemExpanded( item ) ? "true" : "false" );
+
       Qt::CheckState cstate = item->checkState( 0 );
       if ( cstate == Qt::Checked )
       {
@@ -900,6 +901,7 @@
       // to keep it compatible with older projects
       QgsLegendLayer *ll = dynamic_cast<QgsLegendLayer *>( item );
       QgsMapLayer* layer = ll->layer();
+      legendlayernode.setAttribute( "showFeatureCount", ll->showFeatureCount() );
 
       QDomElement layerfilegroupnode = document.createElement( "filegroup" );
       layerfilegroupnode.setAttribute( "open", isItemExpanded( item ) ? "true" : "false" );
@@ -1060,6 +1062,7 @@
 
   // create the item
   QgsLegendLayer* ll = new QgsLegendLayer( theMapLayer );
+  ll->setShowFeatureCount( childelem.attribute( "showFeatureCount", "0" ).toInt(), false );
 
   // load layer's visibility and 'show in overview' flag
   ll->setInOverview( atoi( fileElem.attribute( "isInOverview" ).toUtf8() ) );

Modified: trunk/qgis/src/app/legend/qgslegendlayer.cpp
===================================================================
--- trunk/qgis/src/app/legend/qgslegendlayer.cpp	2010-11-19 07:51:19 UTC (rev 14713)
+++ trunk/qgis/src/app/legend/qgslegendlayer.cpp	2010-11-19 13:24:20 UTC (rev 14714)
@@ -27,6 +27,7 @@
 
 #include "qgsapplication.h"
 #include "qgsfield.h"
+#include "qgsmapcanvasmap.h"
 #include "qgsmaplayerregistry.h"
 #include "qgsrasterlayer.h"
 #include "qgsrenderer.h"
@@ -50,11 +51,12 @@
 #include <QPainter>
 #include <QSettings>
 #include <QFileDialog>
+#include <QProgressDialog>
 
 
 QgsLegendLayer::QgsLegendLayer( QgsMapLayer* layer )
     : QgsLegendItem( ),
-    mLyr( layer )
+    mLyr( layer ), mShowFeatureCount( false )
 {
   mType = LEGEND_LAYER;
 
@@ -91,6 +93,7 @@
     QgsDebugMsg( "Connecting signals for updating icons, layer " + layer->name() );
     connect( layer, SIGNAL( editingStarted() ), this, SLOT( updateIcon() ) );
     connect( layer, SIGNAL( editingStopped() ), this, SLOT( updateIcon() ) );
+    connect( layer, SIGNAL( layerModified( bool ) ), this, SLOT( updateAfterLayerModification( bool ) ) );
   }
   connect( layer, SIGNAL( layerNameChanged() ), this, SLOT( layerNameChanged() ) );
 
@@ -184,7 +187,7 @@
 
 
 
-void QgsLegendLayer::vectorLayerSymbology( const QgsVectorLayer* layer, double widthScale )
+void QgsLegendLayer::vectorLayerSymbology( QgsVectorLayer* layer, double widthScale )
 {
   if ( !layer )
   {
@@ -219,6 +222,12 @@
       }
     }
 
+    QMap< QgsSymbol*, int > featureCountMap;
+    if ( mShowFeatureCount )
+    {
+      updateItemListCount( layer, sym, featureCountMap );
+    }
+
     for ( QList<QgsSymbol*>::const_iterator it = sym.begin(); it != sym.end(); ++it )
     {
       QImage img;
@@ -258,6 +267,15 @@
         values += label;
       }
 
+      if ( mShowFeatureCount )
+      {
+        int fCount = featureCountMap[*it];
+        if ( fCount >= 0 )
+        {
+          values += ( " [" + QString::number( fCount ) + "]" );
+        }
+      }
+
       QPixmap pix = QPixmap::fromImage( img ); // convert to pixmap
       itemList.append( qMakePair( values, pix ) );
     }
@@ -270,12 +288,11 @@
 {
   QSize iconSize( 16, 16 );
 
-#if 0 // unused
-  QSettings settings;
-  bool showClassifiers = settings.value( "/qgis/showLegendClassifiers", false ).toBool();
-#endif
-
   SymbologyList itemList = layer->rendererV2()->legendSymbologyItems( iconSize );
+  if ( mShowFeatureCount )
+  {
+    updateItemListCountV2( itemList, layer );
+  }
 
   changeSymbologySettings( layer, itemList );
 }
@@ -436,6 +453,12 @@
     if ( !vlayer->isEditable() && vlayer->dataProvider()->supportsSubsetString() )
       theMenu.addAction( tr( "&Query..." ), QgisApp::instance(), SLOT( layerSubsetString() ) );
 
+    //show number of features in legend if requested
+    QAction* showNFeaturesAction = new QAction( tr( "Show feature count" ), &theMenu );
+    showNFeaturesAction->setCheckable( true );
+    showNFeaturesAction->setChecked( mShowFeatureCount );
+    QObject::connect( showNFeaturesAction, SIGNAL( toggled( bool ) ), this, SLOT( setShowFeatureCount( bool ) ) );
+    theMenu.addAction( showNFeaturesAction );
     theMenu.addSeparator();
   }
 
@@ -503,3 +526,158 @@
   QString name = mLyr.layer()->name();
   setText( 0, name );
 }
+
+void QgsLegendLayer::updateAfterLayerModification( bool onlyGeomChanged )
+{
+  if ( onlyGeomChanged )
+  {
+    return;
+  }
+
+  double widthScale = 1.0;
+  QgsMapCanvas* canvas = QgisApp::instance()->mapCanvas();
+  if ( canvas && canvas->map() )
+  {
+    widthScale = canvas->map()->paintDevice().logicalDpiX() / 25.4;
+  }
+  refreshSymbology( mLyr.layer()->getLayerID(), widthScale );
+}
+
+void QgsLegendLayer::updateItemListCountV2( SymbologyList& itemList, QgsVectorLayer* layer )
+{
+  if ( !layer )
+  {
+    return;
+  }
+
+  QgsFeatureRendererV2* renderer = layer->rendererV2();
+  if ( !renderer )
+  {
+    return;
+  }
+  QgsRenderContext dummyContext;
+  renderer->startRender( dummyContext, layer );
+
+  //create map holding the symbol count
+  QMap< QgsSymbolV2*, int > mSymbolCountMap;
+  QgsLegendSymbolList symbolList = renderer->legendSymbolItems();
+  QgsLegendSymbolList::const_iterator symbolIt = symbolList.constBegin();
+  for ( ; symbolIt != symbolList.constEnd(); ++symbolIt )
+  {
+    mSymbolCountMap.insert( symbolIt->second, 0 );
+  }
+
+  //go through all features and count the number of occurrences
+  int nFeatures = layer->pendingFeatureCount();
+  QProgressDialog p( tr( "Updating feature count for layer " ) + layer->name(), tr( "Abort" ), 0, nFeatures );
+  p.setWindowModality( Qt::WindowModal );
+  int featuresCounted = 0;
+
+
+  layer->select( layer->pendingAllAttributesList(), QgsRectangle(), false, false );
+  QgsFeature f;
+  QgsSymbolV2* currentSymbol = 0;
+
+  while ( layer->nextFeature( f ) )
+  {
+    currentSymbol = renderer->symbolForFeature( f );
+    mSymbolCountMap[currentSymbol] += 1;
+    ++featuresCounted;
+    if ( featuresCounted % 50 == 0 )
+    {
+      if ( featuresCounted > nFeatures ) //sometimes the feature count is not correct
+      {
+        p.setMaximum( 0 );
+      }
+      p.setValue( featuresCounted );
+      if ( p.wasCanceled() )
+      {
+        return;
+      }
+    }
+  }
+  p.setValue( nFeatures );
+
+  QMap<QString, QPixmap> itemMap;
+  SymbologyList::const_iterator symbologyIt = itemList.constBegin();
+  for ( ; symbologyIt != itemList.constEnd(); ++ symbologyIt )
+  {
+    itemMap.insert( symbologyIt->first, symbologyIt->second );
+  }
+  itemList.clear();
+
+  //
+  symbolIt = symbolList.constBegin();
+  for ( ; symbolIt != symbolList.constEnd(); ++symbolIt )
+  {
+    QgsSymbolV2* debug = symbolIt->second;
+    itemList.push_back( qMakePair( symbolIt->first + " [" + QString::number( mSymbolCountMap[symbolIt->second] ) + "]", itemMap[symbolIt->first] ) );
+  }
+}
+
+void QgsLegendLayer::updateItemListCount( QgsVectorLayer* layer, const QList<QgsSymbol*>& sym, QMap< QgsSymbol*, int >& featureCountMap )
+{
+  featureCountMap.clear();
+  QList<QgsSymbol*>::const_iterator symbolIt = sym.constBegin();
+  for ( ; symbolIt != sym.constEnd(); ++symbolIt )
+  {
+    featureCountMap.insert( *symbolIt, 0 );
+  }
+
+  QgsRenderer* renderer = const_cast<QgsRenderer*>( layer->renderer() );
+  if ( !renderer )
+  {
+    return;
+  }
+
+  //go through all features and count the number of occurrences
+  int nFeatures = layer->pendingFeatureCount();
+  QProgressDialog p( tr( "Updating feature count for layer " ) + layer->name(), tr( "Abort" ), 0, nFeatures );
+  p.setWindowModality( Qt::WindowModal );
+  int featuresCounted = 0;
+
+  layer->select( layer->pendingAllAttributesList(), QgsRectangle(), false, false );
+  QgsFeature f;
+  QgsSymbol* currentSymbol = 0;
+
+  while ( layer->nextFeature( f ) )
+  {
+    currentSymbol = renderer->symbolForFeature( &f );
+    if ( currentSymbol )
+    {
+      featureCountMap[currentSymbol] += 1;
+    }
+    ++featuresCounted;
+
+    if ( featuresCounted % 50 == 0 )
+    {
+      if ( featuresCounted > nFeatures ) //sometimes the feature count is not correct
+      {
+        p.setMaximum( 0 );
+      }
+      p.setValue( featuresCounted );
+      if ( p.wasCanceled() ) //set all entries to -1 (= invalid)
+      {
+        QMap< QgsSymbol*, int >::iterator cIt = featureCountMap.begin();
+        for ( ; cIt != featureCountMap.end(); ++cIt )
+        {
+          cIt.value() = -1;
+        }
+        return;
+      }
+    }
+  }
+  p.setValue( nFeatures );
+}
+
+void QgsLegendLayer::setShowFeatureCount( bool show, bool update )
+{
+  if ( show != mShowFeatureCount )
+  {
+    mShowFeatureCount = show;
+    if ( update )
+    {
+      updateAfterLayerModification( false );
+    }
+  }
+}

Modified: trunk/qgis/src/app/legend/qgslegendlayer.h
===================================================================
--- trunk/qgis/src/app/legend/qgslegendlayer.h	2010-11-19 07:51:19 UTC (rev 14713)
+++ trunk/qgis/src/app/legend/qgslegendlayer.h	2010-11-19 13:24:20 UTC (rev 14714)
@@ -29,6 +29,7 @@
 class QgsLegendPropertyGroup;
 class QgsMapLayer;
 class QgsRasterLayer;
+class QgsSymbol;
 class QgsVectorLayer;
 
 class QTreeWidget;
@@ -87,10 +88,16 @@
     /**Layer name has changed - set it also in legend*/
     void layerNameChanged();
 
+    /**Update symbology (e.g. to update feature count in the legend after editing operations)*/
+    void updateAfterLayerModification( bool onlyGeomChanged );
+
+    void setShowFeatureCount( bool show, bool update = true );
+    bool showFeatureCount() const { return mShowFeatureCount; }
+
   protected:
 
     /** Prepare and change symbology for vector layer */
-    void vectorLayerSymbology( const QgsVectorLayer* mapLayer, double widthScale = 1.0 );
+    void vectorLayerSymbology( QgsVectorLayer* mapLayer, double widthScale = 1.0 );
 
     void vectorLayerSymbologyV2( QgsVectorLayer* vlayer );
 
@@ -100,6 +107,11 @@
     /** Removes the symbology items of a layer and adds new ones. */
     void changeSymbologySettings( const QgsMapLayer* mapLayer, const SymbologyList& newSymbologyItems );
 
+    /**Adds feature counts to the symbology items (for symbology v2)*/
+    void updateItemListCountV2( SymbologyList& itemList, QgsVectorLayer* layer );
+    /**Calculates feature count for the individual symbols (old symbology)*/
+    void updateItemListCount( QgsVectorLayer* layer, const QList<QgsSymbol*>& sym, QMap< QgsSymbol*, int >& featureCountMap );
+
     QPixmap getOriginalPixmap();
 
   private:
@@ -113,6 +125,9 @@
 
     /** layer identified by its layer id */
     QgsMapCanvasLayer mLyr;
+
+    /**True if number of features per legend class should is shown in the legend items*/
+    bool mShowFeatureCount;
 };
 
 #endif

Modified: trunk/qgis/src/core/renderer/qgsgraduatedsymbolrenderer.h
===================================================================
--- trunk/qgis/src/core/renderer/qgsgraduatedsymbolrenderer.h	2010-11-19 07:51:19 UTC (rev 14713)
+++ trunk/qgis/src/core/renderer/qgsgraduatedsymbolrenderer.h	2010-11-19 13:24:20 UTC (rev 14714)
@@ -107,6 +107,8 @@
     /**Returns a copy of the renderer (a deep copy on the heap)*/
     QgsRenderer* clone() const;
 
+    QgsSymbol *symbolForFeature( const QgsFeature* f );
+
   protected:
     /** The graduation mode */
     Mode mMode;
@@ -117,12 +119,8 @@
     /**List holding the symbols for the individual classes*/
     QList<QgsSymbol*> mSymbols;
 
-    QgsSymbol *symbolForFeature( const QgsFeature* f );
-
     /**Cached copy of all underlying symbols required attribute fields*/
     QgsAttributeList mSymbolAttributes;
-
-
 };
 
 inline void QgsGraduatedSymbolRenderer::addSymbol( QgsSymbol* sy )

Modified: trunk/qgis/src/core/renderer/qgsrenderer.h
===================================================================
--- trunk/qgis/src/core/renderer/qgsrenderer.h	2010-11-19 07:51:19 UTC (rev 14713)
+++ trunk/qgis/src/core/renderer/qgsrenderer.h	2010-11-19 13:24:20 UTC (rev 14714)
@@ -112,6 +112,10 @@
      This is a hint for QgsVectorLayer to not use the transparency setting on layer level in this cases*/
     virtual bool usesTransparency() const {return false;}
 
+    /**Returns renderer symbol for a feature.
+        @note: this method was added in version 1.6*/
+    virtual QgsSymbol* symbolForFeature( const QgsFeature* f ) { return 0;}
+
     /**Scales a brush to a given raster scale factor (e.g. for printing)*/
     static void scaleBrush( QBrush& b, double rasterScaleFactor );
 

Modified: trunk/qgis/src/core/renderer/qgssinglesymbolrenderer.h
===================================================================
--- trunk/qgis/src/core/renderer/qgssinglesymbolrenderer.h	2010-11-19 07:51:19 UTC (rev 14713)
+++ trunk/qgis/src/core/renderer/qgssinglesymbolrenderer.h	2010-11-19 13:24:20 UTC (rev 14714)
@@ -64,6 +64,11 @@
     const QList<QgsSymbol*> symbols() const;
     /**Returns a deep copy of this renderer*/
     QgsRenderer* clone() const;
+
+    /**Returns renderer symbol for a feature
+        @note: this method was added in version 1.6*/
+    QgsSymbol* symbolForFeature( const QgsFeature* f ) { return mSymbol0; }
+
   protected:
     /**Object containing symbology information*/
     QgsSymbol *mSymbol0;

Modified: trunk/qgis/src/core/renderer/qgsuniquevaluerenderer.h
===================================================================
--- trunk/qgis/src/core/renderer/qgsuniquevaluerenderer.h	2010-11-19 07:51:19 UTC (rev 14713)
+++ trunk/qgis/src/core/renderer/qgsuniquevaluerenderer.h	2010-11-19 13:24:20 UTC (rev 14714)
@@ -67,13 +67,16 @@
        @note added in 1.4 */
     const QMap<QString, QgsSymbol*> symbolMap() const { return mSymbols; }
     QgsRenderer* clone() const;
+
+    /**Returns the symbol for a feature or 0 if there isn't any*/
+    QgsSymbol *symbolForFeature( const QgsFeature* f );
+
   protected:
     /**Field index used for classification*/
     int mClassificationField;
     /**Symbols for the unique values*/
     QMap<QString, QgsSymbol*> mSymbols;
-    /**Returns the symbol for a feature or 0 if there isn't any*/
-    QgsSymbol *symbolForFeature( const QgsFeature* f );
+
     /**Cached copy of all underlying symbols required attribute fields*/
     QgsAttributeList mSymbolAttributes;
     bool mSymbolAttributesDirty;  // insertValue was called

Modified: trunk/qgis/src/core/symbology-ng/qgscategorizedsymbolrendererv2.cpp
===================================================================
--- trunk/qgis/src/core/symbology-ng/qgscategorizedsymbolrendererv2.cpp	2010-11-19 07:51:19 UTC (rev 14713)
+++ trunk/qgis/src/core/symbology-ng/qgscategorizedsymbolrendererv2.cpp	2010-11-19 13:24:20 UTC (rev 14714)
@@ -75,7 +75,9 @@
     mAttrName( attrName ),
     mCategories( categories ),
     mSourceSymbol( NULL ),
-    mSourceColorRamp( NULL )
+    mSourceColorRamp( NULL ),
+    mRotationFieldIdx( -1 ),
+    mSizeScaleFieldIdx( -1 )
 {
   for ( int i = 0; i < mCategories.count(); ++i )
   {

Modified: trunk/qgis/src/core/symbology-ng/qgsgraduatedsymbolrendererv2.cpp
===================================================================
--- trunk/qgis/src/core/symbology-ng/qgsgraduatedsymbolrendererv2.cpp	2010-11-19 07:51:19 UTC (rev 14713)
+++ trunk/qgis/src/core/symbology-ng/qgsgraduatedsymbolrendererv2.cpp	2010-11-19 13:24:20 UTC (rev 14714)
@@ -100,7 +100,9 @@
     mRanges( ranges ),
     mMode( Custom ),
     mSourceSymbol( NULL ),
-    mSourceColorRamp( NULL )
+    mSourceColorRamp( NULL ),
+    mRotationFieldIdx( -1 ),
+    mSizeScaleFieldIdx( -1 )
 {
   // TODO: check ranges for sanity (NULL symbols, invalid ranges)
 }
@@ -421,13 +423,13 @@
 
   double base = pow( 10.0, floor( log10( cell ) ) );
   double unit = base;
-  if (( 2 * base ) - cell < h * ( cell - unit ) )
+  if (( 2 * base ) - cell < h *( cell - unit ) )
   {
     unit = 2.0 * base;
-    if (( 5 * base ) - cell < adjustBias * ( cell - unit ) )
+    if (( 5 * base ) - cell < adjustBias *( cell - unit ) )
     {
       unit = 5.0 * base;
-      if (( 10.0 * base ) - cell < h * ( cell - unit ) )
+      if (( 10.0 * base ) - cell < h *( cell - unit ) )
       {
         unit = 10.0 * base;
       }

Modified: trunk/qgis/src/core/symbology-ng/qgssinglesymbolrendererv2.cpp
===================================================================
--- trunk/qgis/src/core/symbology-ng/qgssinglesymbolrendererv2.cpp	2010-11-19 07:51:19 UTC (rev 14713)
+++ trunk/qgis/src/core/symbology-ng/qgssinglesymbolrendererv2.cpp	2010-11-19 13:24:20 UTC (rev 14714)
@@ -12,8 +12,7 @@
 #include <QDomElement>
 
 QgsSingleSymbolRendererV2::QgsSingleSymbolRendererV2( QgsSymbolV2* symbol )
-    : QgsFeatureRendererV2( "singleSymbol" )
-    , mTempSymbol( NULL )
+    : QgsFeatureRendererV2( "singleSymbol" ), mRotationFieldIdx( -1 ), mSizeScaleFieldIdx( -1 ), mTempSymbol( NULL )
 {
   Q_ASSERT( symbol );
   mSymbol = symbol;



More information about the QGIS-commit mailing list