miduo_client/Assets/Scripts/Editor/ExcelTool/TreeView/TreeElementUtility.cs

164 lines
4.4 KiB
C#

using System;
using System.Collections.Generic;
namespace GameEditor.Core.TreeViewBase
{
public static class TreeElementUtility
{
public static void TreeToList<T>(T root, IList<T> result) where T : TreeElement
{
if (result == null)
throw new NullReferenceException("The input 'IList<T> result' list is null");
result.Clear();
Stack<T> stack = new Stack<T>();
stack.Push(root);
while (stack.Count > 0)
{
T current = stack.Pop();
result.Add(current);
if (current.children != null && current.children.Count > 0)
{
for (int i = current.children.Count - 1; i >= 0; i--)
{
stack.Push((T)current.children[i]);
}
}
}
}
public static T ListToTree<T>(IList<T> list) where T : TreeElement
{
// Validate input
ValidateDepthValues (list);
// Clear old states
foreach (var element in list)
{
element.parent = null;
element.children = null;
}
// Set child and parent references using depth info
for (int parentIndex = 0; parentIndex < list.Count; parentIndex++)
{
var parent = list[parentIndex];
bool alreadyHasValidChildren = parent.children != null;
if (alreadyHasValidChildren)
continue;
int parentDepth = parent.depth;
int childCount = 0;
// Count children based depth value, we are looking at children until it's the same depth as this object
for (int i = parentIndex + 1; i < list.Count; i++)
{
if (list[i].depth == parentDepth + 1)
childCount++;
if (list[i].depth <= parentDepth)
break;
}
// Fill child array
List<TreeElement> childList = null;
if (childCount != 0)
{
childList = new List<TreeElement>(childCount); // Allocate once
childCount = 0;
for (int i = parentIndex + 1; i < list.Count; i++)
{
if (list[i].depth == parentDepth + 1)
{
list[i].parent = parent;
childList.Add(list[i]);
childCount++;
}
if (list[i].depth <= parentDepth)
break;
}
}
parent.children = childList;
}
return list[0];
}
// Check state of input list
public static void ValidateDepthValues<T>(IList<T> list) where T : TreeElement
{
if (list.Count == 0)
throw new ArgumentException("list should have items, count is 0, check before calling ValidateDepthValues", "list");
if (list[0].depth != -1)
throw new ArgumentException("list item at index 0 should have a depth of -1 (since this should be the hidden root of the tree). Depth is: " + list[0].depth, "list");
for (int i = 0; i < list.Count - 1; i++)
{
int depth = list[i].depth;
int nextDepth = list[i + 1].depth;
if (nextDepth > depth && nextDepth - depth > 1)
throw new ArgumentException(string.Format("Invalid depth info in input list. Depth cannot increase more than 1 per row. Index {0} has depth {1} while index {2} has depth {3}", i, depth, i + 1, nextDepth));
}
for (int i = 1; i < list.Count; ++i)
if (list[i].depth < 0)
throw new ArgumentException("Invalid depth value for item at index " + i + ". Only the first item (the root) should have depth below 0.");
if (list.Count > 1 && list[1].depth != 0)
throw new ArgumentException("Input list item at index 1 is assumed to have a depth of 0", "list");
}
// For updating depth values below any given element e.g after reparenting elements
public static void UpdateDepthValues<T>(T root) where T : TreeElement
{
if (root == null)
throw new ArgumentNullException("root", "The root is null");
if (!root.hasChildren)
return;
Stack<TreeElement> stack = new Stack<TreeElement>();
stack.Push(root);
while (stack.Count > 0)
{
TreeElement current = stack.Pop();
if (current.children != null)
{
foreach (var child in current.children)
{
child.depth = current.depth + 1;
stack.Push(child);
}
}
}
}
// Returns true if there is an ancestor of child in the elements list
static bool IsChildOf<T>(T child, IList<T> elements) where T : TreeElement
{
while (child != null)
{
child = (T)child.parent;
if (elements.Contains(child))
return true;
}
return false;
}
public static IList<T> FindCommonAncestorsWithinList<T>(IList<T> elements) where T : TreeElement
{
if (elements.Count == 1)
return new List<T>(elements);
List<T> result = new List<T>(elements);
result.RemoveAll(g => IsChildOf(g, elements));
return result;
}
}
}