Welcome to mirror list, hosted at ThFree Co, Russian Federation.

TreePrinter.cs « Utils « Common « Data « System « System.Data.Entity « referencesource « class « mcs - github.com/mono/mono.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: fd2ab6566ee509dbb6cca3cb1860295c2fc454c3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
//---------------------------------------------------------------------
// <copyright file="TreePrinter.cs" company="Microsoft">
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>
//
// @owner  [....]
//---------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Text;

namespace System.Data.Common.Utils
{
    /// <summary>
    /// Represents a node in a hierarchical collection of information strings. 
    /// Intended as a common way mechanism to represent tree structures for debugging (using the TreePrinter class).
    /// A node consists of a string (represented as a StringBuilder), its collection of child nodes, and an optional Tag value.
    /// </summary>
    internal class TreeNode
    {
        private StringBuilder _text;
        private List<TreeNode> _children = new List<TreeNode>();
        private int _position;

        // Default constructor
        internal TreeNode()
        {
            _text = new StringBuilder();
        }

        /// <summary>
        /// Constructs a new TreeNode with the specified text, tag value and child nodes
        /// </summary>
        /// <param name="text">The initial value of the new node's text</param>
        /// <param name="children">An optional list of initial child nodes</param>
        internal TreeNode(string text, params TreeNode[] children)
        {
            if (string.IsNullOrEmpty(text))
            {
                _text = new StringBuilder();
            }
            else
            {
                _text = new StringBuilder(text);
            }

            if (children != null)
            {
                _children.AddRange(children);
            }
        }

        // IEnumerable convenience constructors
        internal TreeNode(string text, List<TreeNode> children)
            : this(text)
        {
            if (children != null)
            {
                _children.AddRange(children);
            }
        }
                
        // 'public' properties

        /// <summary>
        /// The current text of this node.
        /// </summary>
        internal StringBuilder Text { get { return _text; } }

        /// <summary>
        /// The collection of child nodes for this node, which may be empty.
        /// </summary>
        internal IList<TreeNode> Children { get { return _children; } }

        // Used only by the TreePrinter when generating the output string
        internal int Position { get { return _position; } set { _position = value; } }
    }

    /// <summary>
    /// Generates a formatted string from a hierarchy of tree nodes. Derived types may override
    /// the PreProcess, Before/AfterAppend, Print, PrintNode and PrintChildren methods to add
    /// specific functionality at particular points in process of building the string.
    /// </summary>
    internal abstract class TreePrinter
    {
        #region Private Instance Members

        private List<TreeNode> _scopes = new List<TreeNode>();
        private bool _showLines = true;
        private char _horizontals = '_';
        private char _verticals = '|';

        #endregion

        #region 'Public' API

        /// <summary>
        /// Entry point method for the TreePrinter
        /// </summary>
        /// <param name="node">The TreeNode instance that is the root of the tree to be printed</param>
        /// <returns>A string representation of the specified tree</returns>
        internal virtual string Print(TreeNode node)
        {
             this.PreProcess(node);

            StringBuilder text = new StringBuilder();
            PrintNode(text, node);
            return text.ToString();
        }

        #endregion

        #region 'Protected' API

        // 'protected' constructor
        internal TreePrinter() { }

        // 'protected' API that may be overriden to customize printing
        
        /// <summary>
        /// Called once on the root of the tree before printing begins
        /// </summary>
        /// <param name="node">The TreeNode that is the root of the tree</param>
        internal virtual void PreProcess(TreeNode node) { }

        /// <summary>
        /// Called once for every node after indentation, connecting lines and the node's text value
        /// have been added to the output but before the line suffix (if any) has been added.
        /// </summary>
        /// <param name="node">The current node</param>
        /// <param name="text">The StringBuilder into which the tree is being printed</param>
        internal virtual void AfterAppend(TreeNode node, StringBuilder text) { }

        /// <summary>
        /// Called once for every node immediately after the line prefix (if any) and appropriate
        /// indentation and connecting lines have been added to the output but before the node's
        /// text value has been added.
        /// </summary>
        /// <param name="node">The current node</param>
        /// <param name="text">The StringBuilder into which the tree is being printed</param>
        internal virtual void BeforeAppend(TreeNode node, StringBuilder text) { }

        /// <summary>
        /// The recursive step of the printing process, called once for each TreeNode in the tree
        /// </summary>
        /// <param name="text">The StringBuilder into which the tree is being printed</param>
        /// <param name="node">The current node that should be printed to the StringBuilder</param>
        internal virtual void PrintNode(StringBuilder text, TreeNode node)
        {
            IndentLine(text);
            
            this.BeforeAppend(node, text);
            text.Append(node.Text.ToString());
            this.AfterAppend(node, text);

            PrintChildren(text, node);
        }

        /// <summary>
        /// Called to recursively visit the child nodes of the current TreeNode.
        /// </summary>
        /// <param name="text">The StringBuilder into which the tree is being printed</param>
        /// <param name="node">The current node</param>
        internal virtual void PrintChildren(StringBuilder text, TreeNode node)
        {
            _scopes.Add(node);
            node.Position = 0;
            foreach (TreeNode childNode in node.Children)
            {
                text.AppendLine();
                node.Position++;
                PrintNode(text, childNode);
            }

            _scopes.RemoveAt(_scopes.Count - 1);
        }

        #endregion

        #region Private Implementation

        private void IndentLine(StringBuilder text)
        {
            int idx = 0;
            for (int scopeIdx = 0; scopeIdx < _scopes.Count; scopeIdx++)
            {
                TreeNode parentScope = _scopes[scopeIdx];
                if (!_showLines || (parentScope.Position == parentScope.Children.Count && scopeIdx != _scopes.Count - 1))
                {
                    text.Append(' ');
                }
                else
                {
                    text.Append(_verticals);
                }

                idx++;
                if (_scopes.Count == idx && _showLines)
                {
                    text.Append(_horizontals);
                }
                else
                {
                    text.Append(' ');
                }
            }
        }

        #endregion
    }
}