238 lines
4.8 KiB
C#
238 lines
4.8 KiB
C#
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<ColumnView> Columns { get; set; }
|
|
public Dictionary<string, Item> Items { get; set; }
|
|
}
|
|
|
|
private readonly List<ColumnView> _columns = new();
|
|
private readonly HashSet<TreeNode> _selectingNodes = new();
|
|
private readonly Dictionary<TreeItem, TreeNode> _mapper = new();
|
|
private readonly Dictionary<string, Item> _items = new();
|
|
|
|
public HashSet<TreeNode> SelectingNodes => _selectingNodes;
|
|
|
|
public override void _Ready()
|
|
{
|
|
Columns = 1;
|
|
SetColumnTitlesVisible(true);
|
|
|
|
SetColumnTitle(0, "文件名");
|
|
SetColumnCustomMinimumWidth(0, 400);
|
|
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<MainTreeData>(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;
|
|
}
|
|
}
|