using System.IO; namespace DeskCore; /// Eine rückgängig machbare Aktion, bestehend aus mehreren Einzelschritten. public class UndoEntry(string description) { public string Description { get; } = description; private readonly List> _steps = []; /// Elemente, die beim Löschen zwischengeparkt wurden – gehen später in den Papierkorb. public List HeldPaths { get; } = []; public bool IsEmpty => _steps.Count == 0; /// Schritt zum Rückgängigmachen; gibt eine Fehlermeldung oder null zurück. public void Add(Func undo) => _steps.Add(undo); public void AddMove(string from, string to) => Add(() => { if (!File.Exists(to) && !Directory.Exists(to)) return $"„{Path.GetFileName(to)}“ gibt es nicht mehr."; var dir = Path.GetDirectoryName(from)!; Directory.CreateDirectory(dir); var back = File.Exists(from) || Directory.Exists(from) ? Storage.UniquePath(dir, Path.GetFileName(from)) : from; Storage.MoveAny(to, back); return null; }); public void AddCopy(string original, string copy) => Add(() => { if (!File.Exists(copy) && !Directory.Exists(copy)) return null; // Original noch da → Kopie weg; sonst Kopie dorthin zurück, wo das Original lag if (File.Exists(original) || Directory.Exists(original)) Storage.Recycle(copy); else { Directory.CreateDirectory(Path.GetDirectoryName(original)!); Storage.MoveAny(copy, original); } return null; }); public void AddDelete(string original, string held) { HeldPaths.Add(held); AddMove(original, held); } public List Run() { var errors = new List(); for (int i = _steps.Count - 1; i >= 0; i--) { try { if (_steps[i]() is { } err) errors.Add(err); } catch (Exception ex) { errors.Add(ex.Message); } } HeldPaths.Clear(); // wurden zurückgeholt return errors; } } public class UndoManager { private const int Limit = 30; private readonly LinkedList _stack = new(); public event Action? Changed; public bool CanUndo => _stack.Count > 0; public string? NextDescription => _stack.Last?.Value.Description; public void Push(UndoEntry entry) { if (entry.IsEmpty) return; _stack.AddLast(entry); while (_stack.Count > Limit) { Flush(_stack.First!.Value); _stack.RemoveFirst(); } Changed?.Invoke(); } public (string Description, List Errors)? Undo() { if (_stack.Last is not { } last) return null; _stack.RemoveLast(); var errors = last.Value.Run(); Changed?.Invoke(); return (last.Value.Description, errors); } /// Beim Beenden: alles Zwischengeparkte in den Papierkorb. public void FlushAll() { foreach (var e in _stack) Flush(e); _stack.Clear(); Storage.FlushHolding(); } private static void Flush(UndoEntry e) { foreach (var p in e.HeldPaths) Storage.Recycle(p); e.HeldPaths.Clear(); } }