Updates referencesource to .NET 4.7
[mono-project.git] / mcs / class / referencesource / System.Data.Entity / System / Data / Common / Utils / TreePrinter.cs
blobdd2a101c588fe813eaf8104c9612f91f1d86314e
1 //---------------------------------------------------------------------
2 // <copyright file="TreePrinter.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
4 // </copyright>
5 //
6 // @owner Microsoft
7 //---------------------------------------------------------------------
9 using System;
10 using System.Collections.Generic;
11 using System.Diagnostics;
12 using System.Globalization;
13 using System.Text;
15 namespace System.Data.Common.Utils
17 /// <summary>
18 /// Represents a node in a hierarchical collection of information strings.
19 /// Intended as a common way mechanism to represent tree structures for debugging (using the TreePrinter class).
20 /// A node consists of a string (represented as a StringBuilder), its collection of child nodes, and an optional Tag value.
21 /// </summary>
22 internal class TreeNode
24 private StringBuilder _text;
25 private List<TreeNode> _children = new List<TreeNode>();
26 private int _position;
28 // Default constructor
29 internal TreeNode()
31 _text = new StringBuilder();
34 /// <summary>
35 /// Constructs a new TreeNode with the specified text, tag value and child nodes
36 /// </summary>
37 /// <param name="text">The initial value of the new node's text</param>
38 /// <param name="children">An optional list of initial child nodes</param>
39 internal TreeNode(string text, params TreeNode[] children)
41 if (string.IsNullOrEmpty(text))
43 _text = new StringBuilder();
45 else
47 _text = new StringBuilder(text);
50 if (children != null)
52 _children.AddRange(children);
56 // IEnumerable convenience constructors
57 internal TreeNode(string text, List<TreeNode> children)
58 : this(text)
60 if (children != null)
62 _children.AddRange(children);
66 // 'public' properties
68 /// <summary>
69 /// The current text of this node.
70 /// </summary>
71 internal StringBuilder Text { get { return _text; } }
73 /// <summary>
74 /// The collection of child nodes for this node, which may be empty.
75 /// </summary>
76 internal IList<TreeNode> Children { get { return _children; } }
78 // Used only by the TreePrinter when generating the output string
79 internal int Position { get { return _position; } set { _position = value; } }
82 /// <summary>
83 /// Generates a formatted string from a hierarchy of tree nodes. Derived types may override
84 /// the PreProcess, Before/AfterAppend, Print, PrintNode and PrintChildren methods to add
85 /// specific functionality at particular points in process of building the string.
86 /// </summary>
87 internal abstract class TreePrinter
89 #region Private Instance Members
91 private List<TreeNode> _scopes = new List<TreeNode>();
92 private bool _showLines = true;
93 private char _horizontals = '_';
94 private char _verticals = '|';
96 #endregion
98 #region 'Public' API
100 /// <summary>
101 /// Entry point method for the TreePrinter
102 /// </summary>
103 /// <param name="node">The TreeNode instance that is the root of the tree to be printed</param>
104 /// <returns>A string representation of the specified tree</returns>
105 internal virtual string Print(TreeNode node)
107 this.PreProcess(node);
109 StringBuilder text = new StringBuilder();
110 PrintNode(text, node);
111 return text.ToString();
114 #endregion
116 #region 'Protected' API
118 // 'protected' constructor
119 internal TreePrinter() { }
121 // 'protected' API that may be overriden to customize printing
123 /// <summary>
124 /// Called once on the root of the tree before printing begins
125 /// </summary>
126 /// <param name="node">The TreeNode that is the root of the tree</param>
127 internal virtual void PreProcess(TreeNode node) { }
129 /// <summary>
130 /// Called once for every node after indentation, connecting lines and the node's text value
131 /// have been added to the output but before the line suffix (if any) has been added.
132 /// </summary>
133 /// <param name="node">The current node</param>
134 /// <param name="text">The StringBuilder into which the tree is being printed</param>
135 internal virtual void AfterAppend(TreeNode node, StringBuilder text) { }
137 /// <summary>
138 /// Called once for every node immediately after the line prefix (if any) and appropriate
139 /// indentation and connecting lines have been added to the output but before the node's
140 /// text value has been added.
141 /// </summary>
142 /// <param name="node">The current node</param>
143 /// <param name="text">The StringBuilder into which the tree is being printed</param>
144 internal virtual void BeforeAppend(TreeNode node, StringBuilder text) { }
146 /// <summary>
147 /// The recursive step of the printing process, called once for each TreeNode in the tree
148 /// </summary>
149 /// <param name="text">The StringBuilder into which the tree is being printed</param>
150 /// <param name="node">The current node that should be printed to the StringBuilder</param>
151 internal virtual void PrintNode(StringBuilder text, TreeNode node)
153 IndentLine(text);
155 this.BeforeAppend(node, text);
156 text.Append(node.Text.ToString());
157 this.AfterAppend(node, text);
159 PrintChildren(text, node);
162 /// <summary>
163 /// Called to recursively visit the child nodes of the current TreeNode.
164 /// </summary>
165 /// <param name="text">The StringBuilder into which the tree is being printed</param>
166 /// <param name="node">The current node</param>
167 internal virtual void PrintChildren(StringBuilder text, TreeNode node)
169 _scopes.Add(node);
170 node.Position = 0;
171 foreach (TreeNode childNode in node.Children)
173 text.AppendLine();
174 node.Position++;
175 PrintNode(text, childNode);
178 _scopes.RemoveAt(_scopes.Count - 1);
181 #endregion
183 #region Private Implementation
185 private void IndentLine(StringBuilder text)
187 int idx = 0;
188 for (int scopeIdx = 0; scopeIdx < _scopes.Count; scopeIdx++)
190 TreeNode parentScope = _scopes[scopeIdx];
191 if (!_showLines || (parentScope.Position == parentScope.Children.Count && scopeIdx != _scopes.Count - 1))
193 text.Append(' ');
195 else
197 text.Append(_verticals);
200 idx++;
201 if (_scopes.Count == idx && _showLines)
203 text.Append(_horizontals);
205 else
207 text.Append(' ');
212 #endregion