[mapguide-commits] r6947 - branches/2.4/MgDev/Desktop/MapViewer

svn_mapguide at osgeo.org svn_mapguide at osgeo.org
Tue Aug 21 10:33:07 PDT 2012


Author: jng
Date: 2012-08-21 10:33:07 -0700 (Tue, 21 Aug 2012)
New Revision: 6947

Modified:
   branches/2.4/MgDev/Desktop/MapViewer/MgLegend.cs
   branches/2.4/MgDev/Desktop/MapViewer/MgLegendControlPresenter.cs
Log:
#2096: Improve MgLegend performance:
 - Lazy load layer definition content on-demand instead of all on the spot. Should be readily apparent with really large maps for the first load.
 - Cache the icons that are generated for subsequent rebuilds of the underlying TreeView
 - For subsequent rebuilds of the underlying TreeView, create nodes off of existing cached metadata where possible instead of going for direct resource content seek and calls to GenerateLegendImage
 - Instead of having various dictionaries storing various layer and group data, extend the Layer and Group node metadata classes to store this information where applicable. Add a new metadata class for theme information

Modified: branches/2.4/MgDev/Desktop/MapViewer/MgLegend.cs
===================================================================
--- branches/2.4/MgDev/Desktop/MapViewer/MgLegend.cs	2012-08-21 14:54:08 UTC (rev 6946)
+++ branches/2.4/MgDev/Desktop/MapViewer/MgLegend.cs	2012-08-21 17:33:07 UTC (rev 6947)
@@ -89,13 +89,14 @@
                 if (node.Nodes.Count > 0)
                     ClearNodes(node.Nodes);
 
+                /*
                 var layerMeta = node.Tag as LayerNodeMetadata;
                 if (layerMeta != null && layerMeta.ThemeIcon != null)
                 {
                     layerMeta.Layer = null;
                     layerMeta.ThemeIcon.Dispose();
                     layerMeta.ThemeIcon = null;
-                }
+                }*/
             }
             nodes.Clear();
         }
@@ -139,14 +140,14 @@
             if (e.Node.Tag == null)
                 return;
 
-            if (((LegendNodeMetadata)e.Node.Tag).IsGroup) //Group
+            var meta = ((LegendNodeMetadata)e.Node.Tag);
+            if (meta.IsGroup) //Group
             {
-                _presenter.SetGroupVisible(e.Node.Name, e.Node.Checked);
+                _presenter.SetGroupVisible(meta.ObjectId, e.Node.Checked);
             }
             else //Layer
             {
-                
-                _presenter.SetLayerVisible(e.Node.Name, e.Node.Checked);
+                _presenter.SetLayerVisible(meta.ObjectId, e.Node.Checked);
             }
         }
 
@@ -155,13 +156,14 @@
             if (e.Node.Tag == null)
                 return;
 
-            if (((LegendNodeMetadata)e.Node.Tag).IsGroup) //Group
+            var meta = ((LegendNodeMetadata)e.Node.Tag);
+            if (meta.IsGroup) //Group
             {
-                _presenter.SetGroupExpandInLegend(e.Node.Name, true);
+                _presenter.SetGroupExpandInLegend(meta.ObjectId, true);
             }
             else //Layer
             {
-                _presenter.SetLayerExpandInLegend(e.Node.Name, true);
+                _presenter.SetLayerExpandInLegend(meta.ObjectId, true);
             }
         }
 
@@ -170,13 +172,14 @@
             if (e.Node.Tag == null)
                 return;
 
-            if (((LegendNodeMetadata)e.Node.Tag).IsGroup) //Group
+            var meta = ((LegendNodeMetadata)e.Node.Tag);
+            if (meta.IsGroup) //Group
             {
-                _presenter.SetGroupExpandInLegend(e.Node.Name, false);
+                _presenter.SetGroupExpandInLegend(meta.ObjectId, false);
             }
             else //Layer
             {
-                _presenter.SetLayerExpandInLegend(e.Node.Name, false);
+                _presenter.SetLayerExpandInLegend(meta.ObjectId, false);
             }
         }
 
@@ -269,7 +272,7 @@
             get { return _themeCompressionLimit; }
             set { _themeCompressionLimit = value; }
         }
-
+        
         private void OnLayerContextMenuOpening(object sender, CancelEventArgs e)
         {
 

Modified: branches/2.4/MgDev/Desktop/MapViewer/MgLegendControlPresenter.cs
===================================================================
--- branches/2.4/MgDev/Desktop/MapViewer/MgLegendControlPresenter.cs	2012-08-21 14:54:08 UTC (rev 6946)
+++ branches/2.4/MgDev/Desktop/MapViewer/MgLegendControlPresenter.cs	2012-08-21 17:33:07 UTC (rev 6947)
@@ -10,6 +10,7 @@
     using Legend.Model;
     using System.Xml;
     using System.IO;
+using System.Diagnostics;
 
     interface ILegendView
     {
@@ -40,11 +41,8 @@
 
         private ILegendView _legend;
 
-        //TODO: Coalesce this all into a single object. ie. Merge into the respective metadata classes.
-        private Dictionary<string, bool> _initialLayerSelectabilityState = new Dictionary<string, bool>();
-        private Dictionary<string, MgLayerBase> _layers = new Dictionary<string, MgLayerBase>();
-        private Dictionary<string, MgLayerGroup> _groups = new Dictionary<string, MgLayerGroup>();
-        private Dictionary<string, string> _layerDefinitionContents = new Dictionary<string, string>();
+        private Dictionary<string, LayerNodeMetadata> _layers = new Dictionary<string, LayerNodeMetadata>();
+        private Dictionary<string, GroupNodeMetadata> _groups = new Dictionary<string, GroupNodeMetadata>();
 
         public MgLegendControlPresenter(ILegendView legend, MgMapViewerProvider provider)
         {
@@ -61,12 +59,12 @@
         {
             if (_map != null)
             {
-                _initialLayerSelectabilityState.Clear();
+                _layers.Clear();
                 var layers = _map.GetLayers();
                 for (int i = 0; i < layers.GetCount(); i++)
                 {
                     var layer = layers.GetItem(i);
-                    _initialLayerSelectabilityState[layer.GetObjectId()] = layer.Selectable;
+                    _layers[layer.GetObjectId()] = new LayerNodeMetadata(layer, layer.Selectable);
                 }
             }
         }
@@ -98,26 +96,43 @@
             var lt = layer.GetLayerType();
             var fsId = layer.GetFeatureSourceId();
 
+            LayerNodeMetadata layerMeta = null;
             if (fsId.EndsWith("DrawingSource"))
             {
                 node.SelectedImageKey = node.ImageKey = IMG_DWF;
-                //If not in the dictionary, assume it is a dynamically added layer
-                bool bInitiallySelectable = _initialLayerSelectabilityState.ContainsKey(layer.GetObjectId()) ? _initialLayerSelectabilityState[layer.GetObjectId()] : layer.Selectable;
-                node.Tag = new LayerNodeMetadata(layer, bInitiallySelectable);
+                bool bInitiallySelectable = layer.Selectable;
+                if (_layers.ContainsKey(layer.GetObjectId()))
+                {
+                    layerMeta = _layers[layer.GetObjectId()];
+                    bInitiallySelectable = layerMeta.WasInitiallySelectable;
+                }
+                else //If not in the dictionary, assume it is a dynamically added layer
+                {
+                    layerMeta = new LayerNodeMetadata(layer, bInitiallySelectable);
+                    _layers[layer.GetObjectId()] = layerMeta;
+                }
+                node.Tag = layerMeta;
                 node.ToolTipText = string.Format(Properties.Resources.DrawingLayerTooltip, Environment.NewLine, layer.Name, layer.FeatureSourceId);
             }
             else
             {
-                string layerData = null;
                 var ldfId = layer.LayerDefinition;
-                if (_layerDefinitionContents.ContainsKey(ldfId.ToString()))
-                    layerData = _layerDefinitionContents[ldfId.ToString()];
-
-                if (layerData == null)
+                if (_layers.ContainsKey(layer.GetObjectId()))
+                {
+                    layerMeta = _layers[layer.GetObjectId()];
+                }
+                else
+                {
+                    layerMeta = new LayerNodeMetadata(layer, layer.Selectable);
+                    _layers[layer.GetObjectId()] = layerMeta;
+                }
+                if (string.IsNullOrEmpty(layerMeta.LayerDefinitionContent))
                     return null;
 
+                node.Tag = layerMeta;
+
                 XmlDocument doc = new XmlDocument();
-                doc.LoadXml(layerData);
+                doc.LoadXml(layerMeta.LayerDefinitionContent);
                 int type = 0;
                 XmlNodeList scaleRanges = doc.GetElementsByTagName("VectorScaleRange");
                 if (scaleRanges.Count == 0)
@@ -139,111 +154,116 @@
 
                 try
                 {
-                    MgByteReader layerIcon = _provider.GenerateLegendImage(layer.LayerDefinition,
-                                                                            _map.ViewScale,
-                                                                            16,
-                                                                            16,
-                                                                            "PNG",
-                                                                            -1,
-                                                                            -1);
-                    if (layerIcon != null)
+                    if (layerMeta.Icon == null)
                     {
-                        try
+                        MgByteReader layerIcon = _provider.GenerateLegendImage(layer.LayerDefinition,
+                                                                                _map.ViewScale,
+                                                                                16,
+                                                                                16,
+                                                                                "PNG",
+                                                                                -1,
+                                                                                -1);
+                        legendCallCount++;
+                        if (layerIcon != null)
                         {
-                            byte[] b = new byte[layerIcon.GetLength()];
-                            layerIcon.Read(b, b.Length);
-                            using (var ms = new MemoryStream(b))
+                            try
                             {
-                                string id = Guid.NewGuid().ToString();
-                                Image img = Image.FromStream(ms);
-
-                                _legend.AddLegendIcon(id, img);
-                                node.SelectedImageKey = node.ImageKey = id;
-                                //If not in the dictionary, assume it is a dynamically added layer
-                                bool bInitiallySelectable = _initialLayerSelectabilityState.ContainsKey(layer.GetObjectId()) ? _initialLayerSelectabilityState[layer.GetObjectId()] : layer.Selectable;
-                                node.Tag = new LayerNodeMetadata(layer, bInitiallySelectable)
+                                byte[] b = new byte[layerIcon.GetLength()];
+                                layerIcon.Read(b, b.Length);
+                                using (var ms = new MemoryStream(b))
                                 {
-                                    ThemeIcon = img
-                                };
-                                node.ToolTipText = string.Format(Properties.Resources.DefaultLayerTooltip, Environment.NewLine, layer.Name, layer.FeatureSourceId, layer.FeatureClassName);
+                                    layerMeta.Icon = Image.FromStream(ms);
+                                    node.ToolTipText = string.Format(Properties.Resources.DefaultLayerTooltip, Environment.NewLine, layer.Name, layer.FeatureSourceId, layer.FeatureClassName);
+                                }
                             }
+                            finally
+                            {
+                                layerIcon.Dispose();
+                            }
                         }
-                        finally
+                        else
                         {
-                            layerIcon.Dispose();
+                            layerMeta.Icon = Properties.Resources.lc_broken;
                         }
                     }
-                    else
-                    {
-                        node.SelectedImageKey = node.ImageKey = IMG_BROKEN;
-                    }
                 }
                 catch
                 {
-                    node.SelectedImageKey = node.ImageKey = IMG_BROKEN;
+                    layerMeta.Icon = Properties.Resources.lc_broken;
                 }
 
-                for (int sc = 0; sc < scaleRanges.Count; sc++)
+                if (!layerMeta.HasTheme())
                 {
-                    XmlElement scaleRange = (XmlElement)scaleRanges[sc];
-                    XmlNodeList minElt = scaleRange.GetElementsByTagName("MinScale");
-                    XmlNodeList maxElt = scaleRange.GetElementsByTagName("MaxScale");
-                    String minScale, maxScale;
-                    minScale = "0";
-                    maxScale = "1000000000000.0";   // as MDF's VectorScaleRange::MAX_MAP_SCALE
-                    if (minElt.Count > 0)
-                        minScale = minElt[0].ChildNodes[0].Value;
-                    if (maxElt.Count > 0)
-                        maxScale = maxElt[0].ChildNodes[0].Value;
+                    for (int sc = 0; sc < scaleRanges.Count; sc++)
+                    {
+                        XmlElement scaleRange = (XmlElement)scaleRanges[sc];
+                        XmlNodeList minElt = scaleRange.GetElementsByTagName("MinScale");
+                        XmlNodeList maxElt = scaleRange.GetElementsByTagName("MaxScale");
+                        String minScale, maxScale;
+                        minScale = "0";
+                        maxScale = "1000000000000.0";   // as MDF's VectorScaleRange::MAX_MAP_SCALE
+                        if (minElt.Count > 0)
+                            minScale = minElt[0].ChildNodes[0].Value;
+                        if (maxElt.Count > 0)
+                            maxScale = maxElt[0].ChildNodes[0].Value;
 
-                    if (type != 0)
-                        break;
+                        if (type != 0)
+                            break;
 
-                    for (int geomType = 0; geomType < typeStyles.Length; geomType++)
-                    {
-                        int catIndex = 0;
-                        XmlNodeList typeStyle = scaleRange.GetElementsByTagName(typeStyles[geomType]);
-                        for (int st = 0; st < typeStyle.Count; st++)
+                        for (int geomType = 0; geomType < typeStyles.Length; geomType++)
                         {
-                            // We will check if this typestyle is going to be shown in the legend
-                            XmlNodeList showInLegend = ((XmlElement)typeStyle[st]).GetElementsByTagName("ShowInLegend");
-                            if (showInLegend.Count > 0)
-                                if (!bool.Parse(showInLegend[0].ChildNodes[0].Value))
-                                    continue;   // This typestyle does not need to be shown in the legend
+                            ThemeCategory themeCat = new ThemeCategory()
+                            {
+                                MinScale = minScale,
+                                MaxScale = maxScale,
+                                GeometryType = geomType
+                            };
 
-                            XmlNodeList rules = ((XmlElement)typeStyle[st]).GetElementsByTagName(ruleNames[geomType]);
-                            if (rules.Count > 1)
+                            int catIndex = 0;
+                            XmlNodeList typeStyle = scaleRange.GetElementsByTagName(typeStyles[geomType]);
+                            for (int st = 0; st < typeStyle.Count; st++)
                             {
-                                node.SelectedImageKey = node.ImageKey = IMG_THEME;
-                                var layerMeta = node.Tag as LayerNodeMetadata;
-                                if (layerMeta != null)
+                                // We will check if this typestyle is going to be shown in the legend
+                                XmlNodeList showInLegend = ((XmlElement)typeStyle[st]).GetElementsByTagName("ShowInLegend");
+                                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)
                                 {
-                                    layerMeta.ThemeIcon = Properties.Resources.lc_theme;
+                                    layerMeta.Icon = Properties.Resources.lc_theme;
                                     node.ToolTipText = string.Format(Properties.Resources.ThemedLayerTooltip, Environment.NewLine, layer.Name, layer.FeatureSourceId, layer.FeatureClassName, rules.Count);
-                                }
-                                if (_legend.ThemeCompressionLimit > 0 && rules.Count > _legend.ThemeCompressionLimit)
-                                {
-                                    AddThemeRuleNode(layer, node, geomType, 0, rules, 0);
-                                    node.Nodes.Add(CreateCompressedThemeNode(rules.Count - 2));
-                                    AddThemeRuleNode(layer, node, geomType, rules.Count - 1, rules, rules.Count - 1);
-                                }
-                                else
-                                {
-                                    for (int r = 0; r < rules.Count; r++)
+
+                                    if (_legend.ThemeCompressionLimit > 0 && rules.Count > _legend.ThemeCompressionLimit)
                                     {
-                                        AddThemeRuleNode(layer, node, geomType, catIndex++, rules, 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);
                                     }
+                                    else
+                                    {
+                                        for (int r = 0; r < rules.Count; r++)
+                                        {
+                                            AddThemeRuleNode(layerMeta, themeCat, node, geomType, catIndex++, rules, r);
+                                        }
+                                    }
                                 }
                             }
                         }
                     }
                 }
+                else //Already cached
+                {
+                    Trace.TraceInformation("Icons already cached for: " + layer.Name);
+                    node.Nodes.AddRange(layerMeta.CreateThemeNodesFromCachedMetadata(_map.ViewScale));
+                }
             }
 
             return node;
         }
 
-        private void AddThemeRuleNode(MgLayerBase layer, 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 r)
         {
             XmlElement rule = (XmlElement)rules[r];
             XmlNodeList label = rule.GetElementsByTagName("LegendLabel");
@@ -256,33 +276,32 @@
             //if (filter != null && filter.Count > 0 && filter[0].ChildNodes.Count > 0)
             //    filterText = filter[0].ChildNodes[0].Value;
 
-            var child = CreateThemeRuleNode(layer.LayerDefinition, _map.ViewScale, labelText, (geomType + 1), catIndex);
+            var child = CreateThemeRuleNode(layerMeta, themeCat, _map.ViewScale, labelText, (geomType + 1), catIndex);
             node.Nodes.Add(child);
         }
 
-        private TreeNode CreateCompressedThemeNode(int count)
+        private TreeNode CreateCompressedThemeNode(LayerNodeMetadata layer, ThemeCategory cat, int count)
         {
             TreeNode node = new TreeNode();
             node.Text = (count + " other styles");
             node.ImageKey = node.SelectedImageKey = IMG_OTHER;
-            node.Tag = new LayerNodeMetadata(null, false)
-            {
-                IsBaseLayer = false,
-                ThemeIcon = Properties.Resources.icon_etc,
-                IsThemeRule = true
-            };
+            var meta = new LayerThemeNodeMetadata(true, Properties.Resources.icon_etc, node.Text);
+            node.Tag = meta;
+            layer.AddThemeNode(cat, meta);
             return node;
         }
 
-        private TreeNode CreateThemeRuleNode(MgResourceIdentifier layerDefId, double viewScale, string labelText, int geomType, int categoryIndex)
+        private TreeNode CreateThemeRuleNode(LayerNodeMetadata layer, ThemeCategory themeCat, double viewScale, string labelText, int geomType, int categoryIndex)
         {
-            MgByteReader icon = _provider.GenerateLegendImage(layerDefId,
+            MgLayerBase lyr = layer.Layer;
+            MgByteReader icon = _provider.GenerateLegendImage(lyr.LayerDefinition,
                                                               viewScale,
                                                               16,
                                                               16,
                                                               "PNG",
                                                               geomType,
                                                               categoryIndex);
+            legendCallCount++;
             TreeNode node = new TreeNode();
             node.Text = labelText;
             if (icon != null)
@@ -292,17 +311,12 @@
 
                     byte[] b = new byte[icon.GetLength()];
                     icon.Read(b, b.Length);
-                    var tag = new LayerNodeMetadata(null, false)
-                    {
-                        IsBaseLayer = false,
-                        IsThemeRule = true
-                    };
                     using (var ms = new MemoryStream(b))
                     {
-                        string id = Guid.NewGuid().ToString();
-                        tag.ThemeIcon = Image.FromStream(ms);
+                        var tag = new LayerThemeNodeMetadata(false, Image.FromStream(ms), labelText);
+                        layer.AddThemeNode(themeCat, tag);
+                        node.Tag = tag;
                     }
-                    node.Tag = tag;
                 }
                 finally
                 {
@@ -319,30 +333,34 @@
             node.Text = group.GetLegendLabel();
             node.Checked = group.IsVisible();
             node.SelectedImageKey = node.ImageKey = IMG_GROUP;
-            node.Tag = new GroupNodeMetadata(group);
+            var meta = new GroupNodeMetadata(group);
+            node.Tag = meta;
+            _groups[group.GetObjectId()] = meta;
             node.ContextMenuStrip = _legend.GroupContextMenu;
             return node;
         }
 
+        private int legendCallCount = 0;
+
         public TreeNode[] CreateNodes()
         {
             List<TreeNode> output = new List<TreeNode>();
             var nodesById = new Dictionary<string, TreeNode>();
 
             var scale = _map.ViewScale;
+            if (scale < 10.0)
+                return output.ToArray();
+
             var groups = _map.GetLayerGroups();
             var layers = _map.GetLayers();
 
-            _layerDefinitionContents.Clear();
-            _layers.Clear();
-            _groups.Clear();
+            legendCallCount = 0;
 
             //Process groups first
             List<MgLayerGroup> remainingNodes = new List<MgLayerGroup>();
             for (int i = 0; i < groups.GetCount(); i++)
             {
                 var group = groups.GetItem(i);
-                _groups.Add(group.GetObjectId(), group);
                 if (!group.GetDisplayInLegend())
                     continue;
 
@@ -382,38 +400,73 @@
                 }
             }
 
-            //Now process layers
+            //Collect all resource contents in a batch
+            MgStringCollection layerIds = new MgStringCollection();
+            //Also collect the layer metadata nodes to create or update
+            var layerMetaNodesToUpdate = new Dictionary<string, MgLayerBase>();
+            //Now process layers. Layers without metadata nodes or without layer definition content
+            //are added to the list
             for (int i = 0; i < layers.GetCount(); i++)
             {
                 var lyr = layers.GetItem(i);
-                var ldfId = lyr.LayerDefinition;
+                bool display = lyr.DisplayInLegend;
+                bool visible = _provider.IsLayerPotentiallyVisibleAtScale(lyr, false);
+                if (!display)
+                    continue;
 
-                if (!_layerDefinitionContents.ContainsKey(ldfId.ToString()))
+                if (!visible)
+                    continue;
+
+                if (_layers.ContainsKey(lyr.GetObjectId()))
                 {
-                    _layerDefinitionContents[ldfId.ToString()] = string.Empty;
+                    if (string.IsNullOrEmpty(_layers[lyr.GetObjectId()].LayerDefinitionContent))
+                    {
+                        var ldfId = lyr.LayerDefinition;
+                        layerIds.Add(ldfId.ToString());
+                        layerMetaNodesToUpdate[ldfId.ToString()] = lyr;
+                    }
                 }
+                else
+                {
+                    var ldfId = lyr.LayerDefinition;
+                    layerIds.Add(ldfId.ToString());
+                    layerMetaNodesToUpdate[ldfId.ToString()] = lyr;
+                }
             }
 
-            //Collect all resource contents in a batch
-            MgStringCollection layerIds = new MgStringCollection();
-            foreach (var lid in _layerDefinitionContents.Keys)
+            if (layerIds.GetCount() > 0)
             {
-                layerIds.Add(lid);
+                int added = 0;
+                int updated = 0;
+                //Fetch the contents and create/update the required layer metadata nodes
+                MgStringCollection layerContents = _resSvc.GetResourceContents(layerIds, null);
+                for (int i = 0; i < layerIds.GetCount(); i++)
+                {
+                    string lid = layerIds.GetItem(i);
+                    var lyr = layerMetaNodesToUpdate[lid];
+                    var objId = lyr.GetObjectId();
+                    LayerNodeMetadata meta = null;
+                    if (_layers.ContainsKey(objId))
+                    {
+                        meta = _layers[objId];
+                        updated++;
+                    }
+                    else
+                    {
+                        meta = new LayerNodeMetadata(lyr, lyr.Selectable);
+                        _layers[objId] = meta;
+                        added++;
+                    }
+                    meta.LayerDefinitionContent = layerContents.GetItem(i);
+                }
+                Trace.TraceInformation("CreateNodes: {0} layer contents added, {1} layer contents updated", added, updated);
             }
 
-            MgStringCollection layerContents = _resSvc.GetResourceContents(layerIds, null);
-            for (int i = 0; i < layerIds.GetCount(); i++)
-            {
-                string lid = layerIds.GetItem(i);
-                _layerDefinitionContents[lid] = layerContents.GetItem(i);
-            }
-
             List<MgLayerBase> remainingLayers = new List<MgLayerBase>();
             for (int i = 0; i < layers.GetCount(); i++)
             {
                 var layer = layers.GetItem(i);
-                _layers.Add(layer.GetObjectId(), layer);
-
+                
                 bool display = layer.DisplayInLegend;
                 bool visible = _provider.IsLayerPotentiallyVisibleAtScale(layer, false);
                 if (!display)
@@ -481,15 +534,15 @@
                     }
                 }
             }
-
+            Trace.TraceInformation("{0} calls made to GenerateLegendImage", legendCallCount);
             return output.ToArray();
         }
 
         private static bool IsThemeLayerNode(TreeNode node)
         {
-            var meta = node.Tag as LayerNodeMetadata;
+            var meta = node.Tag as LayerThemeNodeMetadata;
             if (meta != null)
-                return meta.ThemeIcon != null || meta.IsBaseLayer;
+                return true;
 
             return false;
         }
@@ -502,7 +555,7 @@
 
         internal void DrawNode(DrawTreeNodeEventArgs e, bool showPlusMinus, Font font)
         {
-            if (IsLayerNode(e.Node) && !e.Bounds.IsEmpty)
+            if (!e.Bounds.IsEmpty && (IsLayerNode(e.Node) || IsThemeLayerNode(e.Node)))
             {
                 Color backColor, foreColor;
 
@@ -555,11 +608,12 @@
                     foreColor = e.Node.ForeColor;
                 }
 
-                var tag = e.Node.Tag as LayerNodeMetadata;
+                var layerMeta = e.Node.Tag as LayerNodeMetadata;
+                var themeMeta = e.Node.Tag as LayerThemeNodeMetadata;
                 var checkBoxOffset = xoffset;
                 var selectabilityOffset = xoffset + 16;
                 var iconOffsetNoSelect = xoffset + 16;
-                if (tag != null && tag.IsThemeRule) //No checkbox for theme rule nodes
+                if (themeMeta != null) //No checkbox for theme rule nodes
                 {
                     selectabilityOffset = xoffset;
                     iconOffsetNoSelect = xoffset;
@@ -571,7 +625,7 @@
                 //Uncomment if you need to "see" the bounds of the node
                 //e.Graphics.DrawRectangle(Pens.Black, e.Node.Bounds);
 
-                if (tag != null && !tag.IsThemeRule) //No checkbox for theme rule nodes
+                if (layerMeta != null) //No checkbox for theme rule nodes
                 {
                     if (Application.RenderWithVisualStyles)
                     {
@@ -590,33 +644,45 @@
                         e.Graphics.DrawRectangle(new Pen(Brushes.Black, 2.0f), rect);
                     }
                 }
-                if (tag != null)
+                if (layerMeta != null)
                 {
-                    if (tag.DrawSelectabilityIcon)
+                    if (layerMeta.DrawSelectabilityIcon)
                     {
-                        var icon = tag.IsSelectable ? _selectableIcon : _unselectableIcon;
+                        var icon = layerMeta.IsSelectable ? _selectableIcon : _unselectableIcon;
                         e.Graphics.DrawImage(icon, e.Node.Bounds.X + selectabilityOffset, e.Node.Bounds.Y);
                         //Trace.TraceInformation("Painted icon at ({0},{1})", e.Node.Bounds.X, e.Node.Bounds.Y);
                     }
-                    if (tag.ThemeIcon != null)
+                    if (layerMeta.Icon != null)
                     {
-                        if (tag.DrawSelectabilityIcon)
+                        if (layerMeta.DrawSelectabilityIcon)
                         {
-                            e.Graphics.DrawImage(tag.ThemeIcon, e.Node.Bounds.X + iconOffset, e.Node.Bounds.Y);
+                            e.Graphics.DrawImage(layerMeta.Icon, e.Node.Bounds.X + iconOffset, e.Node.Bounds.Y);
                             //Trace.TraceInformation("Painted icon at ({0},{1})", e.Node.Bounds.X, e.Node.Bounds.Y);
                         }
                         else
                         {
-                            e.Graphics.DrawImage(tag.ThemeIcon, e.Node.Bounds.X + iconOffsetNoSelect, e.Node.Bounds.Y);
+                            e.Graphics.DrawImage(layerMeta.Icon, e.Node.Bounds.X + iconOffsetNoSelect, e.Node.Bounds.Y);
                             //Trace.TraceInformation("Painted icon at ({0},{1})", e.Node.Bounds.X, e.Node.Bounds.Y);
                         }
                     }
 
                     using (SolidBrush brush = new SolidBrush(Color.Black))
                     {
-                        e.Graphics.DrawString(e.Node.Text, font, brush, e.Node.Bounds.X + (tag.DrawSelectabilityIcon ? textOffset : textOffsetNoSelect), e.Node.Bounds.Y);
+                        e.Graphics.DrawString(e.Node.Text, font, brush, e.Node.Bounds.X + (layerMeta.DrawSelectabilityIcon ? textOffset : textOffsetNoSelect), e.Node.Bounds.Y);
                     }
                 }
+                else if (themeMeta != null)
+                {
+                    if (themeMeta.ThemeIcon != null)
+                    {
+                        e.Graphics.DrawImage(themeMeta.ThemeIcon, e.Node.Bounds.X + iconOffsetNoSelect, e.Node.Bounds.Y);
+                    }
+
+                    using (SolidBrush brush = new SolidBrush(Color.Black))
+                    {
+                        e.Graphics.DrawString(e.Node.Text, font, brush, e.Node.Bounds.X + textOffsetNoSelect, e.Node.Bounds.Y);
+                    }
+                }
                 else
                 {
                     using (SolidBrush brush = new SolidBrush(Color.Black))
@@ -633,23 +699,29 @@
             }
         }
 
-        internal void SetGroupExpandInLegend(string groupName, bool expand)
+        internal void SetGroupExpandInLegend(string objectId, bool expand)
         {
-            if (_groups.ContainsKey(groupName))
-                _provider.SetGroupExpandInLegend(_groups[groupName], expand);
+            if (_groups.ContainsKey(objectId))
+            {
+                var grp = _groups[objectId].Group;
+                _provider.SetGroupExpandInLegend(grp, expand);
+            }
         }
 
-        internal void SetLayerExpandInLegend(string layerName, bool expand)
+        internal void SetLayerExpandInLegend(string objectId, bool expand)
         {
-            if (_layers.ContainsKey(layerName))
-                _provider.SetLayerExpandInLegend(_layers[layerName], expand);
+            if (_layers.ContainsKey(objectId))
+            {
+                var lyr = _layers[objectId].Layer;
+                _provider.SetLayerExpandInLegend(lyr, expand);
+            }
         }
 
-        internal void SetGroupVisible(string name, bool bChecked)
+        internal void SetGroupVisible(string objectId, bool bChecked)
         {
-            if (_groups.ContainsKey(name))
+            if (_groups.ContainsKey(objectId))
             {
-                var grp = _groups[name];
+                var grp = _groups[objectId].Group;
                 grp.SetVisible(bChecked);
                 var bVis = HasVisibleParent(grp);
                 if (bVis)
@@ -657,11 +729,11 @@
             }
         }
 
-        internal void SetLayerVisible(string name, bool bChecked)
+        internal void SetLayerVisible(string objectId, bool bChecked)
         {
-            if (_layers.ContainsKey(name))
+            if (_layers.ContainsKey(objectId))
             {
-                var layer = _layers[name];
+                var layer = _layers[objectId].Layer;
                 layer.SetVisible(bChecked);
                 var bVis = HasVisibleParent(layer);
                 if (bVis)
@@ -675,22 +747,77 @@
 
     namespace Legend.Model
     {
-        class LegendNodeMetadata
+        abstract class LegendNodeMetadata
         {
             public bool IsGroup { get; protected set; }
+
+            public abstract string ObjectId { get; }
         }
 
+        [DebuggerDisplay("Name = {Layer.Name}, Label = {Layer.LegendLabel}")]
         class GroupNodeMetadata : LegendNodeMetadata
         {
-            internal MgLayerGroup Group { get; set; }
+            internal MgLayerGroup Group { get; private set; }
 
             public GroupNodeMetadata(MgLayerGroup group)
             {
                 base.IsGroup = true;
                 this.Group = group;
             }
+
+            public override string ObjectId
+            {
+                get { return this.Group.GetObjectId(); }
+            }
         }
 
+        [DebuggerDisplay("Layer Theme Node")]
+        class LayerThemeNodeMetadata : LegendNodeMetadata
+        {
+            public LayerThemeNodeMetadata(bool bPlaceholder, Image themeIcon, string labelText)
+            {
+                this.IsPlaceholder = bPlaceholder;
+                this.ThemeIcon = themeIcon;
+                this.Label = labelText;
+            }
+
+            public bool IsPlaceholder { get; private set; }
+
+            public Image ThemeIcon { get; set; }
+
+            public string Label { get; private set; }
+
+            public override string ObjectId
+            {
+                get { return ""; }
+            }
+        }
+
+        class ThemeCategory
+        {
+            public string MinScale { get; set; }
+
+            public string MaxScale { get; set; }
+
+            public int GeometryType { get; set; }
+
+            public override int GetHashCode()
+            {
+                unchecked // Overflow is fine, just wrap
+                {
+                    int hash = 17;
+                    // Suitable nullity checks etc, of course :)
+                    if (MinScale != null)
+                        hash = hash * 23 + MinScale.GetHashCode();
+                    if (MaxScale != null)
+                        hash = hash * 23 + MaxScale.GetHashCode();
+                    hash = hash * 23 + GeometryType.GetHashCode();
+                    return hash;
+                }
+            }
+        }
+
+        [DebuggerDisplay("Name = {Layer.Name}, Label = {Layer.LegendLabel}")]
         class LayerNodeMetadata : LegendNodeMetadata
         {
             public LayerNodeMetadata(MgLayerBase layer, bool bInitiallySelectable)
@@ -699,20 +826,122 @@
                 this.Layer = layer;
                 this.IsSelectable = (layer != null) ? layer.Selectable : false;
                 this.DrawSelectabilityIcon = (layer != null && bInitiallySelectable);
-                this.IsThemeRule = false;
+                this.WasInitiallySelectable = bInitiallySelectable;
+                this.LayerDefinitionContent = null;
+                _themeNodes = new Dictionary<ThemeCategory, List<LayerThemeNodeMetadata>>();
             }
 
-            internal MgLayerBase Layer { get; set; }
+            public override string ObjectId
+            {
+                get { return this.Layer.GetObjectId(); }
+            }
 
+            public Image Icon { get; set; }
+
+            public string IconId { get; set; }
+
+            internal MgLayerBase Layer { get; private set; }
+
             public bool DrawSelectabilityIcon { get; set; }
 
             public bool IsSelectable { get; set; }
 
-            public bool IsThemeRule { get; set; }
+            public bool WasInitiallySelectable { get; private set; }
 
             public bool IsBaseLayer { get; set; }
 
-            public Image ThemeIcon { get; set; }
+            public string LayerDefinitionContent { get; set; }
+
+            private Dictionary<ThemeCategory, List<LayerThemeNodeMetadata>> _themeNodes;
+
+            public List<LayerThemeNodeMetadata> GetThemeNodes(ThemeCategory category)
+            {
+                if (_themeNodes.ContainsKey(category))
+                    return _themeNodes[category];
+                return null;
+            }
+
+            public void AddThemeNode(ThemeCategory category, LayerThemeNodeMetadata themeMeta)
+            {
+                if (!_themeNodes.ContainsKey(category))
+                    _themeNodes[category] = new List<LayerThemeNodeMetadata>();
+
+                _themeNodes[category].Add(themeMeta);
+            }
+
+            internal bool HasTheme()
+            {
+                if (_themeNodes.Count == 0)
+                    return false;
+
+                foreach (var coll in _themeNodes.Values)
+                    if (coll.Count > 0)
+                        return true;
+
+                return false;
+            }
+
+            internal TreeNode[] CreateThemeNodesFromCachedMetadata(double scale)
+            {
+                var nodes = new List<TreeNode>();
+
+                //Find the applicable scale range(s)
+                foreach (var cat in _themeNodes.Keys)
+                {
+                    bool bApplicable = false;
+
+                    bool bHasMin = !string.IsNullOrEmpty(cat.MinScale);
+                    bool bHasMax = !string.IsNullOrEmpty(cat.MaxScale);
+
+                    if (bHasMin)
+                    {
+                        double minVal = double.Parse(cat.MinScale);
+                        if (bHasMax) //bHasMin = true, bHasMax = true
+                        {
+                            double maxVal = double.Parse(cat.MaxScale);
+                            if (scale >= minVal && scale < maxVal)
+                                bApplicable = true;
+                        }
+                        else         //bHasMin = true, bHasMax = false
+                        {
+                            if (scale >= minVal)
+                                bApplicable = true;
+                        }
+                    }
+                    else
+                    {
+                        if (bHasMax) //bHasMin = false, bHasMax = true
+                        {
+                            double maxVal = double.Parse(cat.MaxScale);
+                            if (scale < maxVal)
+                                bApplicable = true;
+                        }
+                        else         //bHasMin = false, bHasMax = false
+                        {
+                            bApplicable = true;
+                        }
+                    }
+
+                    if (bApplicable)
+                    {
+                        var metadata = _themeNodes[cat];
+                        nodes.AddRange(CreateThemeNodes(metadata));
+                    }
+                }
+
+                return nodes.ToArray();
+            }
+
+            private IEnumerable<TreeNode> CreateThemeNodes(List<LayerThemeNodeMetadata> metadata)
+            {
+                foreach (var meta in metadata)
+                {
+                    var node = new TreeNode();
+                    node.Text = meta.Label;
+                    node.Tag = meta;
+                    yield return node;
+                }
+            }
         }
     }
 }



More information about the mapguide-commits mailing list