277 lines
10 KiB
C#
277 lines
10 KiB
C#
using RobotNet10.ScriptEngine.Shared;
|
|
using static System.Runtime.InteropServices.JavaScript.JSType;
|
|
|
|
namespace RobotNet10.ScriptEditor.Models;
|
|
|
|
public class ScriptFolder(ScriptFolderDto data, ScriptFolder? parent = null) : IHierarchyItem
|
|
{
|
|
public ScriptFolder? Parent => parent;
|
|
public string Path => System.IO.Path.Combine(parent?.Path ?? "", Name);
|
|
public int Level { get; } = data.Level;
|
|
|
|
public bool IsModified { get; private set; }
|
|
public int WarningCount { get; private set; }
|
|
public int ErrorCount { get; private set; }
|
|
public bool IsExpanded { get; set; } = false;
|
|
|
|
public event Action? ChildrenChanged;
|
|
public event Action? Modified;
|
|
public event Action? NameChanged;
|
|
public event Action<int, int>? DiagnosticsChanged;
|
|
|
|
public IEnumerable<ScriptFolder> Folders => WorkspaceFolders;
|
|
public IEnumerable<ScriptFile> Files => WorkspaceFiles;
|
|
|
|
private string _name = data.Name;
|
|
public string Name
|
|
{
|
|
get => _name;
|
|
set
|
|
{
|
|
if (string.IsNullOrEmpty(value)) throw new ArgumentNullException($"Tên file {_name} không được để trống");
|
|
|
|
if (_name == value) return;
|
|
|
|
_name = value;
|
|
|
|
NameChanged?.Invoke();
|
|
}
|
|
}
|
|
|
|
private readonly List<ScriptFolder> WorkspaceFolders = [];
|
|
private readonly List<ScriptFile> WorkspaceFiles = [];
|
|
|
|
public void AddFiles(params IEnumerable<ScriptFile> files)
|
|
{
|
|
WorkspaceFiles.AddRange(files);
|
|
WorkspaceFiles.Sort((a, b) => string.Compare(a.Name, b.Name, StringComparison.Ordinal));
|
|
|
|
// Recalculate totals including new files
|
|
var totalWarningCount = Files.Sum(file => file.WarningCount) + Folders.Sum(folder => folder.WarningCount);
|
|
var totalErrorCount = Files.Sum(file => file.ErrorCount) + Folders.Sum(folder => folder.ErrorCount);
|
|
var newIsModified = Files.Any(file => file.IsModified) || Folders.Any(folder => folder.IsModified);
|
|
|
|
var warningChanged = WarningCount != totalWarningCount;
|
|
var errorChanged = ErrorCount != totalErrorCount;
|
|
var modifiedChanged = IsModified != newIsModified;
|
|
|
|
WarningCount = totalWarningCount;
|
|
ErrorCount = totalErrorCount;
|
|
IsModified = newIsModified;
|
|
|
|
foreach (var file in files)
|
|
{
|
|
file.Modified += UpdateModified;
|
|
file.DiagnosticsChanged += OnDiagnosticsChanged;
|
|
}
|
|
|
|
// Notify changes
|
|
if (warningChanged || errorChanged)
|
|
{
|
|
DiagnosticsChanged?.Invoke(WarningCount, ErrorCount);
|
|
}
|
|
if (modifiedChanged)
|
|
{
|
|
Modified?.Invoke();
|
|
}
|
|
|
|
ChildrenChanged?.Invoke();
|
|
}
|
|
|
|
public void AddFolders(params IEnumerable<ScriptFolder> folders)
|
|
{
|
|
WorkspaceFolders.AddRange(folders);
|
|
WorkspaceFolders.Sort((a, b) => string.Compare(a.Name, b.Name, StringComparison.Ordinal));
|
|
|
|
// Recalculate totals including new folders
|
|
var totalWarningCount = Files.Sum(file => file.WarningCount) + Folders.Sum(folder => folder.WarningCount);
|
|
var totalErrorCount = Files.Sum(file => file.ErrorCount) + Folders.Sum(folder => folder.ErrorCount);
|
|
var newIsModified = Files.Any(file => file.IsModified) || Folders.Any(folder => folder.IsModified);
|
|
|
|
var warningChanged = WarningCount != totalWarningCount;
|
|
var errorChanged = ErrorCount != totalErrorCount;
|
|
var modifiedChanged = IsModified != newIsModified;
|
|
|
|
WarningCount = totalWarningCount;
|
|
ErrorCount = totalErrorCount;
|
|
IsModified = newIsModified;
|
|
|
|
foreach (var folder in folders)
|
|
{
|
|
folder.Modified += UpdateModified;
|
|
folder.DiagnosticsChanged += OnDiagnosticsChanged;
|
|
}
|
|
|
|
// Notify changes
|
|
if (warningChanged || errorChanged)
|
|
{
|
|
DiagnosticsChanged?.Invoke(WarningCount, ErrorCount);
|
|
}
|
|
if (modifiedChanged)
|
|
{
|
|
Modified?.Invoke();
|
|
}
|
|
|
|
ChildrenChanged?.Invoke();
|
|
}
|
|
|
|
public void RemoveFile(ScriptFile file)
|
|
{
|
|
if (WorkspaceFiles.Remove(file))
|
|
{
|
|
// Unsubscribe from file events
|
|
file.Modified -= UpdateModified;
|
|
file.DiagnosticsChanged -= OnDiagnosticsChanged;
|
|
|
|
// Recalculate totals after removal
|
|
var totalWarningCount = Files.Sum(f => f.WarningCount) + Folders.Sum(folder => folder.WarningCount);
|
|
var totalErrorCount = Files.Sum(f => f.ErrorCount) + Folders.Sum(folder => folder.ErrorCount);
|
|
var newIsModified = Files.Any(f => f.IsModified) || Folders.Any(folder => folder.IsModified);
|
|
|
|
var warningChanged = WarningCount != totalWarningCount;
|
|
var errorChanged = ErrorCount != totalErrorCount;
|
|
var modifiedChanged = IsModified != newIsModified;
|
|
|
|
WarningCount = totalWarningCount;
|
|
ErrorCount = totalErrorCount;
|
|
IsModified = newIsModified;
|
|
|
|
// Dispose the removed file
|
|
file.Dispose();
|
|
|
|
// Notify changes
|
|
if (warningChanged || errorChanged)
|
|
{
|
|
DiagnosticsChanged?.Invoke(WarningCount, ErrorCount);
|
|
}
|
|
if (modifiedChanged)
|
|
{
|
|
Modified?.Invoke();
|
|
}
|
|
|
|
ChildrenChanged?.Invoke();
|
|
}
|
|
}
|
|
|
|
public void RemoveFolder(ScriptFolder folder)
|
|
{
|
|
if (WorkspaceFolders.Remove(folder))
|
|
{
|
|
// Unsubscribe from folder events
|
|
folder.Modified -= UpdateModified;
|
|
folder.DiagnosticsChanged -= OnDiagnosticsChanged;
|
|
|
|
// Recalculate totals after removal
|
|
var totalWarningCount = Files.Sum(file => file.WarningCount) + Folders.Sum(f => f.WarningCount);
|
|
var totalErrorCount = Files.Sum(file => file.ErrorCount) + Folders.Sum(f => f.ErrorCount);
|
|
var newIsModified = Files.Any(file => file.IsModified) || Folders.Any(f => f.IsModified);
|
|
|
|
var warningChanged = WarningCount != totalWarningCount;
|
|
var errorChanged = ErrorCount != totalErrorCount;
|
|
var modifiedChanged = IsModified != newIsModified;
|
|
|
|
WarningCount = totalWarningCount;
|
|
ErrorCount = totalErrorCount;
|
|
IsModified = newIsModified;
|
|
|
|
// Dispose the removed folder (will handle its children)
|
|
folder.Dispose();
|
|
|
|
// Notify changes
|
|
if (warningChanged || errorChanged)
|
|
{
|
|
DiagnosticsChanged?.Invoke(WarningCount, ErrorCount);
|
|
}
|
|
if (modifiedChanged)
|
|
{
|
|
Modified?.Invoke();
|
|
}
|
|
|
|
ChildrenChanged?.Invoke();
|
|
}
|
|
}
|
|
|
|
private void UpdateModified()
|
|
{
|
|
var newIsModified = Files.Any(file => file.IsModified) || Folders.Any(folder => folder.IsModified);
|
|
|
|
// Only update and notify if the value actually changed
|
|
if (IsModified != newIsModified)
|
|
{
|
|
IsModified = newIsModified;
|
|
Modified?.Invoke();
|
|
}
|
|
}
|
|
|
|
private void OnDiagnosticsChanged(int warningCount, int errorCount)
|
|
{
|
|
// Recalculate totals from all children
|
|
// Note: The parameters (warningCount, errorCount) are the absolute values from the child that changed,
|
|
// but we recalculate from all children to ensure accuracy, especially when multiple files change simultaneously
|
|
var totalWarningCount = Files.Sum(file => file.WarningCount) + Folders.Sum(folder => folder.WarningCount);
|
|
var totalErrorCount = Files.Sum(file => file.ErrorCount) + Folders.Sum(folder => folder.ErrorCount);
|
|
|
|
if (WarningCount != totalWarningCount || ErrorCount != totalErrorCount)
|
|
{
|
|
WarningCount = totalWarningCount;
|
|
ErrorCount = totalErrorCount;
|
|
DiagnosticsChanged?.Invoke(WarningCount, ErrorCount);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Recalculates WarningCount, ErrorCount, and IsModified from all children.
|
|
/// This is useful after diagnostics have been updated for all children.
|
|
/// </summary>
|
|
internal void RecalculateTotals()
|
|
{
|
|
// First, recalculate all child folders recursively
|
|
foreach (var subFolder in Folders)
|
|
{
|
|
subFolder.RecalculateTotals();
|
|
}
|
|
|
|
// Then calculate totals from all children
|
|
var totalWarningCount = Files.Sum(f => f.WarningCount) + Folders.Sum(f => f.WarningCount);
|
|
var totalErrorCount = Files.Sum(f => f.ErrorCount) + Folders.Sum(f => f.ErrorCount);
|
|
var isModified = Files.Any(f => f.IsModified) || Folders.Any(f => f.IsModified);
|
|
|
|
// Update properties if changed
|
|
var warningChanged = WarningCount != totalWarningCount;
|
|
var errorChanged = ErrorCount != totalErrorCount;
|
|
var modifiedChanged = IsModified != isModified;
|
|
|
|
if (warningChanged || errorChanged || modifiedChanged)
|
|
{
|
|
WarningCount = totalWarningCount;
|
|
ErrorCount = totalErrorCount;
|
|
IsModified = isModified;
|
|
|
|
if (warningChanged || errorChanged)
|
|
{
|
|
DiagnosticsChanged?.Invoke(WarningCount, ErrorCount);
|
|
}
|
|
|
|
if (modifiedChanged)
|
|
{
|
|
Modified?.Invoke();
|
|
}
|
|
}
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
foreach (var file in WorkspaceFiles)
|
|
{
|
|
file.Dispose();
|
|
}
|
|
WorkspaceFiles.Clear();
|
|
foreach (var folder in Folders)
|
|
{
|
|
folder.Dispose();
|
|
}
|
|
WorkspaceFolders.Clear();
|
|
GC.SuppressFinalize(this);
|
|
}
|
|
}
|