Split TreeNode, TreeStyle and TreeBuilder into seperate files

This commit is contained in:
tznind
2021-03-08 10:18:11 +00:00
parent db322b27ef
commit 7cb3812c19
4 changed files with 275 additions and 259 deletions

View File

@@ -0,0 +1,155 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace Terminal.Gui {
/// <summary>
/// Interface for supplying data to a <see cref="TreeView{T}"/> on demand as root level nodes
/// are expanded by the user
/// </summary>
public interface ITreeBuilder<T> {
/// <summary>
/// Returns true if <see cref="CanExpand"/> is implemented by this class
/// </summary>
/// <value></value>
bool SupportsCanExpand { get; }
/// <summary>
/// Returns true/false for whether a model has children. This method should be implemented
/// when <see cref="GetChildren"/> is an expensive operation otherwise
/// <see cref="SupportsCanExpand"/> should return false (in which case this method will not
/// be called)
/// </summary>
/// <remarks>Only implement this method if you have a very fast way of determining whether
/// an object can have children e.g. checking a Type (directories can always be expanded)
/// </remarks>
/// <param name="toExpand"></param>
/// <returns></returns>
bool CanExpand (T toExpand);
/// <summary>
/// Returns all children of a given <paramref name="forObject"/> which should be added to the
/// tree as new branches underneath it
/// </summary>
/// <param name="forObject"></param>
/// <returns></returns>
IEnumerable<T> GetChildren (T forObject);
}
/// <summary>
/// Abstract implementation of <see cref="ITreeBuilder{T}"/>.
/// </summary>
public abstract class TreeBuilder<T> : ITreeBuilder<T> {
/// <inheritdoc/>
public bool SupportsCanExpand { get; protected set; } = false;
/// <summary>
/// Override this method to return a rapid answer as to whether <see cref="GetChildren(T)"/>
/// returns results. If you are implementing this method ensure you passed true in base
/// constructor or set <see cref="SupportsCanExpand"/>
/// </summary>
/// <param name="toExpand"></param>
/// <returns></returns>
public virtual bool CanExpand (T toExpand)
{
return GetChildren (toExpand).Any ();
}
/// <inheritdoc/>
public abstract IEnumerable<T> GetChildren (T forObject);
/// <summary>
/// Constructs base and initializes <see cref="SupportsCanExpand"/>
/// </summary>
/// <param name="supportsCanExpand">Pass true if you intend to
/// implement <see cref="CanExpand(T)"/> otherwise false</param>
public TreeBuilder (bool supportsCanExpand)
{
SupportsCanExpand = supportsCanExpand;
}
}
/// <summary>
/// <see cref="ITreeBuilder{T}"/> implementation for <see cref="ITreeNode"/> objects
/// </summary>
public class TreeNodeBuilder : TreeBuilder<ITreeNode> {
/// <summary>
/// Initialises a new instance of builder for any model objects of
/// Type <see cref="ITreeNode"/>
/// </summary>
public TreeNodeBuilder () : base (false)
{
}
/// <summary>
/// Returns <see cref="ITreeNode.Children"/> from <paramref name="model"/>
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
public override IEnumerable<ITreeNode> GetChildren (ITreeNode model)
{
return model.Children;
}
}
/// <summary>
/// Implementation of <see cref="ITreeBuilder{T}"/> that uses user defined functions
/// </summary>
public class DelegateTreeBuilder<T> : TreeBuilder<T> {
private Func<T, IEnumerable<T>> childGetter;
private Func<T, bool> canExpand;
/// <summary>
/// Constructs an implementation of <see cref="ITreeBuilder{T}"/> that calls the user
/// defined method <paramref name="childGetter"/> to determine children
/// </summary>
/// <param name="childGetter"></param>
/// <returns></returns>
public DelegateTreeBuilder (Func<T, IEnumerable<T>> childGetter) : base (false)
{
this.childGetter = childGetter;
}
/// <summary>
/// Constructs an implementation of <see cref="ITreeBuilder{T}"/> that calls the user
/// defined method <paramref name="childGetter"/> to determine children
/// and <paramref name="canExpand"/> to determine expandability
/// </summary>
/// <param name="childGetter"></param>
/// <param name="canExpand"></param>
/// <returns></returns>
public DelegateTreeBuilder (Func<T, IEnumerable<T>> childGetter, Func<T, bool> canExpand) : base (true)
{
this.childGetter = childGetter;
this.canExpand = canExpand;
}
/// <summary>
/// Returns whether a node can be expanded based on the delegate passed during construction
/// </summary>
/// <param name="toExpand"></param>
/// <returns></returns>
public override bool CanExpand (T toExpand)
{
return canExpand?.Invoke (toExpand) ?? base.CanExpand (toExpand);
}
/// <summary>
/// Returns children using the delegate method passed during construction
/// </summary>
/// <param name="forObject"></param>
/// <returns></returns>
public override IEnumerable<T> GetChildren (T forObject)
{
return childGetter.Invoke (forObject);
}
}
}

View File

@@ -0,0 +1,73 @@
using System.Collections.Generic;
namespace Terminal.Gui {
/// <summary>
/// Interface to implement when you want the regular (non generic) <see cref="TreeView"/>
/// to automatically determine children for your class (without having to specify
/// an <see cref="ITreeBuilder{T}"/>)
/// </summary>
public interface ITreeNode {
/// <summary>
/// Text to display when rendering the node
/// </summary>
string Text { get; set; }
/// <summary>
/// The children of your class which should be rendered underneath it when expanded
/// </summary>
/// <value></value>
IList<ITreeNode> Children { get; }
/// <summary>
/// Optionally allows you to store some custom data/class here.
/// </summary>
object Tag { get; set; }
}
/// <summary>
/// Simple class for representing nodes, use with regular (non generic) <see cref="TreeView"/>.
/// </summary>
public class TreeNode : ITreeNode {
/// <summary>
/// Children of the current node
/// </summary>
/// <returns></returns>
public virtual IList<ITreeNode> Children { get; set; } = new List<ITreeNode> ();
/// <summary>
/// Text to display in tree node for current entry
/// </summary>
/// <value></value>
public virtual string Text { get; set; }
/// <summary>
/// Optionally allows you to store some custom data/class here.
/// </summary>
public object Tag { get; set; }
/// <summary>
/// returns <see cref="Text"/>
/// </summary>
/// <returns></returns>
public override string ToString ()
{
return Text ?? "Unamed Node";
}
/// <summary>
/// Initialises a new instance with no <see cref="Text"/>
/// </summary>
public TreeNode ()
{
}
/// <summary>
/// Initialises a new instance and sets starting <see cref="Text"/>
/// </summary>
public TreeNode (string text)
{
Text = text;
}
}
}

View File

@@ -0,0 +1,47 @@
using System;
namespace Terminal.Gui {
/// <summary>
/// Defines rendering options that affect how the tree is displayed
/// </summary>
public class TreeStyle {
/// <summary>
/// True to render vertical lines under expanded nodes to show which node belongs to which
/// parent. False to use only whitespace
/// </summary>
/// <value></value>
public bool ShowBranchLines { get; set; } = true;
/// <summary>
/// Symbol to use for branch nodes that can be expanded to indicate this to the user.
/// Defaults to '+'. Set to null to hide
/// </summary>
public Rune? ExpandableSymbol { get; set; } = '+';
/// <summary>
/// Symbol to use for branch nodes that can be collapsed (are currently expanded).
/// Defaults to '-'. Set to null to hide
/// </summary>
public Rune? CollapseableSymbol { get; set; } = '-';
/// <summary>
/// Set to true to highlight expand/collapse symbols in hot key color
/// </summary>
public bool ColorExpandSymbol { get; set; }
/// <summary>
/// Invert console colours used to render the expand symbol
/// </summary>
public bool InvertExpandSymbolColors { get; set; }
/// <summary>
/// True to leave the last row of the control free for overwritting (e.g. by a scrollbar)
/// When True scrolling will be triggered on the second last row of the control rather than
/// the last.
/// </summary>
/// <value></value>
public bool LeaveLastRow { get; set; }
}
}

View File

@@ -9,221 +9,6 @@ using NStack;
namespace Terminal.Gui {
/// <summary>
/// Interface to implement when you want the regular (non generic) <see cref="TreeView"/>
/// to automatically determine children for your class (without having to specify
/// an <see cref="ITreeBuilder{T}"/>)
/// </summary>
public interface ITreeNode {
/// <summary>
/// Text to display when rendering the node
/// </summary>
string Text { get; set; }
/// <summary>
/// The children of your class which should be rendered underneath it when expanded
/// </summary>
/// <value></value>
IList<ITreeNode> Children { get; }
/// <summary>
/// Optionally allows you to store some custom data/class here.
/// </summary>
object Tag { get; set; }
}
/// <summary>
/// Simple class for representing nodes, use with regular (non generic) <see cref="TreeView"/>.
/// </summary>
public class TreeNode : ITreeNode {
/// <summary>
/// Children of the current node
/// </summary>
/// <returns></returns>
public virtual IList<ITreeNode> Children { get; set; } = new List<ITreeNode> ();
/// <summary>
/// Text to display in tree node for current entry
/// </summary>
/// <value></value>
public virtual string Text { get; set; }
/// <summary>
/// Optionally allows you to store some custom data/class here.
/// </summary>
public object Tag { get; set; }
/// <summary>
/// returns <see cref="Text"/>
/// </summary>
/// <returns></returns>
public override string ToString ()
{
return Text ?? "Unamed Node";
}
/// <summary>
/// Initialises a new instance with no <see cref="Text"/>
/// </summary>
public TreeNode ()
{
}
/// <summary>
/// Initialises a new instance and sets starting <see cref="Text"/>
/// </summary>
public TreeNode (string text)
{
Text = text;
}
}
/// <summary>
/// Interface for supplying data to a <see cref="TreeView{T}"/> on demand as root level nodes
/// are expanded by the user
/// </summary>
public interface ITreeBuilder<T> {
/// <summary>
/// Returns true if <see cref="CanExpand"/> is implemented by this class
/// </summary>
/// <value></value>
bool SupportsCanExpand { get; }
/// <summary>
/// Returns true/false for whether a model has children. This method should be implemented
/// when <see cref="GetChildren"/> is an expensive operation otherwise
/// <see cref="SupportsCanExpand"/> should return false (in which case this method will not
/// be called)
/// </summary>
/// <remarks>Only implement this method if you have a very fast way of determining whether
/// an object can have children e.g. checking a Type (directories can always be expanded)
/// </remarks>
/// <param name="toExpand"></param>
/// <returns></returns>
bool CanExpand (T toExpand);
/// <summary>
/// Returns all children of a given <paramref name="forObject"/> which should be added to the
/// tree as new branches underneath it
/// </summary>
/// <param name="forObject"></param>
/// <returns></returns>
IEnumerable<T> GetChildren (T forObject);
}
/// <summary>
/// Abstract implementation of <see cref="ITreeBuilder{T}"/>.
/// </summary>
public abstract class TreeBuilder<T> : ITreeBuilder<T> {
/// <inheritdoc/>
public bool SupportsCanExpand { get; protected set; } = false;
/// <summary>
/// Override this method to return a rapid answer as to whether <see cref="GetChildren(T)"/>
/// returns results. If you are implementing this method ensure you passed true in base
/// constructor or set <see cref="SupportsCanExpand"/>
/// </summary>
/// <param name="toExpand"></param>
/// <returns></returns>
public virtual bool CanExpand (T toExpand)
{
return GetChildren (toExpand).Any ();
}
/// <inheritdoc/>
public abstract IEnumerable<T> GetChildren (T forObject);
/// <summary>
/// Constructs base and initializes <see cref="SupportsCanExpand"/>
/// </summary>
/// <param name="supportsCanExpand">Pass true if you intend to
/// implement <see cref="CanExpand(T)"/> otherwise false</param>
public TreeBuilder (bool supportsCanExpand)
{
SupportsCanExpand = supportsCanExpand;
}
}
/// <summary>
/// <see cref="ITreeBuilder{T}"/> implementation for <see cref="ITreeNode"/> objects
/// </summary>
public class TreeNodeBuilder : TreeBuilder<ITreeNode> {
/// <summary>
/// Initialises a new instance of builder for any model objects of
/// Type <see cref="ITreeNode"/>
/// </summary>
public TreeNodeBuilder () : base (false)
{
}
/// <summary>
/// Returns <see cref="ITreeNode.Children"/> from <paramref name="model"/>
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
public override IEnumerable<ITreeNode> GetChildren (ITreeNode model)
{
return model.Children;
}
}
/// <summary>
/// Implementation of <see cref="ITreeBuilder{T}"/> that uses user defined functions
/// </summary>
public class DelegateTreeBuilder<T> : TreeBuilder<T> {
private Func<T, IEnumerable<T>> childGetter;
private Func<T, bool> canExpand;
/// <summary>
/// Constructs an implementation of <see cref="ITreeBuilder{T}"/> that calls the user
/// defined method <paramref name="childGetter"/> to determine children
/// </summary>
/// <param name="childGetter"></param>
/// <returns></returns>
public DelegateTreeBuilder (Func<T, IEnumerable<T>> childGetter) : base (false)
{
this.childGetter = childGetter;
}
/// <summary>
/// Constructs an implementation of <see cref="ITreeBuilder{T}"/> that calls the user
/// defined method <paramref name="childGetter"/> to determine children
/// and <paramref name="canExpand"/> to determine expandability
/// </summary>
/// <param name="childGetter"></param>
/// <param name="canExpand"></param>
/// <returns></returns>
public DelegateTreeBuilder (Func<T, IEnumerable<T>> childGetter, Func<T, bool> canExpand) : base (true)
{
this.childGetter = childGetter;
this.canExpand = canExpand;
}
/// <summary>
/// Returns whether a node can be expanded based on the delegate passed during construction
/// </summary>
/// <param name="toExpand"></param>
/// <returns></returns>
public override bool CanExpand (T toExpand)
{
return canExpand?.Invoke (toExpand) ?? base.CanExpand (toExpand);
}
/// <summary>
/// Returns children using the delegate method passed during construction
/// </summary>
/// <param name="forObject"></param>
/// <returns></returns>
public override IEnumerable<T> GetChildren (T forObject)
{
return childGetter.Invoke (forObject);
}
}
/// <summary>
/// Interface for all non generic members of <see cref="TreeView{T}"/>
/// </summary>
@@ -263,50 +48,6 @@ namespace Terminal.Gui {
}
}
/// <summary>
/// Defines rendering options that affect how the tree is displayed
/// </summary>
public class TreeStyle {
/// <summary>
/// True to render vertical lines under expanded nodes to show which node belongs to which
/// parent. False to use only whitespace
/// </summary>
/// <value></value>
public bool ShowBranchLines { get; set; } = true;
/// <summary>
/// Symbol to use for branch nodes that can be expanded to indicate this to the user.
/// Defaults to '+'. Set to null to hide
/// </summary>
public Rune? ExpandableSymbol { get; set; } = '+';
/// <summary>
/// Symbol to use for branch nodes that can be collapsed (are currently expanded).
/// Defaults to '-'. Set to null to hide
/// </summary>
public Rune? CollapseableSymbol { get; set; } = '-';
/// <summary>
/// Set to true to highlight expand/collapse symbols in hot key color
/// </summary>
public bool ColorExpandSymbol { get; set; }
/// <summary>
/// Invert console colours used to render the expand symbol
/// </summary>
public bool InvertExpandSymbolColors { get; set; }
/// <summary>
/// True to leave the last row of the control free for overwritting (e.g. by a scrollbar)
/// When True scrolling will be triggered on the second last row of the control rather than
/// the last.
/// </summary>
/// <value></value>
public bool LeaveLastRow { get; set; }
}
/// <summary>
/// Hierarchical tree view with expandable branches. Branch objects are dynamically determined
/// when expanded using a user defined <see cref="ITreeBuilder{T}"/>