using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.IO; using System.Linq; using Godot; using Learn.Models; using Learn.Parsers; using Newtonsoft.Json; namespace Learn.Component; public partial class MainTreePanel : Tree { public class ColumnView { public string Name { get; set; } public int Width { get; set; } } public class MainTreeData { public List Columns { get; set; } public Dictionary Items { get; set; } } private readonly List _columns = new(); private readonly HashSet _selectingNodes = new(); private readonly Dictionary _mapper = new(); private readonly Dictionary _items = new(); public HashSet SelectingNodes => _selectingNodes; public override void _Ready() { Columns = 1; SetColumnTitlesVisible(true); SetColumnTitle(0, "文件名"); SetColumnCustomMinimumWidth(0, 500); SetColumnExpand(0, true); MultiSelected += OnMultiSelected; UpdateColumns(); } public void AddColumn(string columnName, int index, int width) { if (string.IsNullOrEmpty(columnName)) return; var targets = _columns.Where(column => column.Name == columnName).ToList(); if (index < 0) index = _columns.Count; if (width < 0) width = 400; if (targets.Any()) { targets.First().Width = width; } else { _columns.Insert(index, new ColumnView { Name = columnName, Width = width }); } UpdateColumns(); } public void RemoveColumn(string columnName) { if (string.IsNullOrEmpty(columnName)) return; _columns.RemoveAll(column => column.Name == columnName); UpdateColumns(); } public void ClearColumns() { _columns.Clear(); UpdateColumns(); } public void UpdateColumns() { Columns = _columns.Count + 1; int index = 1; foreach (var column in _columns) { SetColumnTitle(index, column.Name); SetColumnCustomMinimumWidth(index, column.Width); SetColumnExpand(index, true); index += 1; } foreach (var kv in _mapper) { index = 1; foreach (var column in _columns) { if (!kv.Value.TryGetValue(column.Name, out var value, out _)) { value = ""; } kv.Key.SetText(index, value); kv.Key.SetTextAlignment(index, HorizontalAlignment.Center); index += 1; } } } private void OnMultiSelected(TreeItem item, long column, bool selected) { for (int i = 0; i < Columns; i++) { if (i == column ? selected : item.IsSelected(i)) { _selectingNodes.Add(_mapper[item]); return; } } _selectingNodes.Remove(_mapper[item]); } private TreeItem CreateNode(TreeItem father, Item item) { var node = CreateItem(father); var name = Path.GetFileName(item.MainInfo[ItemFields.MainKey_Path]); node.SetText(0, name); return node; } private Item InitItem(string path, bool isDir) { if (_items.TryGetValue(path, out var item)) { return item; } item = new Item { MainInfo = { [ItemFields.MainKey_IsDir] = isDir ? "True" : "False", [ItemFields.MainKey_Path] = path } }; _items.Add(path, item); return item; } public void ClearData() { foreach (var item in _items.Values) { item.Info.Clear(); } UpdateColumns(); } public void LoadData(string dataPath) { var data = JsonConvert.DeserializeObject(File.ReadAllText(dataPath)); foreach (var kv in data.Items) { if (string.IsNullOrEmpty(kv.Key)) continue; _items[kv.Key] = kv.Value; } _columns.Clear(); foreach (var column in data.Columns) { _columns.Add(column); } UpdateColumns(); } public void SaveData(string dataPath) { var data = new MainTreeData { Columns = _columns.ToList(), Items = _items }; File.WriteAllText(dataPath, JsonConvert.SerializeObject(data, Formatting.Indented)); } public void Scan(string path) { Clear(); _mapper.Clear(); _selectingNodes.Clear(); TreeItem root = CreateItem(); _mapper[root] = new TreeNode(null); BuildTree(root, path); } public bool Query(TreeItem item, out TreeNode node) { return _mapper.TryGetValue(item, out node); } private bool BuildTree(TreeItem current, string path) { var isEmpty = true; var node = _mapper[current]; foreach (var filePath in Directory.GetFiles(path)) { isEmpty = false; var item = InitItem(filePath, false); var childNode = new TreeNode(item); node.AddNode(childNode); var child = CreateNode(current, item); _mapper[child] = childNode; } foreach (var subDirPath in Directory.GetDirectories(path)) { var item = InitItem(subDirPath, true); var childNode = new TreeNode(item); node.AddNode(childNode); var child = CreateNode(current, item); _mapper[child] = childNode; if (BuildTree(child, subDirPath)) { _mapper.Remove(child); child.Free(); } else { isEmpty = false; } } return isEmpty; } }