添加持久化保存和日志

This commit is contained in:
limil 2025-12-20 22:29:24 +08:00
parent c3d826991c
commit 89de0e2ebd
7 changed files with 2086 additions and 23 deletions

View File

@ -2,6 +2,7 @@ using System.Collections.Generic;
using System.IO; using System.IO;
using Godot; using Godot;
using Learn.Models; using Learn.Models;
using Newtonsoft.Json;
namespace Learn.Component; namespace Learn.Component;
@ -11,6 +12,7 @@ public partial class MainTreePanel : Tree
private readonly HashSet<string> _columns = new(); private readonly HashSet<string> _columns = new();
private readonly HashSet<TreeNode> _selectingNodes = new(); private readonly HashSet<TreeNode> _selectingNodes = new();
private readonly Dictionary<TreeItem, TreeNode> _mapper = new(); private readonly Dictionary<TreeItem, TreeNode> _mapper = new();
private readonly Dictionary<string, Item> _items = new();
public HashSet<TreeNode> SelectingNodes => _selectingNodes; public HashSet<TreeNode> SelectingNodes => _selectingNodes;
@ -80,21 +82,57 @@ public partial class MainTreePanel : Tree
private TreeItem CreateNode(TreeItem father, Item item) private TreeItem CreateNode(TreeItem father, Item item)
{ {
var node = CreateItem(father); var node = CreateItem(father);
node.SetText(0, item.Info["Name"]); var name = Path.GetFileName(item.MainInfo["Path"]);
node.SetText(0, name);
return node; return node;
} }
private Item InitItem(string path, bool isDir) private Item InitItem(string path, bool isDir)
{ {
var name = Path.GetFileName(path); if (_items.TryGetValue(path, out var item))
var item = new Item(); {
item.Info["Name"] = name; return item;
item.Info["IsDir"] = isDir ? "True" : "False"; }
item.Info["Path"] = path; item = new Item
{
MainInfo =
{
["IsDir"] = isDir ? "True" : "False",
["Path"] = path
}
};
_items.Add(path, item);
return item; return item;
} }
public void Build(string path)
public void ClearData()
{
foreach (var item in _items.Values)
{
item.Info.Clear();
}
UpdateColumns();
}
public void LoadData(string dataPath)
{
var items = JsonConvert.DeserializeObject<Dictionary<string, Item>>(File.ReadAllText(dataPath));
foreach (var kv in items)
{
if (string.IsNullOrEmpty(kv.Key)) continue;
_items[kv.Key] = kv.Value;
}
UpdateColumns();
}
public void SaveData(string dataPath)
{
File.WriteAllText(dataPath, JsonConvert.SerializeObject(_items, Formatting.Indented));
}
public void Scan(string path)
{ {
Clear(); Clear();
_mapper.Clear(); _mapper.Clear();

View File

@ -78,7 +78,7 @@ public partial class NodeInfoEditPanel : Tree
OnNodesChanged(); OnNodesChanged();
} }
private void OnNodesChanged() public void OnNodesChanged()
{ {
Clear(); Clear();
_nodeKeys.Clear(); _nodeKeys.Clear();
@ -96,6 +96,7 @@ public partial class NodeInfoEditPanel : Tree
node.SetEditable(ValueColumn, true); node.SetEditable(ValueColumn, true);
_nodeKeys.Add(node, key); _nodeKeys.Add(node, key);
} }
OnNodeInfoEdited?.Invoke();
} }
public void AddKeyValue() public void AddKeyValue()

View File

@ -4,4 +4,7 @@
<TargetFramework Condition=" '$(GodotTargetPlatform)' == 'android' ">net9.0</TargetFramework> <TargetFramework Condition=" '$(GodotTargetPlatform)' == 'android' ">net9.0</TargetFramework>
<EnableDynamicLoading>true</EnableDynamicLoading> <EnableDynamicLoading>true</EnableDynamicLoading>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.4" />
</ItemGroup>
</Project> </Project>

46
Main.cs
View File

@ -1,3 +1,4 @@
using System.IO;
using Godot; using Godot;
using System.Linq; using System.Linq;
using Learn.Component; using Learn.Component;
@ -6,8 +7,11 @@ public partial class Main : Node
{ {
[ExportGroup("文件夹操作")][Export] private FileDirSelector _dirSelector; [ExportGroup("文件夹操作")][Export] private FileDirSelector _dirSelector;
[ExportGroup("操作面板")][Export] private RichTextLabel _console;
[ExportGroup("操作面板")][Export] private Button _openDirButton; [ExportGroup("操作面板")][Export] private Button _openDirButton;
[ExportGroup("操作面板")][Export] private Button _doParseButton; [ExportGroup("操作面板")][Export] private Button _doParseButton;
[ExportGroup("操作面板")][Export] private Button _saveButton;
[ExportGroup("操作面板")][Export] private Button _resetButton;
[ExportGroup("编辑面板")][Export] private NodeInfoEditPanel _nodeInfoEditPanel; [ExportGroup("编辑面板")][Export] private NodeInfoEditPanel _nodeInfoEditPanel;
[ExportGroup("编辑面板")][Export] private Button _addKeyButton; [ExportGroup("编辑面板")][Export] private Button _addKeyButton;
@ -22,6 +26,18 @@ public partial class Main : Node
private bool _refreshPanels; private bool _refreshPanels;
private void Log(string log)
{
var time = Time.GetTimeDictFromSystem();
string timestamp = $"[{time["hour"]:D2}:{time["minute"]:D2}:{time["second"]:D2}]";
string bbcode = $"[color=#888888]{timestamp}[/color] " +
$"{log}\n";
_console.AppendText(bbcode);
_console.ScrollToLine(_console.GetLineCount());
}
public override void _Ready() public override void _Ready()
{ {
_nodeInfoEditPanel.OnNodeInfoEdited += _mainTreePanel.UpdateColumns; _nodeInfoEditPanel.OnNodeInfoEdited += _mainTreePanel.UpdateColumns;
@ -33,8 +49,17 @@ public partial class Main : Node
_removeColumnButton.Pressed += () => _mainTreePanel.RemoveColumn(_columnText.Text); _removeColumnButton.Pressed += () => _mainTreePanel.RemoveColumn(_columnText.Text);
// 功能区 // 功能区
_openDirButton.Pressed += OpenDir; _openDirButton.Pressed += ScanDir;
_doParseButton.Pressed += DoParse; _doParseButton.Pressed += DoParse;
_saveButton.Pressed += DoSave;
_resetButton.Pressed += DoReset;
// 先加载保存的数据
if (File.Exists(DataPath))
{
_mainTreePanel.LoadData(DataPath);
Log("加载成功:" + DataPath);
}
} }
@ -49,14 +74,14 @@ public partial class Main : Node
} }
#region Commands #region Commands
private async void OpenDir() private async void ScanDir()
{ {
var path = await _dirSelector.SelectFolderAsync(); var path = await _dirSelector.SelectFolderAsync();
if (string.IsNullOrEmpty(path)) if (string.IsNullOrEmpty(path))
{ {
return; return;
} }
_mainTreePanel.Build(path); _mainTreePanel.Scan(path);
_refreshPanels = true; _refreshPanels = true;
} }
@ -65,5 +90,20 @@ public partial class Main : Node
// todo; // todo;
} }
private const string DataPath = "data.json";
private void DoSave()
{
_mainTreePanel.SaveData(DataPath);
Log("保存成功");
}
private void DoReset()
{
_mainTreePanel.ClearData();
_nodeInfoEditPanel.OnNodesChanged();
Log("清空成功");
}
#endregion #endregion
} }

View File

@ -17,11 +17,14 @@ grow_vertical = 2
[node name="FileDirDialog" type="FileDialog" parent="."] [node name="FileDirDialog" type="FileDialog" parent="."]
script = ExtResource("1_d2g23") script = ExtResource("1_d2g23")
[node name="Main" type="Node" parent="." node_paths=PackedStringArray("_dirSelector", "_openDirButton", "_doParseButton", "_nodeInfoEditPanel", "_addKeyButton", "_removeKeyButton", "_parsedInfoPanel", "_mainTreePanel", "_columnText", "_addColumnButton", "_removeColumnButton")] [node name="Main" type="Node" parent="." node_paths=PackedStringArray("_dirSelector", "_console", "_openDirButton", "_doParseButton", "_saveButton", "_resetButton", "_nodeInfoEditPanel", "_addKeyButton", "_removeKeyButton", "_parsedInfoPanel", "_mainTreePanel", "_columnText", "_addColumnButton", "_removeColumnButton")]
script = ExtResource("2_0727o") script = ExtResource("2_0727o")
_dirSelector = NodePath("../FileDirDialog") _dirSelector = NodePath("../FileDirDialog")
_openDirButton = NodePath("../MarginContainer/HSplitContainer/ScrollContainer/VBoxContainer2/FoldableContainer4/HFlowContainer/OpenDir") _console = NodePath("../MarginContainer/HSplitContainer/ScrollContainer/VBoxContainer2/FoldableContainer4/VBoxContainer/RichTextLabel")
_doParseButton = NodePath("../MarginContainer/HSplitContainer/ScrollContainer/VBoxContainer2/FoldableContainer4/HFlowContainer/DoParse") _openDirButton = NodePath("../MarginContainer/HSplitContainer/ScrollContainer/VBoxContainer2/FoldableContainer4/VBoxContainer/HFlowContainer/ScanDir")
_doParseButton = NodePath("../MarginContainer/HSplitContainer/ScrollContainer/VBoxContainer2/FoldableContainer4/VBoxContainer/HFlowContainer/DoParse")
_saveButton = NodePath("../MarginContainer/HSplitContainer/ScrollContainer/VBoxContainer2/FoldableContainer4/VBoxContainer/HFlowContainer/Save")
_resetButton = NodePath("../MarginContainer/HSplitContainer/ScrollContainer/VBoxContainer2/FoldableContainer4/VBoxContainer/HFlowContainer/Reset")
_nodeInfoEditPanel = NodePath("../MarginContainer/HSplitContainer/ScrollContainer/VBoxContainer2/FoldableContainer/VBoxContainer/NodeEditPanel") _nodeInfoEditPanel = NodePath("../MarginContainer/HSplitContainer/ScrollContainer/VBoxContainer2/FoldableContainer/VBoxContainer/NodeEditPanel")
_addKeyButton = NodePath("../MarginContainer/HSplitContainer/ScrollContainer/VBoxContainer2/FoldableContainer/VBoxContainer/HBoxContainer/AddKey") _addKeyButton = NodePath("../MarginContainer/HSplitContainer/ScrollContainer/VBoxContainer2/FoldableContainer/VBoxContainer/HBoxContainer/AddKey")
_removeKeyButton = NodePath("../MarginContainer/HSplitContainer/ScrollContainer/VBoxContainer2/FoldableContainer/VBoxContainer/HBoxContainer/RemoveKey") _removeKeyButton = NodePath("../MarginContainer/HSplitContainer/ScrollContainer/VBoxContainer2/FoldableContainer/VBoxContainer/HBoxContainer/RemoveKey")
@ -64,23 +67,37 @@ size_flags_horizontal = 3
[node name="FoldableContainer4" type="FoldableContainer" parent="MarginContainer/HSplitContainer/ScrollContainer/VBoxContainer2"] [node name="FoldableContainer4" type="FoldableContainer" parent="MarginContainer/HSplitContainer/ScrollContainer/VBoxContainer2"]
layout_mode = 2 layout_mode = 2
folded = true
title = "功能操作" title = "功能操作"
[node name="HFlowContainer" type="HFlowContainer" parent="MarginContainer/HSplitContainer/ScrollContainer/VBoxContainer2/FoldableContainer4"] [node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer/HSplitContainer/ScrollContainer/VBoxContainer2/FoldableContainer4"]
visible = false
layout_mode = 2 layout_mode = 2
[node name="OpenDir" type="Button" parent="MarginContainer/HSplitContainer/ScrollContainer/VBoxContainer2/FoldableContainer4/HFlowContainer"] [node name="RichTextLabel" type="RichTextLabel" parent="MarginContainer/HSplitContainer/ScrollContainer/VBoxContainer2/FoldableContainer4/VBoxContainer"]
custom_minimum_size = Vector2(0, 200)
layout_mode = 2
bbcode_enabled = true
[node name="HFlowContainer" type="HFlowContainer" parent="MarginContainer/HSplitContainer/ScrollContainer/VBoxContainer2/FoldableContainer4/VBoxContainer"]
layout_mode = 2
[node name="ScanDir" type="Button" parent="MarginContainer/HSplitContainer/ScrollContainer/VBoxContainer2/FoldableContainer4/VBoxContainer/HFlowContainer"]
layout_mode = 2 layout_mode = 2
size_flags_vertical = 4 size_flags_vertical = 4
text = "打开文件夹" text = "扫描文件夹"
[node name="DoParse" type="Button" parent="MarginContainer/HSplitContainer/ScrollContainer/VBoxContainer2/FoldableContainer4/HFlowContainer"] [node name="DoParse" type="Button" parent="MarginContainer/HSplitContainer/ScrollContainer/VBoxContainer2/FoldableContainer4/VBoxContainer/HFlowContainer"]
layout_mode = 2 layout_mode = 2
size_flags_vertical = 4 size_flags_vertical = 4
text = "开始解析" text = "开始解析"
[node name="Save" type="Button" parent="MarginContainer/HSplitContainer/ScrollContainer/VBoxContainer2/FoldableContainer4/VBoxContainer/HFlowContainer"]
layout_mode = 2
text = "保存"
[node name="Reset" type="Button" parent="MarginContainer/HSplitContainer/ScrollContainer/VBoxContainer2/FoldableContainer4/VBoxContainer/HFlowContainer"]
layout_mode = 2
text = "重置"
[node name="FoldableContainer3" type="FoldableContainer" parent="MarginContainer/HSplitContainer/ScrollContainer/VBoxContainer2"] [node name="FoldableContainer3" type="FoldableContainer" parent="MarginContainer/HSplitContainer/ScrollContainer/VBoxContainer2"]
layout_mode = 2 layout_mode = 2
folded = true folded = true

View File

@ -4,5 +4,7 @@ namespace Learn.Models;
public class Item public class Item
{ {
public Dictionary<string, string> Info { get; } = new (); public Dictionary<string, string> MainInfo { get; set; } = new();
public Dictionary<string, string> Info { get; set; } = new();
} }

1962
data.json Normal file

File diff suppressed because it is too large Load Diff