[mapguide-commits] r7945 - in branches/2.5/MgDev/Desktop: MapViewer MgDesktop MgDesktop/Services/Rendering UnitTest

svn_mapguide at osgeo.org svn_mapguide at osgeo.org
Sun Dec 1 09:39:38 PST 2013


Author: jng
Date: 2013-12-01 09:39:38 -0800 (Sun, 01 Dec 2013)
New Revision: 7945

Modified:
   branches/2.5/MgDev/Desktop/MapViewer/MgLegend.cs
   branches/2.5/MgDev/Desktop/MapViewer/MgLegendControlPresenter.cs
   branches/2.5/MgDev/Desktop/MgDesktop/Services/Rendering/LegendPlotUtil.cpp
   branches/2.5/MgDev/Desktop/MgDesktop/Services/Rendering/LegendPlotUtil.h
   branches/2.5/MgDev/Desktop/MgDesktop/Services/Rendering/icons.h
   branches/2.5/MgDev/Desktop/MgDesktop/changelog.txt
   branches/2.5/MgDev/Desktop/UnitTest/TestRenderingService.cpp
   branches/2.5/MgDev/Desktop/UnitTest/TestRenderingService.h
Log:
mg-desktop: Merge r7935, r7936, r7943 and r7944 from trunk

Modified: branches/2.5/MgDev/Desktop/MapViewer/MgLegend.cs
===================================================================
--- branches/2.5/MgDev/Desktop/MapViewer/MgLegend.cs	2013-12-01 16:54:17 UTC (rev 7944)
+++ branches/2.5/MgDev/Desktop/MapViewer/MgLegend.cs	2013-12-01 17:39:38 UTC (rev 7945)
@@ -344,7 +344,7 @@
             get { return _themeCompressionLimit; }
             set 
             {
-                if (value != _themeCompressionLimit)
+                if (value == _themeCompressionLimit)
                     return;
 
                 _themeCompressionLimit = value;

Modified: branches/2.5/MgDev/Desktop/MapViewer/MgLegendControlPresenter.cs
===================================================================
--- branches/2.5/MgDev/Desktop/MapViewer/MgLegendControlPresenter.cs	2013-12-01 16:54:17 UTC (rev 7944)
+++ branches/2.5/MgDev/Desktop/MapViewer/MgLegendControlPresenter.cs	2013-12-01 17:39:38 UTC (rev 7945)
@@ -85,6 +85,12 @@
             return true;
         }
 
+        class RuleData
+        {
+            public int GeomType;
+            public XmlNodeList RuleNodes;
+        }
+
         private TreeNode CreateLayerNode(MgLayerBase layer)
         {
             var node = new TreeNode();
@@ -113,7 +119,7 @@
                 node.Tag = layerMeta;
                 node.ToolTipText = string.Format(Strings.DrawingLayerTooltip, Environment.NewLine, layer.Name, layer.FeatureSourceId);
             }
-            else
+            else //Vector or Grid layer
             {
                 var ldfId = layer.LayerDefinition;
                 if (_layers.ContainsKey(layer.GetObjectId()))
@@ -130,9 +136,13 @@
 
                 node.Tag = layerMeta;
 
+                const int LAYER_VECTOR = 0;
+                const int LAYER_RASTER = 1;
+                const int LAYER_DWF = 2;
+
                 XmlDocument doc = new XmlDocument();
                 doc.LoadXml(layerMeta.LayerDefinitionContent);
-                int type = 0;
+                int type = LAYER_VECTOR;
                 XmlNodeList scaleRanges = doc.GetElementsByTagName("VectorScaleRange"); //NOXLATE
                 if (scaleRanges.Count == 0)
                 {
@@ -142,16 +152,17 @@
                         scaleRanges = doc.GetElementsByTagName("DrawingLayerDefinition"); //NOXLATE
                         if (scaleRanges.Count == 0)
                             return null;
-                        type = 2;
+                        type = LAYER_DWF;
                     }
                     else
-                        type = 1;
+                        type = LAYER_RASTER;
                 }
 
                 String[] typeStyles = new String[] { "PointTypeStyle", "LineTypeStyle", "AreaTypeStyle", "CompositeTypeStyle" }; //NOXLATE
                 String[] ruleNames = new String[] { "PointRule", "LineRule", "AreaRule", "CompositeRule" }; //NOXLATE
 
                 node.ToolTipText = string.Format(Strings.DefaultLayerTooltip, Environment.NewLine, layer.Name, layer.FeatureSourceId, layer.FeatureClassName);
+                //Do this if not cached already from a previous run
                 if (!layerMeta.HasTheme() || !layerMeta.HasDefaultIcons())
                 {
                     for (int sc = 0; sc < scaleRanges.Count; sc++)
@@ -167,95 +178,165 @@
                         if (maxElt.Count > 0)
                             maxScale = maxElt[0].ChildNodes[0].Value;
 
-                        if (type != 0)
+                        if (type != LAYER_VECTOR)
                             break;
 
-                        for (int geomType = 0; geomType < typeStyles.Length; geomType++)
+                        bool bComposite = false;
+
+                        //Check TS count. Give precedence to composite type styles
+                        List<XmlNode> typeStyleCol = new List<XmlNode>();
+                        XmlNodeList styleNodes = scaleRange.GetElementsByTagName(typeStyles[3]);
+                        List<RuleData> rules = new List<RuleData>();
+                        if (styleNodes.Count > 0)
                         {
-                            ThemeCategory themeCat = new ThemeCategory()
+                            foreach (XmlNode n in styleNodes)
                             {
-                                MinScale = minScale,
-                                MaxScale = maxScale,
-                                GeometryType = geomType
-                            };
-
-                            if (layerMeta.CategoryExists(themeCat))
-                                continue;
-
-                            int catIndex = 0;
-                            XmlNodeList typeStyle = scaleRange.GetElementsByTagName(typeStyles[geomType]);
-                            for (int st = 0; st < typeStyle.Count; st++)
-                            {
                                 // We will check if this typestyle is going to be shown in the legend
-                                XmlNodeList showInLegend = ((XmlElement)typeStyle[st]).GetElementsByTagName("ShowInLegend"); //NOXLATE
+                                XmlNodeList showInLegend = ((XmlElement)n).GetElementsByTagName("ShowInLegend"); //NOXLATE
                                 if (showInLegend.Count > 0)
                                     if (!bool.Parse(showInLegend[0].ChildNodes[0].Value))
                                         continue;   // This typestyle does not need to be shown in the legend
 
-                                XmlNodeList rules = ((XmlElement)typeStyle[st]).GetElementsByTagName(ruleNames[geomType]);
-                                if (rules.Count > 1)
+                                typeStyleCol.Add(n);
+
+                                var ruleData = new RuleData();
+                                ruleData.GeomType = 3;
+                                ruleData.RuleNodes = ((XmlElement)n).GetElementsByTagName(ruleNames[3]);
+                                if (ruleData.RuleNodes.Count > 0)
+                                    rules.Add(ruleData);
+                            }
+
+                            bComposite = true;
+                        }
+                        else
+                        {
+                            for (int t = 0; t < 3; t++)
+                            {
+                                styleNodes = scaleRange.GetElementsByTagName(typeStyles[t]);
+                                foreach (XmlNode n in styleNodes)
                                 {
-                                    layerMeta.SetDefaultIcon(themeCat, Properties.Resources.lc_theme);
-                                    node.ToolTipText = string.Format(Strings.ThemedLayerTooltip, Environment.NewLine, layer.Name, layer.FeatureSourceId, layer.FeatureClassName, rules.Count);
+                                    // We will check if this typestyle is going to be shown in the legend
+                                    XmlNodeList showInLegend = ((XmlElement)n).GetElementsByTagName("ShowInLegend"); //NOXLATE
+                                    if (showInLegend.Count > 0)
+                                        if (!bool.Parse(showInLegend[0].ChildNodes[0].Value))
+                                            continue;   // This typestyle does not need to be shown in the legend
 
-                                    if (_legend.ThemeCompressionLimit > 0 && rules.Count > _legend.ThemeCompressionLimit)
+                                    typeStyleCol.Add(n);
+
+                                    var ruleData = new RuleData();
+                                    ruleData.GeomType = t;
+                                    ruleData.RuleNodes = ((XmlElement)n).GetElementsByTagName(ruleNames[t]);
+                                    if (ruleData.RuleNodes.Count > 0)
+                                        rules.Add(ruleData);
+                                }
+                            }
+                        }
+
+                        //No type styles. Skip
+                        if (typeStyleCol.Count == 0)
+                            continue;
+
+                        //Determine if this is themed or not
+                        int nTotalRules = 0;
+                        foreach(RuleData r in rules)
+                        {
+                            nTotalRules += r.RuleNodes.Count;
+                        }
+                        bool bThemed = nTotalRules > 1;
+                        if (bThemed)
+                        {
+                            int catIndex = 0;
+                            for (int i = 0; i < rules.Count; i++)
+                            {
+                                RuleData theRule = rules[i];
+                                ThemeCategory themeCat = new ThemeCategory()
+                                {
+                                    MinScale = minScale,
+                                    MaxScale = maxScale,
+                                    GeometryType = theRule.GeomType
+                                };
+
+                                //Non-composite styles must be processed once
+                                if (layerMeta.CategoryExists(themeCat) && theRule.GeomType != 3)
+                                    continue;
+
+                                layerMeta.SetDefaultIcon(themeCat, Properties.Resources.lc_theme);
+                                node.ToolTipText = string.Format(Strings.ThemedLayerTooltip, Environment.NewLine, layer.Name, layer.FeatureSourceId, layer.FeatureClassName, nTotalRules);
+
+                                if (_legend.ThemeCompressionLimit > 0 && theRule.RuleNodes.Count > _legend.ThemeCompressionLimit)
+                                {
+                                    AddThemeRuleNode(layerMeta, themeCat, node, theRule.GeomType, catIndex, theRule.RuleNodes, 0);
+                                    node.Nodes.Add(CreateCompressedThemeNode(layerMeta, themeCat, theRule.RuleNodes.Count - 2));
+                                    AddThemeRuleNode(layerMeta, themeCat, node, theRule.GeomType, (catIndex + (theRule.RuleNodes.Count - 1)), theRule.RuleNodes, theRule.RuleNodes.Count - 1);
+                                }
+                                else
+                                {
+                                    for (int r = 0; r < theRule.RuleNodes.Count; r++)
                                     {
-                                        AddThemeRuleNode(layerMeta, themeCat, node, geomType, 0, rules, 0);
-                                        node.Nodes.Add(CreateCompressedThemeNode(layerMeta, themeCat, rules.Count - 2));
-                                        AddThemeRuleNode(layerMeta, themeCat, node, geomType, rules.Count - 1, rules, rules.Count - 1);
+                                        AddThemeRuleNode(layerMeta, themeCat, node, theRule.GeomType, (catIndex + r), theRule.RuleNodes, r);
                                     }
-                                    else
-                                    {
-                                        for (int r = 0; r < rules.Count; r++)
-                                        {
-                                            AddThemeRuleNode(layerMeta, themeCat, node, geomType, catIndex++, rules, r);
-                                        }
-                                    }
                                 }
-                                else
+                                //Only bump catIndex if composite, as category indexes for composite styles are handled differently
+                                if (bComposite)
+                                    catIndex += theRule.RuleNodes.Count;
+                            }
+                        }
+                        else
+                        {
+                            Trace.Assert(rules.Count == 1);
+                            Trace.Assert(rules[0].RuleNodes.Count == 1);
+                            RuleData theRule = rules[0];
+
+                            ThemeCategory themeCat = new ThemeCategory()
+                            {
+                                MinScale = minScale,
+                                MaxScale = maxScale,
+                                GeometryType = theRule.GeomType
+                            };
+
+                            if (layerMeta.CategoryExists(themeCat))
+                                continue;
+
+                            if (LayerNodeMetadata.ScaleIsApplicable(_map.ViewScale, themeCat))
+                            {
+                                if (!layerMeta.HasDefaultIconsAt(_map.ViewScale))
                                 {
-                                    if (LayerNodeMetadata.ScaleIsApplicable(_map.ViewScale, themeCat))
+                                    try
                                     {
-                                        if (!layerMeta.HasDefaultIconsAt(_map.ViewScale))
+                                        MgByteReader layerIcon = _provider.GenerateLegendImage(layer.LayerDefinition,
+                                                                                               _map.ViewScale,
+                                                                                               16,
+                                                                                               16,
+                                                                                               "PNG", //NOXLATE
+                                                                                               (theRule.GeomType+1),
+                                                                                               -1);
+                                        legendCallCount++;
+                                        if (layerIcon != null)
                                         {
                                             try
                                             {
-                                                MgByteReader layerIcon = _provider.GenerateLegendImage(layer.LayerDefinition,
-                                                                                                           _map.ViewScale,
-                                                                                                           16,
-                                                                                                           16,
-                                                                                                           "PNG", //NOXLATE
-                                                                                                           -1,
-                                                                                                           -1);
-                                                legendCallCount++;
-                                                if (layerIcon != null)
+                                                byte[] b = new byte[layerIcon.GetLength()];
+                                                layerIcon.Read(b, b.Length);
+                                                using (var ms = new MemoryStream(b))
                                                 {
-                                                    try
-                                                    {
-                                                        byte[] b = new byte[layerIcon.GetLength()];
-                                                        layerIcon.Read(b, b.Length);
-                                                        using (var ms = new MemoryStream(b))
-                                                        {
-                                                            layerMeta.SetDefaultIcon(themeCat, Image.FromStream(ms));
-                                                            node.ToolTipText = string.Format(Strings.DefaultLayerTooltip, Environment.NewLine, layer.Name, layer.FeatureSourceId, layer.FeatureClassName);
-                                                        }
-                                                    }
-                                                    finally
-                                                    {
-                                                        layerIcon.Dispose();
-                                                    }
+                                                    layerMeta.SetDefaultIcon(themeCat, Image.FromStream(ms));
+                                                    node.ToolTipText = string.Format(Strings.DefaultLayerTooltip, Environment.NewLine, layer.Name, layer.FeatureSourceId, layer.FeatureClassName);
                                                 }
-                                                else
-                                                {
-                                                    layerMeta.SetDefaultIcon(themeCat, Properties.Resources.lc_broken);
-                                                }
                                             }
-                                            catch
+                                            finally
                                             {
-                                                layerMeta.SetDefaultIcon(themeCat, Properties.Resources.lc_broken);
+                                                layerIcon.Dispose();
                                             }
                                         }
+                                        else
+                                        {
+                                            layerMeta.SetDefaultIcon(themeCat, Properties.Resources.lc_broken);
+                                        }
                                     }
+                                    catch
+                                    {
+                                        layerMeta.SetDefaultIcon(themeCat, Properties.Resources.lc_broken);
+                                    }
                                 }
                             }
                         }
@@ -271,9 +352,9 @@
             return node;
         }
 
-        private void AddThemeRuleNode(LayerNodeMetadata layerMeta, ThemeCategory themeCat, TreeNode node, int geomType, int catIndex, XmlNodeList rules, int r)
+        private void AddThemeRuleNode(LayerNodeMetadata layerMeta, ThemeCategory themeCat, TreeNode node, int geomType, int catIndex, XmlNodeList rules, int ruleOffset)
         {
-            XmlElement rule = (XmlElement)rules[r];
+            XmlElement rule = (XmlElement)rules[ruleOffset];
             XmlNodeList label = rule.GetElementsByTagName("LegendLabel"); //NOXLATE
             XmlNodeList filter = rule.GetElementsByTagName("Filter"); //NOXLATE
 

Modified: branches/2.5/MgDev/Desktop/MgDesktop/Services/Rendering/LegendPlotUtil.cpp
===================================================================
--- branches/2.5/MgDev/Desktop/MgDesktop/Services/Rendering/LegendPlotUtil.cpp	2013-12-01 16:54:17 UTC (rev 7944)
+++ branches/2.5/MgDev/Desktop/MgDesktop/Services/Rendering/LegendPlotUtil.cpp	2013-12-01 17:39:38 UTC (rev 7945)
@@ -80,6 +80,9 @@
     RS_LineStroke lineStroke;
     dr.ProcessPolyline(&lb, lineStroke);
 
+    //Pad left at the top-level
+    legendOffsetX += (defaultLegendMargin * convertUnits);
+
     //And then do the content.
     BuildLegendContent(map, dMapScale, legendSpec, legendOffsetX, legendOffsetY, dr, convertUnits);
 }
@@ -93,6 +96,10 @@
     textDef.halign() = RS_HAlignment_Left;
     textDef.valign() = RS_VAlignment_Base;
 
+    //for convenience compute legend bitmap size in plot units (inches, mm, pixels, whatever)
+    double dIconWidth = ((double)bitmapPixelWidth / bitmapDpi)*convertUnits;
+    double dIconHeight = ((double)bitmapPixelHeight / bitmapDpi)*convertUnits;
+
     // Get the layer info
     double x = legendOffsetX + legendSpec->GetMarginLeft();
     double y = legendOffsetY + legendSpec->GetPaperHeight() - legendSpec->GetMarginTop() - legendFontHeightMeters*M_TO_IN*convertUnits;
@@ -101,63 +108,54 @@
     //for icon and label from the bottom up
     y -= legendSpacing * convertUnits;
 
+    // Compile the necessary information needed to avoid repeated linear searches for this information
+    LayerGroupChildMap groupChildren;
+    VisibleLayerCountMap visibleLayers;
+    CompileInformation(map, visibleLayers, groupChildren);
+
     // Add legend entries for layers that do not belong to a group
-    ProcessLayersForLegend(map, scale, NULL, x, y, textDef, dr, legendSpec, legendOffsetY, convertUnits);
+    ProcessLayersForLegend(map, scale, NULL, x, y, textDef, dr, legendSpec, legendOffsetY, convertUnits, visibleLayers, groupChildren);
+}
 
-    // do layer groups
-    Ptr<MgLayerGroupCollection> mggroups = map->GetLayerGroups();
+void MgdLegendPlotUtil::CompileInformation(MgdMap* map, VisibleLayerCountMap& visibleLayers, LayerGroupChildMap& groupChildren)
+{
     Ptr<MgLayerCollection> layers = map->GetLayers();
+    Ptr<MgLayerGroupCollection> groups = map->GetLayerGroups();
 
-    // iterate over groups and draw each group's layers
-    for (int k = 0; k < mggroups->GetCount(); k++)
+    for (INT32 i = 0; i < layers->GetCount(); i++)
     {
-        Ptr<MgLayerGroup> mggroup = mggroups->GetItem(k);
+        Ptr<MgLayerBase> layer = layers->GetItem(i);
+        if (!layer->IsVisible()) //Not visible
+            continue;
 
-        // Count number of visible layers in this group.
-        bool hasVisibleLayers = false;
-        for (int l = 0; l < layers->GetCount(); l++)
-        {
-            Ptr<MgLayerBase> layer = layers->GetItem(l);
-            Ptr<MgLayerGroup> layerGroup = layer->GetGroup();
-            if ((layer->IsVisible()) && (layerGroup.p == mggroup.p))
-            {
-                hasVisibleLayers = true;
-                break;
-            }
-        }
-        if (!hasVisibleLayers)
+        Ptr<MgLayerGroup> parentGroup = layer->GetGroup();
+        if (NULL == parentGroup.p) //No parent
             continue;
 
-        if (mggroup == NULL)
-        {
-            throw new MgNullReferenceException(L"MgdLegendPlotUtil.AddLegendElement", __LINE__, __WFILE__, NULL, L"", NULL);
-        }
-        Ptr<MgLayerGroup> mgparent = mggroup->GetGroup();
+        STRING parentGroupName = parentGroup->GetName();
+        VisibleLayerCountMap::iterator vit = visibleLayers.find(parentGroupName);
+        if (vit == visibleLayers.end())
+            visibleLayers[parentGroupName] = 0;
+        visibleLayers[parentGroupName]++;
+    }
 
-        double indent = 0;
-        while (mgparent)
+    for (INT32 i = 0; i < groups->GetCount(); i++)
+    {
+        Ptr<MgLayerGroup> group = groups->GetItem(i);
+        Ptr<MgLayerGroup> parentGroup = group->GetGroup();
+        if (NULL != parentGroup.p)
         {
-            indent += PrintGroupIndent;
-            mgparent = mgparent->GetGroup();
+            STRING groupName = group->GetName();
+            STRING parentGroupName = parentGroup->GetName();
+            LayerGroupChildMap::iterator cit = groupChildren.find(parentGroupName);
+            if (cit == groupChildren.end())
+                groupChildren[parentGroupName] = LayerGroupList();
+            groupChildren[parentGroupName].push_back(groupName);
         }
-
-        x = legendOffsetX + (defaultLegendMargin + indent)*convertUnits;
-
-        RS_LabelInfo info(x, y + legendTextVertAdjust*convertUnits, textDef);
-        dr.ProcessLabelGroup(&info, 1, mggroup->GetLegendLabel(), RS_OverpostType_All, false, NULL, 0.0);
-
-        y -= legendSpacing*convertUnits;
-
-        if (y < legendSpec->GetMarginBottom())
-            break;
-
-        // Process the layers
-        ProcessLayersForLegend(map, scale, mggroup, x, y, textDef, dr, legendSpec, legendOffsetY, convertUnits);
     }
 }
 
-
-void MgdLegendPlotUtil::ProcessLayersForLegend(MgdMap* map, double mapScale, MgLayerGroup* mggroup, double startX, double& startY, RS_TextDef textDef, Renderer& dr, MgdPlotSpecification* legendSpec, double legendOffsetY, double convertUnits)
+void MgdLegendPlotUtil::ProcessLayersForLegend(MgdMap* map, double mapScale, MgLayerGroup* mggroup, double startX, double& startY, RS_TextDef textDef, Renderer& dr, MgdPlotSpecification* legendSpec, double legendOffsetY, double convertUnits, VisibleLayerCountMap& visibleLayers, LayerGroupChildMap& groupChildren)
 {
     double x;
     double &y = startY;
@@ -178,6 +176,29 @@
     //bottom of the legend -- where we stop drawing
     double bottomLimit = legendOffsetY + legendSpec->GetMarginBottom();
 
+    if (NULL != mggroup)
+    {
+        x = startX - initialMarginX;
+        // use group icon
+        RS_Bounds b2(x, y, x + dIconWidth, y + dIconHeight);
+        DrawPNG(&dr, (unsigned char*)LAYER_GROUP_ICON, sizeof(LAYER_GROUP_ICON), bitmapPixelWidth, bitmapPixelHeight, b2);
+
+        // Add the group legend label.
+        RS_LabelInfo info(x + dIconWidth + (defaultLegendMargin * convertUnits), y + legendTextVertAdjust*convertUnits, textDef);
+        dr.ProcessLabelGroup(&info, 1, mggroup->GetLegendLabel(), RS_OverpostType_All, false, NULL, 0.0);
+
+        // Indent for children
+        x += initialMarginX;
+
+        //move y cursor down one line
+        y -= verticalDelta;
+
+        if (y < bottomLimit)
+        {
+            return;
+        }
+    }
+
     // build the list of layers that need to be processed
     Ptr<MgLayerCollection> layers = map->GetLayers();
     Ptr<MgStringCollection> layerIds = new MgStringCollection();
@@ -268,24 +289,70 @@
             if (ftscol->GetCount() == 0)
                 continue;
 
-            // if there are multiple feature type styles, using the first one
-            MdfModel::FeatureTypeStyle* fts = ftscol->GetAt(0);
-            MdfModel::RuleCollection* rules = fts->GetRules();
-            int nRuleCount = rules->GetCount();
+            //Peek ahead to determine what we're dealing with
+            bool bThemed = false;
+            int nCompositeStyleCount = 0;
+            MdfModel::FeatureTypeStyle* singleFTS = NULL;
+            MdfModel::FeatureTypeStyle* singleCTS = NULL;
+            int nTotalFTSRules = 0;
+            int nTotalCTSRules = 0;
+            //Compile type/rule count to determine if this is a themed layer
+            for (int j = 0; j < ftscol->GetCount(); j++)
+            {
+                MdfModel::FeatureTypeStyle* fts = ftscol->GetAt(j);
+                if (!fts->IsShowInLegend())
+                    continue;
 
+                MdfModel::RuleCollection* rules = fts->GetRules();
+                MdfModel::CompositeTypeStyle* cts = dynamic_cast<MdfModel::CompositeTypeStyle*>(fts);
+                //Composite Styles take precedence (it's what the stylizer does. So we're doing the same thing here). 
+                //If a Composite Style exists, we're using it.
+                if (NULL != cts)
+                {
+                    //For a single type scale range, this will only be set once. Otherwise it could
+                    //be set many times over (for each style type we encounter), but this is okay 
+                    //because we won't be using this pointer anyway for multi-type layers
+                    singleCTS = fts;
+                    nTotalCTSRules += rules->GetCount();
+                    nCompositeStyleCount++;
+                }
+                else
+                {
+                    //For a single type scale range, this will only be set once. Otherwise it could
+                    //be set many times over (for each style type we encounter), but this is okay 
+                    //because we won't be using this pointer anyway for multi-type layers
+                    singleFTS = fts;
+                    nTotalFTSRules += rules->GetCount();
+                }
+            }
+            //It's a themed layer if we found more than one rule of that type
+            bThemed = (nTotalFTSRules > 1);
+            //Found a composite style, re-evaluate against composite rule count
+            if (nCompositeStyleCount > 0)
+                bThemed = (nTotalCTSRules > 1);
+
             //add the layer icon, if any
             x = startX;
             RS_Bounds b2(x, y, x + dIconWidth, y + dIconHeight);
 
-            if (nRuleCount > 1)
+            if (bThemed)
             {
                 //in case of themed layer, use standard theme icon
                 DrawPNG(&dr, (unsigned char*)THEMED_LAYER_ICON, sizeof(THEMED_LAYER_ICON), bitmapPixelWidth, bitmapPixelHeight, b2);
             }
             else
             {
+                assert(NULL != singleFTS || NULL != singleCTS); //Should've been set by peek-ahead from above
+
+                MdfModel::FeatureTypeStyle* theFTS = NULL;
+                //Composite TS takes precedence
+                if (NULL != singleCTS)
+                    theFTS = singleCTS;
+                else if (NULL != singleFTS)
+                    theFTS = singleFTS;
+
                 //otherwise pick the icon from the only rule
-                Ptr<MgByteReader> layerIcon = MgdMappingUtil::DrawFTS(m_svcResource, fts, bitmapPixelWidth, bitmapPixelHeight, 0);
+                Ptr<MgByteReader> layerIcon = MgdMappingUtil::DrawFTS(m_svcResource, theFTS, bitmapPixelWidth, bitmapPixelHeight, 0);
 
                 if (layerIcon.p)
                 {
@@ -303,38 +370,56 @@
             RS_LabelInfo info(x, y + verticalTextAdjust, textDef);
             dr.ProcessLabelGroup(&info, 1, mapLayer->GetLegendLabel(), RS_OverpostType_All, false, NULL, 0.0);
 
-            if (nRuleCount > 1)
+            //layer is themed : draw the theme icons under the layer title
+            if (bThemed)
             {
                 //theme icons draw slightly indented
                 x = startX + initialMarginX;
 
-                //layer is themed : draw the theme icons under the layer title
-                for (int i = 0; i < nRuleCount; i++)
+                for (int j = 0; j < ftscol->GetCount(); j++)
                 {
-                    MdfModel::Rule* rule = rules->GetAt(i);
+                    MdfModel::FeatureTypeStyle* fts = ftscol->GetAt(j);
+                    //Skip items not marked for display
+                    if (!fts->IsShowInLegend())
+                        continue;
 
-                    //move y cursor down one line
-                    y -= verticalDelta;
+                    MdfModel::CompositeTypeStyle* cts = dynamic_cast<MdfModel::CompositeTypeStyle*>(fts);
+                    //If we found one or more composite styles, then they take precedence. So skip all non-composite ones
+                    if (nCompositeStyleCount > 0 && NULL == cts)
+                        continue;
 
-                    if (y < bottomLimit)
-                        break;
+                    MdfModel::RuleCollection* rules = fts->GetRules();
 
-                    //draw the icon for the current theming rule
-                    Ptr<MgByteReader> rdr = MgdMappingUtil::DrawFTS(m_svcResource, fts, bitmapPixelWidth, bitmapPixelHeight, i);
-
-                    if (rdr != NULL)
+                    for (int k = 0; k < rules->GetCount(); k++)
                     {
-                        MgByteSink sink(rdr);
-                        Ptr<MgByte> bytes = sink.ToBuffer();
+                        MdfModel::Rule* rule = rules->GetAt(k);
 
-                        RS_Bounds b2(x, y, x + dIconWidth, y + dIconHeight);
-                        DrawPNG(&dr, bytes->Bytes(), bytes->GetLength(), bitmapPixelWidth, bitmapPixelHeight, b2);
+                        //move y cursor down one line
+                        y -= verticalDelta;
+
+                        if (y < bottomLimit)
+                            break;
+
+                        //draw the icon for the current theming rule
+                        Ptr<MgByteReader> rdr = MgdMappingUtil::DrawFTS(m_svcResource, fts, bitmapPixelWidth, bitmapPixelHeight, k);
+
+                        if (rdr != NULL)
+                        {
+                            MgByteSink sink(rdr);
+                            Ptr<MgByte> bytes = sink.ToBuffer();
+
+                            RS_Bounds b2(x, y, x + dIconWidth, y + dIconHeight);
+                            DrawPNG(&dr, bytes->Bytes(), bytes->GetLength(), bitmapPixelWidth, bitmapPixelHeight, b2);
+                        }
+
+                        //draw the label after the icon, but also allow
+                        //some blank space for better clarity
+                        RS_LabelInfo info(x + dIconWidth + initialMarginX, y + verticalTextAdjust, textDef);
+                        dr.ProcessLabelGroup(&info, 1, rule->GetLegendLabel(), RS_OverpostType_All, false, NULL, 0.0);
                     }
 
-                    //draw the label after the icon, but also allow
-                    //some blank space for better clarity
-                    RS_LabelInfo info(x + dIconWidth + initialMarginX, y + verticalTextAdjust, textDef);
-                    dr.ProcessLabelGroup(&info, 1, rule->GetLegendLabel(), RS_OverpostType_All, false, NULL, 0.0);
+                    if (y < bottomLimit)
+                        break;
                 }
             }
         }
@@ -382,6 +467,29 @@
             break;
         }
     }
+
+    //Process child groups of this legend
+    Ptr<MgLayerGroupCollection> groups = map->GetLayerGroups();
+    for (int i = 0; i < groups->GetCount(); i++)
+    {
+        Ptr<MgLayerGroup> group = groups->GetItem(i);
+        if (!group->GetDisplayInLegend())
+            continue;
+
+        Ptr<MgLayerGroup> groupParent = group->GetGroup();
+        if (groupParent.p == mggroup)
+        {
+            //If this group has no visible layers, skip it
+            if (!HasVisibleLayers(group->GetName(), visibleLayers, groupChildren))
+                continue;
+
+            ProcessLayersForLegend(map, mapScale, group, startX + initialMarginX, y, textDef, dr, legendSpec, legendOffsetY, convertUnits, visibleLayers, groupChildren);
+            if (y < bottomLimit)
+            {
+                break;
+            }
+        }
+    }
 }
 
 
@@ -1280,6 +1388,28 @@
     dr.EndLayout();
 }
 
+bool MgdLegendPlotUtil::HasVisibleLayers(CREFSTRING groupName, VisibleLayerCountMap& visibleLayers, LayerGroupChildMap& groupChildren)
+{
+    INT32 total = 0;
+    VisibleLayerCountMap::iterator vit = visibleLayers.find(groupName);
+    if (vit != visibleLayers.end())
+    {
+        if (vit->second > 0)
+            return true;
+    }
+
+    LayerGroupChildMap::iterator cit = groupChildren.find(groupName);
+    if (cit != groupChildren.end())
+    {
+        for (LayerGroupList::iterator lit = cit->second.begin(); lit != cit->second.end(); lit++)
+        {
+            if (HasVisibleLayers(*lit, visibleLayers, groupChildren))
+                return true;
+        }
+    }
+    return false;
+}
+
 //
 //  Compute the legend size and the offset position on the page
 //

Modified: branches/2.5/MgDev/Desktop/MgDesktop/Services/Rendering/LegendPlotUtil.h
===================================================================
--- branches/2.5/MgDev/Desktop/MgDesktop/Services/Rendering/LegendPlotUtil.h	2013-12-01 16:54:17 UTC (rev 7944)
+++ branches/2.5/MgDev/Desktop/MgDesktop/Services/Rendering/LegendPlotUtil.h	2013-12-01 17:39:38 UTC (rev 7945)
@@ -3,6 +3,10 @@
 
 class EPlotRenderer;
 
+typedef std::vector<STRING> LayerGroupList;
+typedef std::map<STRING, LayerGroupList> LayerGroupChildMap;
+typedef std::map<STRING, int> VisibleLayerCountMap;
+
 class MG_DESKTOP_API MgdLegendPlotUtil
 {
 public:
@@ -25,12 +29,14 @@
     //Eventually the scale bar and north arrow ones need to be cleaned up also in order
     //to use them in the AJAX viewer
     void AddLegendElement(double dMapScale, Renderer& dr, MgdMap* map, MgdPlotSpecification* plotSpec, double legendOffsetX, double legendOffsetY);
-    void ProcessLayersForLegend(MgdMap* map, double mapScale, MgLayerGroup* mggroup, double startX, double& startY, RS_TextDef textDef, Renderer& dr, MgdPlotSpecification* plotSpec, double legendOffsetY, double convertUnits);
+    void ProcessLayersForLegend(MgdMap* map, double mapScale, MgLayerGroup* mggroup, double startX, double& startY, RS_TextDef textDef, Renderer& dr, MgdPlotSpecification* plotSpec, double legendOffsetY, double convertUnits, VisibleLayerCountMap& visibleLayers, LayerGroupChildMap& groupChildren);
     void BuildLegendContent(MgdMap* map, double scale, MgdPlotSpecification* legendSpec, double legendOffsetX, double legendOffsetY, Renderer& dr, double convertUnits);
 
     void ExtentFromMapCenter(MgdMap* map, double metersPerUnit, RS_Bounds& b);
+    void CompileInformation(MgdMap* map, VisibleLayerCountMap& visibleLayers, LayerGroupChildMap& groupChildren);
 
 private:
+    static bool HasVisibleLayers(CREFSTRING groupName, VisibleLayerCountMap& visibleLayers, LayerGroupChildMap& groupChildren);
 
     MgResourceService* m_svcResource;
     RS_String m_legendFontName;
@@ -90,8 +96,8 @@
 
 const double legendSpacing = bitmapPixelHeight / bitmapDpi + 0.005;
 const double defaultLegendMargin = 0.1; // inch
-const double legendFontHeightMeters = 0.002;
-const double legendTextVertAdjust = 0.07;  // inch
+const double legendFontHeightMeters = 0.003;
+const double legendTextVertAdjust = 0.06;  // inch
 
 const double PrintLegendWidth     = 2.0;
 const double PrintLegendPadding   = 0.1;

Modified: branches/2.5/MgDev/Desktop/MgDesktop/Services/Rendering/icons.h
===================================================================
--- branches/2.5/MgDev/Desktop/MgDesktop/Services/Rendering/icons.h	2013-12-01 16:54:17 UTC (rev 7944)
+++ branches/2.5/MgDev/Desktop/MgDesktop/Services/Rendering/icons.h	2013-12-01 17:39:38 UTC (rev 7945)
@@ -125,4 +125,26 @@
 0x82
 };
 
+//lc_group.png
+const unsigned char LAYER_GROUP_ICON[] = {
+0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52,
+0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x08, 0x06, 0x00, 0x00, 0x00, 0x1f, 0xf3, 0xff,
+0x61, 0x00, 0x00, 0x00, 0x01, 0x73, 0x52, 0x47, 0x42, 0x00, 0xae, 0xce, 0x1c, 0xe9, 0x00, 0x00,
+0x00, 0x04, 0x67, 0x41, 0x4d, 0x41, 0x00, 0x00, 0xb1, 0x8f, 0x0b, 0xfc, 0x61, 0x05, 0x00, 0x00,
+0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0e, 0xc3, 0x00, 0x00, 0x0e, 0xc3, 0x01, 0xc7,
+0x6f, 0xa8, 0x64, 0x00, 0x00, 0x00, 0x1a, 0x74, 0x45, 0x58, 0x74, 0x53, 0x6f, 0x66, 0x74, 0x77,
+0x61, 0x72, 0x65, 0x00, 0x50, 0x61, 0x69, 0x6e, 0x74, 0x2e, 0x4e, 0x45, 0x54, 0x20, 0x76, 0x33,
+0x2e, 0x35, 0x2e, 0x31, 0x30, 0x30, 0xf4, 0x72, 0xa1, 0x00, 0x00, 0x00, 0x84, 0x49, 0x44, 0x41,
+0x54, 0x38, 0x4f, 0x63, 0xf8, 0xff, 0xff, 0x3f, 0x45, 0x18, 0xab, 0x20, 0x29, 0x18, 0x4c, 0x1c,
+0x5c, 0xd3, 0xf2, 0xbf, 0x39, 0x92, 0x13, 0x03, 0x83, 0xc4, 0x91, 0x15, 0x63, 0xc3, 0x60, 0x02,
+0xa4, 0xf8, 0xff, 0xdb, 0x5e, 0x0c, 0x8c, 0x6e, 0x20, 0x32, 0x86, 0x19, 0x8e, 0x6a, 0xc0, 0x75,
+0x4b, 0x54, 0xfc, 0xa6, 0x03, 0xc3, 0x50, 0x10, 0xbe, 0xb4, 0x25, 0xe2, 0x7f, 0xa2, 0x21, 0x0b,
+0x61, 0x03, 0x90, 0x6d, 0xc4, 0x86, 0x31, 0x0c, 0xc0, 0x50, 0x80, 0x66, 0x20, 0x0c, 0x5f, 0xde,
+0x62, 0x89, 0xdd, 0x05, 0xe8, 0x9a, 0x40, 0x0a, 0xb1, 0xe1, 0x1d, 0xb3, 0x35, 0xf0, 0x1b, 0x80,
+0x4d, 0x13, 0x32, 0x1e, 0xee, 0x06, 0xc0, 0x14, 0x10, 0xc2, 0x28, 0x06, 0x80, 0x52, 0x15, 0x48,
+0x80, 0x14, 0xbc, 0x61, 0x46, 0x23, 0xc2, 0x00, 0x4a, 0x30, 0x56, 0x41, 0xe2, 0xf1, 0x7f, 0x06,
+0x00, 0x36, 0x20, 0xae, 0xaf, 0x57, 0x56, 0xf5, 0x08, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e,
+0x44, 0xae, 0x42, 0x60, 0x82
+};
+
 #endif

Modified: branches/2.5/MgDev/Desktop/MgDesktop/changelog.txt
===================================================================
--- branches/2.5/MgDev/Desktop/MgDesktop/changelog.txt	2013-12-01 16:54:17 UTC (rev 7944)
+++ branches/2.5/MgDev/Desktop/MgDesktop/changelog.txt	2013-12-01 17:39:38 UTC (rev 7945)
@@ -1,5 +1,18 @@
 API Changelog:
 
+ - Fix: Port legend image rendering fixes from MapGuide
+ - Fix: No-op UPDATEREPOSITORY operations in a package manifest. Packages containing such operations can now be loaded without errors
+
+Viewer Changelog:
+
+ - New Generic Redlining component
+ - Fix: Incorrect display of layers with multiple styles and/or composite styles in legend.
+
+2.5.1.7768 (16 Aug 2013)
+========================
+
+API Changelog:
+
  - Fix: MgdResourceService::SetResource not properly flushing out in-memory cached content
  - Fix: Guard against duplicate extended feature classes 
 

Modified: branches/2.5/MgDev/Desktop/UnitTest/TestRenderingService.cpp
===================================================================
--- branches/2.5/MgDev/Desktop/UnitTest/TestRenderingService.cpp	2013-12-01 16:54:17 UTC (rev 7944)
+++ branches/2.5/MgDev/Desktop/UnitTest/TestRenderingService.cpp	2013-12-01 17:39:38 UTC (rev 7945)
@@ -321,6 +321,38 @@
         Ptr<MgByteReader> dataReader7 = dataSource7->GetReader();
         m_svcResource->SetResourceData(fsres6, L"UT_VotingDistricts.sdf", L"File", dataReader7);
 
+        // ---------------------------------------------------------
+        // Data for exercising legend rendering
+        // ---------------------------------------------------------
+        Ptr<MgResourceIdentifier> ldfres14 = new MgResourceIdentifier(L"Library://UnitTests/Layers/MultiFTS.LayerDefinition");
+        Ptr<MgByteSource> ldfsrc14 = new MgByteSource(L"../UnitTestFiles/UT_MultiFTS.ldf", false);
+        Ptr<MgByteReader> ldfrdr14 = ldfsrc14->GetReader();
+        m_svcResource->SetResource(ldfres14, ldfrdr14, NULL);
+
+        Ptr<MgResourceIdentifier> ldfres15 = new MgResourceIdentifier(L"Library://UnitTests/Layers/MultiCTS.LayerDefinition");
+        Ptr<MgByteSource> ldfsrc15 = new MgByteSource(L"../UnitTestFiles/UT_MultiCTS.ldf", false);
+        Ptr<MgByteReader> ldfrdr15 = ldfsrc15->GetReader();
+        m_svcResource->SetResource(ldfres15, ldfrdr15, NULL);
+
+        Ptr<MgResourceIdentifier> ldfres16 = new MgResourceIdentifier(L"Library://UnitTests/Layers/MultiFTSWithTheme.LayerDefinition");
+        Ptr<MgByteSource> ldfsrc16 = new MgByteSource(L"../UnitTestFiles/UT_MultiFTSWithTheme.ldf", false);
+        Ptr<MgByteReader> ldfrdr16 = ldfsrc16->GetReader();
+        m_svcResource->SetResource(ldfres16, ldfrdr16, NULL);
+
+        Ptr<MgResourceIdentifier> ldfres17 = new MgResourceIdentifier(L"Library://UnitTests/Layers/MultiCTSWithTheme.LayerDefinition");
+        Ptr<MgByteSource> ldfsrc17 = new MgByteSource(L"../UnitTestFiles/UT_MultiCTSWithTheme.ldf", false);
+        Ptr<MgByteReader> ldfrdr17 = ldfsrc17->GetReader();
+        m_svcResource->SetResource(ldfres17, ldfrdr17, NULL);
+
+        Ptr<MgResourceIdentifier> ldfres18 = new MgResourceIdentifier(L"Library://UnitTests/Layers/MultiFTSSingleCTS.LayerDefinition");
+        Ptr<MgByteSource> ldfsrc18 = new MgByteSource(L"../UnitTestFiles/UT_MultiFTSSingleCTS.ldf", false);
+        Ptr<MgByteReader> ldfrdr18 = ldfsrc18->GetReader();
+        m_svcResource->SetResource(ldfres18, ldfrdr18, NULL);
+
+        Ptr<MgResourceIdentifier> ldfres19 = new MgResourceIdentifier(L"Library://UnitTests/Layers/SingleFTSMultiCTS.LayerDefinition");
+        Ptr<MgByteSource> ldfsrc19 = new MgByteSource(L"../UnitTestFiles/UT_SingleFTSMultiCTS.ldf", false);
+        Ptr<MgByteReader> ldfrdr19 = ldfsrc19->GetReader();
+        m_svcResource->SetResource(ldfres19, ldfrdr19, NULL);
     }
     catch (MgException* e)
     {
@@ -440,6 +472,19 @@
         m_svcResource->DeleteResource(fsres6);
         Ptr<MgResourceIdentifier> fsres7 = new MgResourceIdentifier(L"Library://UnitTests/Data/VotingDistricts.FeatureSource");
         m_svcResource->DeleteResource(fsres7);
+
+        Ptr<MgResourceIdentifier> ldfres14 = new MgResourceIdentifier(L"Library://UnitTests/Layers/MultiFTS.LayerDefinition");
+        m_svcResource->DeleteResource(ldfres14);
+        Ptr<MgResourceIdentifier> ldfres15 = new MgResourceIdentifier(L"Library://UnitTests/Layers/MultiCTS.LayerDefinition");
+        m_svcResource->DeleteResource(ldfres15);
+        Ptr<MgResourceIdentifier> ldfres16 = new MgResourceIdentifier(L"Library://UnitTests/Layers/MultiFTSWithTheme.LayerDefinition");
+        m_svcResource->DeleteResource(ldfres16);
+        Ptr<MgResourceIdentifier> ldfres17 = new MgResourceIdentifier(L"Library://UnitTests/Layers/MultiCTSWithTheme.LayerDefinition");
+        m_svcResource->DeleteResource(ldfres17);
+        Ptr<MgResourceIdentifier> ldfres18 = new MgResourceIdentifier(L"Library://UnitTests/Layers/MultiFTSSingleCTS.LayerDefinition");
+        m_svcResource->DeleteResource(ldfres18);
+        Ptr<MgResourceIdentifier> ldfres19 = new MgResourceIdentifier(L"Library://UnitTests/Layers/SingleFTSMultiCTS.LayerDefinition");
+        m_svcResource->DeleteResource(ldfres19);
     }
     catch(MgFileIoException* e)
     {
@@ -627,34 +672,58 @@
         Ptr<MgLayerGroupCollection> layerGroups = map->GetLayerGroups();
         Ptr<MgLayerCollection> layers = map->GetLayers();
 
-        Ptr<MgResourceIdentifier> resId = new MgResourceIdentifier(L"Library://UnitTests/Layers/Parcels.LayerDefinition");
+        Ptr<MgResourceIdentifier> resId = new MgResourceIdentifier(L"Library://UnitTests/Layers/HydrographicPolygons.LayerDefinition");
+        Ptr<MgResourceIdentifier> ldfRail = new MgResourceIdentifier(L"Library://UnitTests/Layers/Rail.LayerDefinition");
 
-        Ptr<MgLayerGroup> group = new MgLayerGroup(L"Can't see me");
-        group->SetLegendLabel(L"Can't see me");
+        Ptr<MgLayerGroup> group = new MgLayerGroup(L"Test Group");
+        group->SetLegendLabel(L"Test Group");
         group->SetDisplayInLegend(true);
         layerGroups->Add(group);
 
+        Ptr<MgLayerGroup> group1 = new MgLayerGroup(L"Nest top level");
+        group1->SetLegendLabel(L"Nest top level");
+        group1->SetDisplayInLegend(true);
+        layerGroups->Add(group1);
+
+        Ptr<MgLayerGroup> group2 = new MgLayerGroup(L"Nest child");
+        group2->SetLegendLabel(L"Nest child (Nest top level)");
+        group2->SetDisplayInLegend(true);
+        group2->SetGroup(group1);
+        layerGroups->Add(group2);
+
+        Ptr<MgLayerGroup> group3 = new MgLayerGroup(L"Not visible in legend");
+        group3->SetLegendLabel(L"Not visible in legend");
+        group3->SetDisplayInLegend(false);
+        layerGroups->Add(group3);
+
         Ptr<MgdLayer> layer = new MgdLayer(resId, m_svcResource);
-        layer->SetName(L"MyParcels");
-        layer->SetLegendLabel(L"Parcels");
+        layer->SetName(L"HydroPolygons");
+        layer->SetLegendLabel(L"HydroPolygons (Test Group)");
         layer->SetGroup(group);
         layer->SetDisplayInLegend(true);
 
+        Ptr<MgdLayer> layer2 = new MgdLayer(ldfRail, m_svcResource);
+        layer2->SetName(L"RailUnderNestedGroup");
+        layer2->SetLegendLabel(L"Rail (Nest Child)");
+        layer2->SetGroup(group2);
+        layer2->SetDisplayInLegend(true);
+
         layers->Add(layer);
+        layers->Add(layer2);
 
         //Re-draw at 75k. Layer group should not be there because it has no visible layers
         map->SetViewScale(75000.0);
-		Ptr<MgByteReader> rdr3 = m_svcRendering->RenderMapLegend(map, 200, 400, bgc, imageFormat);
-		rdr3->ToFile(GetPath(L"../UnitTestFiles/RenderLegend75kWithEmptyLayerGroup", imageFormat, extension));
+        Ptr<MgByteReader> rdr3 = m_svcRendering->RenderMapLegend(map, 200, 400, bgc, imageFormat);
+        rdr3->ToFile(GetPath(L"../UnitTestFiles/RenderLegend75kWithEmptyLayerGroup", imageFormat, extension));
 
         //Re-draw at 14000. Layer group should still not be there because it has no visible layers
         map->SetViewScale(14000.0);
-		Ptr<MgByteReader> rdr4 = m_svcRendering->RenderMapLegend(map, 200, 400, bgc, imageFormat);
+        Ptr<MgByteReader> rdr4 = m_svcRendering->RenderMapLegend(map, 200, 400, bgc, imageFormat);
         rdr4->ToFile(GetPath(L"../UnitTestFiles/RenderLegend14kWithEmptyLayerGroup", imageFormat, extension));
 
         //Re-draw at 12000. Layer group should now be there because its child layer (Parcels) should be visible
         map->SetViewScale(12000.0);
-		Ptr<MgByteReader> rdr5 = m_svcRendering->RenderMapLegend(map, 200, 400, bgc, imageFormat);
+        Ptr<MgByteReader> rdr5 = m_svcRendering->RenderMapLegend(map, 200, 400, bgc, imageFormat);
         rdr5->ToFile(GetPath(L"../UnitTestFiles/RenderLegend12kWithLayerGroup", imageFormat, extension));
     }
     catch (MgException* e)
@@ -669,6 +738,263 @@
     }
 }
 
+void TestRenderingService::TestCase_RenderLegendEmptyGroups(CREFSTRING imageFormat, CREFSTRING extension)
+{
+    try
+    {
+        // make a runtime map
+        Ptr<MgdMap> map = CreateTestMap();
+        map->SetViewScale(75000.0);
+        Ptr<MgColor> bgc = new MgColor(255, 255, 255, 255);
+
+        // Set up the following structure
+        //
+        // EmptyGroup1
+        // EmptyGroup2
+        //    EmptyGroup3
+        //
+        // None of these should be visible when we render the legend
+
+        Ptr<MgLayerGroupCollection> groups = map->GetLayerGroups();
+        Ptr<MgLayerGroup> group1 = new MgLayerGroup(L"EmptyGroup1");
+        group1->SetLegendLabel(L"EmptyGroup1");
+        Ptr<MgLayerGroup> group2 = new MgLayerGroup(L"EmptyGroup2");
+        group2->SetLegendLabel(L"EmptyGroup2");
+        Ptr<MgLayerGroup> group3 = new MgLayerGroup(L"EmptyGroup3");
+        group3->SetLegendLabel(L"EmptyGroup3");
+
+        group1->SetDisplayInLegend(true);
+        group2->SetDisplayInLegend(true);
+        group3->SetDisplayInLegend(true);
+
+        groups->Add(group1);
+        groups->Add(group2);
+        groups->Add(group3);
+        group3->SetGroup(group2);
+
+        map->Save();
+
+        // Call the API
+        Ptr<MgByteReader> rdr3 = m_svcRendering->RenderMapLegend(map, 200, 400, bgc, imageFormat);
+        rdr3->ToFile(GetPath(L"../UnitTestFiles/RenderLegendEmptyGroups", imageFormat, extension));
+    }
+    catch (MgException* e)
+    {
+        STRING message = e->GetDetails(TEST_LOCALE);
+        SAFE_RELEASE(e);
+        CPPUNIT_FAIL(MG_WCHAR_TO_CHAR(message.c_str()));
+    }
+    catch (...)
+    {
+        throw;
+    }
+}
+
+void TestRenderingService::TestCase_RenderLegendMultiFTS(CREFSTRING imageFormat, CREFSTRING extension)
+{
+    try
+    {
+        // make a runtime map
+        Ptr<MgdMap> map = CreateTestMap();
+
+        // Insert our test layer
+        Ptr<MgResourceIdentifier> layerDef = new MgResourceIdentifier(L"Library://UnitTests/Layers/MultiFTS.LayerDefinition");
+        Ptr<MgdLayer> layer = new MgdLayer(layerDef, m_svcResource);
+        layer->SetLegendLabel(layerDef->GetName());
+        Ptr<MgLayerCollection> layers = map->GetLayers();
+        layers->Insert(0, layer);
+        map->Save();
+
+        // call the API using scales of 75000 and 12000
+        Ptr<MgColor> bgc = new MgColor(255, 255, 255, 255);
+
+        map->SetViewScale(75000.0);
+        Ptr<MgByteReader> rdr1 = m_svcRendering->RenderMapLegend(map, 200, 400, bgc, imageFormat);
+        rdr1->ToFile(GetPath(L"../UnitTestFiles/RenderLegendMultiFTS", imageFormat, extension));
+    }
+    catch (MgException* e)
+    {
+        STRING message = e->GetDetails(TEST_LOCALE);
+        SAFE_RELEASE(e);
+        CPPUNIT_FAIL(MG_WCHAR_TO_CHAR(message.c_str()));
+    }
+    catch (...)
+    {
+        throw;
+    }
+}
+
+void TestRenderingService::TestCase_RenderLegendMultiCTS(CREFSTRING imageFormat, CREFSTRING extension)
+{
+    try
+    {
+        // make a runtime map
+        Ptr<MgdMap> map = CreateTestMap();
+
+        // Insert our test layer
+        Ptr<MgResourceIdentifier> layerDef = new MgResourceIdentifier(L"Library://UnitTests/Layers/MultiCTS.LayerDefinition");
+        Ptr<MgdLayer> layer = new MgdLayer(layerDef, m_svcResource);
+        layer->SetLegendLabel(layerDef->GetName());
+        Ptr<MgLayerCollection> layers = map->GetLayers();
+        layers->Insert(0, layer);
+        map->Save();
+
+        // call the API using scales of 75000 and 12000
+        Ptr<MgColor> bgc = new MgColor(255, 255, 255, 255);
+
+        map->SetViewScale(75000.0);
+        Ptr<MgByteReader> rdr1 = m_svcRendering->RenderMapLegend(map, 200, 400, bgc, imageFormat);
+        rdr1->ToFile(GetPath(L"../UnitTestFiles/RenderLegendMultiCTS", imageFormat, extension));
+    }
+    catch (MgException* e)
+    {
+        STRING message = e->GetDetails(TEST_LOCALE);
+        SAFE_RELEASE(e);
+        CPPUNIT_FAIL(MG_WCHAR_TO_CHAR(message.c_str()));
+    }
+    catch (...)
+    {
+        throw;
+    }
+}
+
+void TestRenderingService::TestCase_RenderLegendMultiFTSWithTheme(CREFSTRING imageFormat, CREFSTRING extension)
+{
+    try
+    {
+        // make a runtime map
+        Ptr<MgdMap> map = CreateTestMap();
+
+        // Insert our test layer
+        Ptr<MgResourceIdentifier> layerDef = new MgResourceIdentifier(L"Library://UnitTests/Layers/MultiFTSWithTheme.LayerDefinition");
+        Ptr<MgdLayer> layer = new MgdLayer(layerDef, m_svcResource);
+        layer->SetLegendLabel(layerDef->GetName());
+        Ptr<MgLayerCollection> layers = map->GetLayers();
+        layers->Insert(0, layer);
+        map->Save();
+
+        // call the API using scales of 75000 and 12000
+        Ptr<MgColor> bgc = new MgColor(255, 255, 255, 255);
+
+        map->SetViewScale(75000.0);
+        Ptr<MgByteReader> rdr1 = m_svcRendering->RenderMapLegend(map, 200, 400, bgc, imageFormat);
+        rdr1->ToFile(GetPath(L"../UnitTestFiles/RenderLegendMultiFTSWithTheme", imageFormat, extension));
+    }
+    catch (MgException* e)
+    {
+        STRING message = e->GetDetails(TEST_LOCALE);
+        SAFE_RELEASE(e);
+        CPPUNIT_FAIL(MG_WCHAR_TO_CHAR(message.c_str()));
+    }
+    catch (...)
+    {
+        throw;
+    }
+}
+
+void TestRenderingService::TestCase_RenderLegendMultiCTSWithTheme(CREFSTRING imageFormat, CREFSTRING extension)
+{
+    try
+    {
+        // make a runtime map
+        Ptr<MgdMap> map = CreateTestMap();
+
+        // Insert our test layer
+        Ptr<MgResourceIdentifier> layerDef = new MgResourceIdentifier(L"Library://UnitTests/Layers/MultiCTSWithTheme.LayerDefinition");
+        Ptr<MgdLayer> layer = new MgdLayer(layerDef, m_svcResource);
+        layer->SetLegendLabel(layerDef->GetName());
+        Ptr<MgLayerCollection> layers = map->GetLayers();
+        layers->Insert(0, layer);
+        map->Save();
+
+        // call the API using scales of 75000 and 12000
+        Ptr<MgColor> bgc = new MgColor(255, 255, 255, 255);
+
+        map->SetViewScale(75000.0);
+        Ptr<MgByteReader> rdr1 = m_svcRendering->RenderMapLegend(map, 200, 400, bgc, imageFormat);
+        rdr1->ToFile(GetPath(L"../UnitTestFiles/RenderLegendMultiCTSWithTheme", imageFormat, extension));
+    }
+    catch (MgException* e)
+    {
+        STRING message = e->GetDetails(TEST_LOCALE);
+        SAFE_RELEASE(e);
+        CPPUNIT_FAIL(MG_WCHAR_TO_CHAR(message.c_str()));
+    }
+    catch (...)
+    {
+        throw;
+    }
+}
+
+void TestRenderingService::TestCase_RenderLegendMultiFTSSingleCTS(CREFSTRING imageFormat, CREFSTRING extension)
+{
+    try
+    {
+        // make a runtime map
+        Ptr<MgdMap> map = CreateTestMap();
+
+        // Insert our test layer
+        Ptr<MgResourceIdentifier> layerDef = new MgResourceIdentifier(L"Library://UnitTests/Layers/MultiFTSSingleCTS.LayerDefinition");
+        Ptr<MgdLayer> layer = new MgdLayer(layerDef, m_svcResource);
+        layer->SetLegendLabel(layerDef->GetName());
+        Ptr<MgLayerCollection> layers = map->GetLayers();
+        layers->Insert(0, layer);
+        map->Save();
+
+        // call the API using scales of 75000 and 12000
+        Ptr<MgColor> bgc = new MgColor(255, 255, 255, 255);
+
+        map->SetViewScale(75000.0);
+        Ptr<MgByteReader> rdr1 = m_svcRendering->RenderMapLegend(map, 200, 400, bgc, imageFormat);
+        rdr1->ToFile(GetPath(L"../UnitTestFiles/RenderLegendMultiFTSSingleCTS", imageFormat, extension));
+    }
+    catch (MgException* e)
+    {
+        STRING message = e->GetDetails(TEST_LOCALE);
+        SAFE_RELEASE(e);
+        CPPUNIT_FAIL(MG_WCHAR_TO_CHAR(message.c_str()));
+    }
+    catch (...)
+    {
+        throw;
+    }
+}
+
+
+void TestRenderingService::TestCase_RenderLegendSingleFTSMultiCTS(CREFSTRING imageFormat, CREFSTRING extension)
+{
+    try
+    {
+        // make a runtime map
+        Ptr<MgdMap> map = CreateTestMap();
+
+        // Insert our test layer
+        Ptr<MgResourceIdentifier> layerDef = new MgResourceIdentifier(L"Library://UnitTests/Layers/SingleFTSMultiCTS.LayerDefinition");
+        Ptr<MgdLayer> layer = new MgdLayer(layerDef, m_svcResource);
+        layer->SetLegendLabel(layerDef->GetName());
+        Ptr<MgLayerCollection> layers = map->GetLayers();
+        layers->Insert(0, layer);
+        map->Save();
+
+        // call the API using scales of 75000 and 12000
+        Ptr<MgColor> bgc = new MgColor(255, 255, 255, 255);
+
+        map->SetViewScale(75000.0);
+        Ptr<MgByteReader> rdr1 = m_svcRendering->RenderMapLegend(map, 200, 400, bgc, imageFormat);
+        rdr1->ToFile(GetPath(L"../UnitTestFiles/RenderLegendSingleFTSMultiCTS", imageFormat, extension));
+    }
+    catch (MgException* e)
+    {
+        STRING message = e->GetDetails(TEST_LOCALE);
+        SAFE_RELEASE(e);
+        CPPUNIT_FAIL(MG_WCHAR_TO_CHAR(message.c_str()));
+    }
+    catch (...)
+    {
+        throw;
+    }
+}
+
 void TestRenderingService::TestCase_QueryFeatures()
 {
     try

Modified: branches/2.5/MgDev/Desktop/UnitTest/TestRenderingService.h
===================================================================
--- branches/2.5/MgDev/Desktop/UnitTest/TestRenderingService.h	2013-12-01 16:54:17 UTC (rev 7944)
+++ branches/2.5/MgDev/Desktop/UnitTest/TestRenderingService.h	2013-12-01 17:39:38 UTC (rev 7945)
@@ -40,6 +40,13 @@
     CPPUNIT_TEST(TestCase_RenderMapPNG);
     CPPUNIT_TEST(TestCase_RenderMapWithWatermarkPNG);
     CPPUNIT_TEST(TestCase_RenderLegendPNG);
+    CPPUNIT_TEST(TestCase_RenderLegendEmptyGroupsPNG);
+    CPPUNIT_TEST(TestCase_RenderLegendMultiFTSPNG);
+    CPPUNIT_TEST(TestCase_RenderLegendMultiCTSPNG);
+    CPPUNIT_TEST(TestCase_RenderLegendMultiFTSWithThemePNG);
+    CPPUNIT_TEST(TestCase_RenderLegendMultiCTSWithThemePNG);
+    CPPUNIT_TEST(TestCase_RenderLegendMultiFTSSingleCTSPNG);
+    CPPUNIT_TEST(TestCase_RenderLegendSingleFTSMultiCTSPNG);
 
 	CPPUNIT_TEST(TestCase_SymbologyPointsPNG8);
     CPPUNIT_TEST(TestCase_SymbologyPointsParamPNG8);
@@ -56,6 +63,13 @@
     CPPUNIT_TEST(TestCase_RenderMapPNG8);
     CPPUNIT_TEST(TestCase_RenderMapWithWatermarkPNG8);
     CPPUNIT_TEST(TestCase_RenderLegendPNG8);
+    CPPUNIT_TEST(TestCase_RenderLegendEmptyGroupsPNG8);
+    CPPUNIT_TEST(TestCase_RenderLegendMultiFTSPNG8);
+    CPPUNIT_TEST(TestCase_RenderLegendMultiCTSPNG8);
+    CPPUNIT_TEST(TestCase_RenderLegendMultiFTSWithThemePNG8);
+    CPPUNIT_TEST(TestCase_RenderLegendMultiCTSWithThemePNG8);
+    CPPUNIT_TEST(TestCase_RenderLegendMultiFTSSingleCTSPNG8);
+    CPPUNIT_TEST(TestCase_RenderLegendSingleFTSMultiCTSPNG8);
 
 	CPPUNIT_TEST(TestCase_SymbologyPointsGIF);
     CPPUNIT_TEST(TestCase_SymbologyPointsParamGIF);
@@ -72,6 +86,13 @@
     CPPUNIT_TEST(TestCase_RenderMapGIF);
     CPPUNIT_TEST(TestCase_RenderMapWithWatermarkGIF);
     CPPUNIT_TEST(TestCase_RenderLegendGIF);
+    CPPUNIT_TEST(TestCase_RenderLegendEmptyGroupsGIF);
+    CPPUNIT_TEST(TestCase_RenderLegendMultiFTSGIF);
+    CPPUNIT_TEST(TestCase_RenderLegendMultiCTSGIF);
+    CPPUNIT_TEST(TestCase_RenderLegendMultiFTSWithThemeGIF);
+    CPPUNIT_TEST(TestCase_RenderLegendMultiCTSWithThemeGIF);
+    CPPUNIT_TEST(TestCase_RenderLegendMultiFTSSingleCTSGIF);
+    CPPUNIT_TEST(TestCase_RenderLegendSingleFTSMultiCTSGIF);
 
 	CPPUNIT_TEST(TestCase_SymbologyPointsJPG);
     CPPUNIT_TEST(TestCase_SymbologyPointsParamJPG);
@@ -88,6 +109,13 @@
     CPPUNIT_TEST(TestCase_RenderMapJPG);
     CPPUNIT_TEST(TestCase_RenderMapWithWatermarkJPG);
     CPPUNIT_TEST(TestCase_RenderLegendJPG);
+    CPPUNIT_TEST(TestCase_RenderLegendEmptyGroupsJPG);
+    CPPUNIT_TEST(TestCase_RenderLegendMultiFTSJPG);
+    CPPUNIT_TEST(TestCase_RenderLegendMultiCTSJPG);
+    CPPUNIT_TEST(TestCase_RenderLegendMultiFTSWithThemeJPG);
+    CPPUNIT_TEST(TestCase_RenderLegendMultiCTSWithThemeJPG);
+    CPPUNIT_TEST(TestCase_RenderLegendMultiFTSSingleCTSJPG);
+    CPPUNIT_TEST(TestCase_RenderLegendSingleFTSMultiCTSJPG);
 
     CPPUNIT_TEST(TestCase_QueryFeatures);
 
@@ -105,12 +133,21 @@
     void TestStart();
     void TestEnd();
 
+    void TestCase_QueryFeatures();
+
     //Parameterized versions that all format-specific tests call into
     void TestCase_RenderDynamicOverlay(CREFSTRING imageFormat, CREFSTRING extension);
     void TestCase_RenderDynamicOverlayTiledMap(CREFSTRING imageFormat, CREFSTRING extension);
     void TestCase_RenderMap(CREFSTRING imageFormat, CREFSTRING extension);
     void TestCase_RenderMapWithWatermark(CREFSTRING imageFormat, CREFSTRING extension);
     void TestCase_RenderLegend(CREFSTRING imageFormat, CREFSTRING extension);
+    void TestCase_RenderLegendEmptyGroups(CREFSTRING imageFormat, CREFSTRING extension);
+    void TestCase_RenderLegendMultiFTS(CREFSTRING imageFormat, CREFSTRING extension);
+    void TestCase_RenderLegendMultiCTS(CREFSTRING imageFormat, CREFSTRING extension);
+    void TestCase_RenderLegendMultiFTSWithTheme(CREFSTRING imageFormat, CREFSTRING extension);
+    void TestCase_RenderLegendMultiCTSWithTheme(CREFSTRING imageFormat, CREFSTRING extension);
+    void TestCase_RenderLegendMultiFTSSingleCTS(CREFSTRING imageFormat, CREFSTRING extension);
+    void TestCase_RenderLegendSingleFTSMultiCTS(CREFSTRING imageFormat, CREFSTRING extension);
     
     void TestCase_SymbologyPoints(CREFSTRING imageFormat, CREFSTRING extension);
     void TestCase_SymbologyPointsParam(CREFSTRING imageFormat, CREFSTRING extension);
@@ -122,12 +159,13 @@
     void TestCase_Annotation2(CREFSTRING imageFormat, CREFSTRING extension);
     void TestCase_Annotation3(CREFSTRING imageFormat, CREFSTRING extension);
 
-	//PNG output tests
-	void TestCase_RenderDynamicOverlayPNG() { TestCase_RenderDynamicOverlay(L"PNG", L"png"); }
+    //PNG output tests
+    void TestCase_RenderDynamicOverlayPNG() { TestCase_RenderDynamicOverlay(L"PNG", L"png"); }
     void TestCase_RenderDynamicOverlayTiledMapPNG() { TestCase_RenderDynamicOverlayTiledMap(L"PNG", L"png"); }
     void TestCase_RenderMapPNG() { TestCase_RenderMap(L"PNG", L"png"); }
     void TestCase_RenderMapWithWatermarkPNG() { TestCase_RenderMapWithWatermark(L"PNG", L"png"); }
     void TestCase_RenderLegendPNG() { TestCase_RenderLegend(L"PNG", L"png"); }
+    void TestCase_RenderLegendEmptyGroupsPNG() { TestCase_RenderLegendEmptyGroups(L"PNG", L"png"); }
     void TestCase_SymbologyPointsPNG() { TestCase_SymbologyPoints(L"PNG", L"png"); }
     void TestCase_SymbologyPointsParamPNG() { TestCase_SymbologyPointsParam(L"PNG", L"png"); }
     void TestCase_SymbologyLinesPNG() { TestCase_SymbologyLines(L"PNG", L"png"); }
@@ -136,13 +174,20 @@
     void TestCase_Annotation1PNG() { TestCase_Annotation1(L"PNG", L"png"); }
     void TestCase_Annotation2PNG() { TestCase_Annotation2(L"PNG", L"png"); }
     void TestCase_Annotation3PNG() { TestCase_Annotation3(L"PNG", L"png"); }
+    void TestCase_RenderLegendMultiFTSPNG() { TestCase_RenderLegendMultiFTS(L"PNG", L"png"); }
+    void TestCase_RenderLegendMultiCTSPNG() { TestCase_RenderLegendMultiCTS(L"PNG", L"png"); }
+    void TestCase_RenderLegendMultiFTSWithThemePNG() { TestCase_RenderLegendMultiFTSWithTheme(L"PNG", L"png"); }
+    void TestCase_RenderLegendMultiCTSWithThemePNG() { TestCase_RenderLegendMultiCTSWithTheme(L"PNG", L"png"); }
+    void TestCase_RenderLegendMultiFTSSingleCTSPNG() { TestCase_RenderLegendMultiFTSSingleCTS(L"PNG", L"png"); }
+    void TestCase_RenderLegendSingleFTSMultiCTSPNG() { TestCase_RenderLegendSingleFTSMultiCTS(L"PNG", L"png"); }
 
-	//PNG8 output tests
-	void TestCase_RenderDynamicOverlayPNG8() { TestCase_RenderDynamicOverlay(L"PNG8", L"png"); }
+    //PNG8 output tests
+    void TestCase_RenderDynamicOverlayPNG8() { TestCase_RenderDynamicOverlay(L"PNG8", L"png"); }
     void TestCase_RenderDynamicOverlayTiledMapPNG8() { TestCase_RenderDynamicOverlayTiledMap(L"PNG8", L"png"); }
     void TestCase_RenderMapPNG8() { TestCase_RenderMap(L"PNG8", L"png"); }
     void TestCase_RenderMapWithWatermarkPNG8() { TestCase_RenderMapWithWatermark(L"PNG8", L"png"); }
     void TestCase_RenderLegendPNG8() { TestCase_RenderLegend(L"PNG8", L"png"); }
+    void TestCase_RenderLegendEmptyGroupsPNG8() { TestCase_RenderLegendEmptyGroups(L"PNG8", L"png"); }
     void TestCase_SymbologyPointsPNG8() { TestCase_SymbologyPoints(L"PNG8", L"png"); }
     void TestCase_SymbologyPointsParamPNG8() { TestCase_SymbologyPointsParam(L"PNG8", L"png"); }
     void TestCase_SymbologyLinesPNG8() { TestCase_SymbologyLines(L"PNG8", L"png"); }
@@ -151,13 +196,20 @@
     void TestCase_Annotation1PNG8() { TestCase_Annotation1(L"PNG8", L"png"); }
     void TestCase_Annotation2PNG8() { TestCase_Annotation2(L"PNG8", L"png"); }
     void TestCase_Annotation3PNG8() { TestCase_Annotation3(L"PNG8", L"png"); }
+    void TestCase_RenderLegendMultiFTSPNG8() { TestCase_RenderLegendMultiFTS(L"PNG8", L"png"); }
+    void TestCase_RenderLegendMultiCTSPNG8() { TestCase_RenderLegendMultiCTS(L"PNG8", L"png"); }
+    void TestCase_RenderLegendMultiFTSWithThemePNG8() { TestCase_RenderLegendMultiFTSWithTheme(L"PNG8", L"png"); }
+    void TestCase_RenderLegendMultiCTSWithThemePNG8() { TestCase_RenderLegendMultiCTSWithTheme(L"PNG8", L"png"); }
+    void TestCase_RenderLegendMultiFTSSingleCTSPNG8() { TestCase_RenderLegendMultiFTSSingleCTS(L"PNG8", L"png"); }
+    void TestCase_RenderLegendSingleFTSMultiCTSPNG8() { TestCase_RenderLegendSingleFTSMultiCTS(L"PNG8", L"png"); }
 
-	//GIF output tests
-	void TestCase_RenderDynamicOverlayGIF() { TestCase_RenderDynamicOverlay(L"GIF", L"gif"); }
+    //GIF output tests
+    void TestCase_RenderDynamicOverlayGIF() { TestCase_RenderDynamicOverlay(L"GIF", L"gif"); }
     void TestCase_RenderDynamicOverlayTiledMapGIF() { TestCase_RenderDynamicOverlayTiledMap(L"GIF", L"gif"); }
     void TestCase_RenderMapGIF() { TestCase_RenderMap(L"GIF", L"gif"); }
     void TestCase_RenderMapWithWatermarkGIF() { TestCase_RenderMapWithWatermark(L"GIF", L"gif"); }
     void TestCase_RenderLegendGIF() { TestCase_RenderLegend(L"GIF", L"gif"); }
+    void TestCase_RenderLegendEmptyGroupsGIF() { TestCase_RenderLegendEmptyGroups(L"GIF", L"gif"); }
     void TestCase_SymbologyPointsGIF() { TestCase_SymbologyPoints(L"GIF", L"gif"); }
     void TestCase_SymbologyPointsParamGIF() { TestCase_SymbologyPointsParam(L"GIF", L"gif"); }
     void TestCase_SymbologyLinesGIF() { TestCase_SymbologyLines(L"GIF", L"gif"); }
@@ -166,13 +218,20 @@
     void TestCase_Annotation1GIF() { TestCase_Annotation1(L"GIF", L"gif"); }
     void TestCase_Annotation2GIF() { TestCase_Annotation2(L"GIF", L"gif"); }
     void TestCase_Annotation3GIF() { TestCase_Annotation3(L"GIF", L"gif"); }
+    void TestCase_RenderLegendMultiFTSGIF() { TestCase_RenderLegendMultiFTS(L"GIF", L"gif"); }
+    void TestCase_RenderLegendMultiCTSGIF() { TestCase_RenderLegendMultiCTS(L"GIF", L"gif"); }
+    void TestCase_RenderLegendMultiFTSWithThemeGIF() { TestCase_RenderLegendMultiFTSWithTheme(L"GIF", L"gif"); }
+    void TestCase_RenderLegendMultiCTSWithThemeGIF() { TestCase_RenderLegendMultiCTSWithTheme(L"GIF", L"gif"); }
+    void TestCase_RenderLegendMultiFTSSingleCTSGIF() { TestCase_RenderLegendMultiFTSSingleCTS(L"GIF", L"gif"); }
+    void TestCase_RenderLegendSingleFTSMultiCTSGIF() { TestCase_RenderLegendSingleFTSMultiCTS(L"GIF", L"gif"); }
 
-	//JPG output tests
-	void TestCase_RenderDynamicOverlayJPG() { TestCase_RenderDynamicOverlay(L"JPG", L"jpg"); }
+    //JPG output tests
+    void TestCase_RenderDynamicOverlayJPG() { TestCase_RenderDynamicOverlay(L"JPG", L"jpg"); }
     void TestCase_RenderDynamicOverlayTiledMapJPG() { TestCase_RenderDynamicOverlayTiledMap(L"JPG", L"jpg"); }
     void TestCase_RenderMapJPG() { TestCase_RenderMap(L"JPG", L"jpg"); }
     void TestCase_RenderMapWithWatermarkJPG() { TestCase_RenderMapWithWatermark(L"JPG", L"jpg"); }
     void TestCase_RenderLegendJPG() { TestCase_RenderLegend(L"JPG", L"jpg"); }
+    void TestCase_RenderLegendEmptyGroupsJPG() { TestCase_RenderLegendEmptyGroups(L"JPG", L"jpg"); }
     void TestCase_SymbologyPointsJPG() { TestCase_SymbologyPoints(L"JPG", L"jpg"); }
     void TestCase_SymbologyPointsParamJPG() { TestCase_SymbologyPointsParam(L"JPG", L"jpg"); }
     void TestCase_SymbologyLinesJPG() { TestCase_SymbologyLines(L"JPG", L"jpg"); }
@@ -181,9 +240,13 @@
     void TestCase_Annotation1JPG() { TestCase_Annotation1(L"JPG", L"jpg"); }
     void TestCase_Annotation2JPG() { TestCase_Annotation2(L"JPG", L"jpg"); }
     void TestCase_Annotation3JPG() { TestCase_Annotation3(L"JPG", L"jpg"); }
+    void TestCase_RenderLegendMultiFTSJPG() { TestCase_RenderLegendMultiFTS(L"JPG", L"jpg"); }
+    void TestCase_RenderLegendMultiCTSJPG() { TestCase_RenderLegendMultiCTS(L"JPG", L"jpg"); }
+    void TestCase_RenderLegendMultiFTSWithThemeJPG() { TestCase_RenderLegendMultiFTSWithTheme(L"JPG", L"jpg"); }
+    void TestCase_RenderLegendMultiCTSWithThemeJPG() { TestCase_RenderLegendMultiCTSWithTheme(L"JPG", L"jpg"); }
+    void TestCase_RenderLegendMultiFTSSingleCTSJPG() { TestCase_RenderLegendMultiFTSSingleCTS(L"JPG", L"jpg"); }
+    void TestCase_RenderLegendSingleFTSMultiCTSJPG() { TestCase_RenderLegendSingleFTSMultiCTS(L"JPG", L"jpg"); }
 
-    void TestCase_QueryFeatures();
-
     //void TestCase_RendererPerformance();
 
 private:



More information about the mapguide-commits mailing list