private TreeNode CreateThemeRuleNode(LayerNodeMetadata layer, ThemeCategory themeCat, double viewScale, string labelText, int geomType, int categoryIndex) { var lyr = layer.Layer; TreeNode node = new TreeNode(); node.Text = labelText; Image icon = _map.GetLegendImage(lyr.LayerDefinitionID, viewScale, 16, 16, "PNG", geomType, categoryIndex); legendCallCount++; var tag = new LayerThemeNodeMetadata(false, icon, labelText); layer.AddThemeNode(themeCat, tag); node.Tag = tag; return node; }
public TreeNode[] CreateNodes() { List<TreeNode> topLevelNodes = new List<TreeNode>(); var scale = _map.ViewScale; if (scale < 10.0) return topLevelNodes.ToArray(); var nodesById = new Dictionary<string, TreeNode>(); var groupsById = new Dictionary<string, TreeNode>(); var groups = _map.Groups; var layers = _map.Layers; legendCallCount = 0; //Process groups first List<RuntimeMapGroup> remainingNodes = new List<RuntimeMapGroup>(); for (int i = 0; i < groups.Count; i++) { var group = groups[i]; if (!_legend.ShowAllLayersAndGroups && !group.ShowInLegend) continue; //Add ones without parents first. Queue up child groups if (!string.IsNullOrEmpty(group.Group)) { remainingNodes.Add(group); } else { var node = CreateGroupNode(group); topLevelNodes.Add(node); nodesById.Add(group.ObjectId, node); groupsById.Add(group.ObjectId, node); } } //Process child groups while (remainingNodes.Count > 0) { List<RuntimeMapGroup> toRemove = new List<RuntimeMapGroup>(); //Establish parent-child relationships for any child groups here for (int j = 0; j < remainingNodes.Count; j++) { var grpName = remainingNodes[j].Group; var parentGroup = _map.Groups[grpName]; if (parentGroup != null && nodesById.ContainsKey(parentGroup.ObjectId)) { var node = CreateGroupNode(remainingNodes[j]); nodesById[parentGroup.ObjectId].Nodes.Add(node); var grpId = remainingNodes[j].ObjectId; //Got to add this group node too, otherwise we could infinite //loop looking for a parent that's not registered nodesById.Add(grpId, node); groupsById.Add(grpId, node); toRemove.Add(remainingNodes[j]); } } //Whittle down this list if (toRemove.Count > 0) { foreach (var g in toRemove) { remainingNodes.Remove(g); } } } //Collect all resource contents in a batch var layerIds = new List<string>(); //Also collect the layer metadata nodes to create or update var layerMetaNodesToUpdate = new Dictionary<string, RuntimeMapLayer>(); //Now process layers. Layers without metadata nodes or without layer definition content //are added to the list for (int i = 0; i < layers.Count; i++) { var lyr = layers[i]; bool display = lyr.ShowInLegend; bool visible = lyr.IsVisibleAtScale(_map.ViewScale); if (!_legend.ShowAllLayersAndGroups && !display) continue; if (!_legend.ShowAllLayersAndGroups && !visible) continue; if (_layers.ContainsKey(lyr.ObjectId)) { if (string.IsNullOrEmpty(_layers[lyr.ObjectId].LayerDefinitionContent)) { var ldfId = lyr.LayerDefinitionID; layerIds.Add(ldfId.ToString()); layerMetaNodesToUpdate[ldfId.ToString()] = lyr; } } else { var ldfId = lyr.LayerDefinitionID; layerIds.Add(ldfId.ToString()); layerMetaNodesToUpdate[ldfId.ToString()] = lyr; } } if (layerIds.Count > 0) { int added = 0; int updated = 0; //Fetch the contents and create/update the required layer metadata nodes //TODO: Surely we can optimize this better foreach (var lid in layerIds) { using (var sr = new StreamReader(_resSvc.GetResourceXmlData(lid))) { string content = sr.ReadToEnd(); var lyr = layerMetaNodesToUpdate[lid]; var objId = lyr.ObjectId; LayerNodeMetadata meta = null; if (_layers.ContainsKey(objId)) { meta = _layers[objId]; updated++; } else { RuntimeMapGroup group = null; if (!string.IsNullOrEmpty(lyr.Group)) group = _map.Groups[lyr.Group]; meta = new LayerNodeMetadata(lyr, lyr.Selectable); _layers[objId] = meta; added++; } meta.LayerDefinitionContent = content; } } Trace.TraceInformation("CreateNodes: {0} layer contents added, {1} layer contents updated", added, updated); } //Now create our layer nodes List<RuntimeMapLayer> remainingLayers = new List<RuntimeMapLayer>(); //NOTE: We're taking a page out of the Fusion playbook of reverse iterating the layer //collection and prepending the nodes, as this control suffered the same problem as the //Legend widget in Fusion. Doing it this way eliminates the need for doing an extra pass to fix //the layer/group ordering, which may make an impact on really chunky maps. for (int i = layers.Count - 1; i >= 0; i--) { var layer = layers[i]; bool display = layer.ShowInLegend; bool visible = layer.IsVisibleAtScale(_map.ViewScale); if (!_legend.ShowAllLayersAndGroups && !display) continue; if (!_legend.ShowAllLayersAndGroups && !visible) continue; //Add ones without parents first. Queue up parented layers if (!string.IsNullOrEmpty(layer.Group)) { remainingLayers.Add(layer); } else { var node = CreateLayerNode(layer); if (node != null) { topLevelNodes.Insert(0, node); nodesById.Add(layer.ObjectId, node); if (layer.ExpandInLegend) node.Expand(); } } } //Process parented layers while (remainingLayers.Count > 0) { List<RuntimeMapLayer> toRemove = new List<RuntimeMapLayer>(); for (int j = remainingLayers.Count - 1; j >= 0; j--) { var grpName = remainingLayers[j].Group; var parentGroup = _map.Groups[grpName]; if (parentGroup != null) { if (nodesById.ContainsKey(parentGroup.ObjectId)) { var node = CreateLayerNode(remainingLayers[j]); if (node != null) { nodesById[parentGroup.ObjectId].Nodes.Add(node); //.Insert(0, node); if (remainingLayers[j].ExpandInLegend) node.Expand(); } toRemove.Add(remainingLayers[j]); } else //Group may not even be set to show in legend. Check for this { if (!parentGroup.ShowInLegend) toRemove.Add(remainingLayers[j]); } } } //Whittle down this list if (toRemove.Count > 0) { foreach (var g in toRemove) { remainingLayers.Remove(g); } } } //Now expand any relevant groups for (int i = 0; i < groups.Count; i++) { var group = groups[i]; if (group.ExpandInLegend) { var groupId = group.ObjectId; if (nodesById.ContainsKey(groupId)) { nodesById[groupId].Expand(); } } } Trace.TraceInformation("{0} calls made to GenerateLegendImage", legendCallCount); return topLevelNodes.ToArray(); }
private TreeNode CreateCompressedThemeNode(LayerNodeMetadata layer, ThemeCategory cat, int count) { TreeNode node = new TreeNode(); node.Text = (count + " other styles"); node.ImageKey = node.SelectedImageKey = IMG_OTHER; var meta = new LayerThemeNodeMetadata(true, Properties.Resources.icon_etc, node.Text); node.Tag = meta; layer.AddThemeNode(cat, meta); return node; }
private TreeNode CreateLayerNode(RuntimeMapLayer layer) { var node = new TreeNode(); node.Name = layer.ObjectId; node.Text = layer.LegendLabel; node.Checked = layer.Visible; //node.ContextMenuStrip = _legend.LayerContextMenu; var lt = layer.Type; var fsId = layer.FeatureSourceID; LayerNodeMetadata layerMeta = null; if (fsId.EndsWith("DrawingSource")) { node.SelectedImageKey = node.ImageKey = IMG_DWF; bool bInitiallySelectable = layer.Selectable; if (_layers.ContainsKey(layer.ObjectId)) { layerMeta = _layers[layer.ObjectId]; bInitiallySelectable = layerMeta.WasInitiallySelectable; } else //If not in the dictionary, assume it is a dynamically added layer { RuntimeMapGroup group = null; if (!string.IsNullOrEmpty(layer.Group)) group = _map.Groups[layer.Group]; layerMeta = new LayerNodeMetadata(layer, bInitiallySelectable); _layers[layer.ObjectId] = layerMeta; } node.Tag = layerMeta; node.ToolTipText = string.Format(Properties.Resources.DrawingLayerTooltip, Environment.NewLine, layer.Name, layer.FeatureSourceID); } else //Vector or Grid layer { var ldfId = layer.LayerDefinitionID; if (_layers.ContainsKey(layer.ObjectId)) { layerMeta = _layers[layer.ObjectId]; } else { RuntimeMapGroup group = null; if (!string.IsNullOrEmpty(layer.Group)) group = _map.Groups[layer.Group]; layerMeta = new LayerNodeMetadata(layer, layer.Selectable); _layers[layer.ObjectId] = layerMeta; } if (string.IsNullOrEmpty(layerMeta.LayerDefinitionContent)) return null; 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 = LAYER_VECTOR; XmlNodeList scaleRanges = doc.GetElementsByTagName("VectorScaleRange"); if (scaleRanges.Count == 0) { scaleRanges = doc.GetElementsByTagName("GridScaleRange"); if (scaleRanges.Count == 0) { scaleRanges = doc.GetElementsByTagName("DrawingLayerDefinition"); if (scaleRanges.Count == 0) return null; type = LAYER_DWF; } else type = LAYER_RASTER; } String[] typeStyles = new String[] { "PointTypeStyle", "LineTypeStyle", "AreaTypeStyle", "CompositeTypeStyle" }; String[] ruleNames = new String[] { "PointRule", "LineRule", "AreaRule", "CompositeRule" }; node.ToolTipText = string.Format(Properties.Resources.DefaultLayerTooltip, Environment.NewLine, layer.Name, layer.FeatureSourceID, layer.QualifiedClassName); //Do this if not cached already from a previous run if (!layerMeta.HasTheme() || !layerMeta.HasDefaultIcons()) { 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 != LAYER_VECTOR) break; 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) { foreach (XmlNode n in styleNodes) { // 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 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) { // 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 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(Properties.Resources.ThemedLayerTooltip, Environment.NewLine, layer.Name, layer.FeatureSourceID, layer.QualifiedClassName, 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, theRule.GeomType, (catIndex + r), theRule.RuleNodes, r); } } //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)) { try { var img = _map.GetLegendImage(layer.LayerDefinitionID, _map.ViewScale, 16, 16, "PNG", (theRule.GeomType + 1), -1); legendCallCount++; layerMeta.SetDefaultIcon(themeCat, img); node.ToolTipText = string.Format(Properties.Resources.DefaultLayerTooltip, Environment.NewLine, layer.Name, layer.FeatureSourceID, layer.QualifiedClassName); } catch { //layerMeta.SetDefaultIcon(themeCat, Properties.Resources.lc_broken); } } } } //for (int geomType = 0; geomType < typeStyles.Length; geomType++) //{ // ThemeCategory themeCat = new ThemeCategory() // { // 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"); // 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.SetDefaultIcon(themeCat, Properties.Resources.lc_theme); // node.ToolTipText = string.Format(Properties.Resources.ThemedLayerTooltip, Environment.NewLine, layer.Name, layer.FeatureSourceID, layer.QualifiedClassName, rules.Count); // if (_legend.ThemeCompressionLimit > 0 && rules.Count > _legend.ThemeCompressionLimit) // { // 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 // { // if (LayerNodeMetadata.ScaleIsApplicable(_map.ViewScale, themeCat)) // { // if (!layerMeta.HasDefaultIconsAt(_map.ViewScale)) // { // try // { // var img = _map.GetLegendImage(layer.LayerDefinitionID, // _map.ViewScale, // 16, // 16, // "PNG", // -1, // -1); // legendCallCount++; // layerMeta.SetDefaultIcon(themeCat, img); // node.ToolTipText = string.Format(Properties.Resources.DefaultLayerTooltip, Environment.NewLine, layer.Name, layer.FeatureSourceID, layer.QualifiedClassName); // } // catch // { // //layerMeta.SetDefaultIcon(themeCat, Properties.Resources.lc_broken); // } // } // } // } // } //} } } else //Already cached { Trace.TraceInformation("Icons already cached for: " + layer.Name); node.Nodes.AddRange(layerMeta.CreateThemeNodesFromCachedMetadata(_map.ViewScale)); } } return node; }
private void AddThemeRuleNode(LayerNodeMetadata layerMeta, ThemeCategory themeCat, TreeNode node, int geomType, int catIndex, XmlNodeList rules, int ruleOffset) { XmlElement rule = (XmlElement)rules[ruleOffset]; XmlNodeList label = rule.GetElementsByTagName("LegendLabel"); XmlNodeList filter = rule.GetElementsByTagName("Filter"); String labelText = ""; if (label != null && label.Count > 0 && label[0].ChildNodes.Count > 0) labelText = label[0].ChildNodes[0].Value; //String filterText = ""; //if (filter != null && filter.Count > 0 && filter[0].ChildNodes.Count > 0) // filterText = filter[0].ChildNodes[0].Value; if (LayerNodeMetadata.ScaleIsApplicable(_map.ViewScale, themeCat)) { var child = CreateThemeRuleNode(layerMeta, themeCat, _map.ViewScale, labelText, (geomType + 1), catIndex); node.Nodes.Add(child); } else { } }