Files
DeskCore/UndoManager.cs
T
M_ViperandClaude Opus 5.5 77bb3e6b9d DeskCore 1.0.0
Desktop-Icons in eigene Kategorien sortieren: Windows-11-Design (hell/dunkel),
Desktop-Boxen, automatisches Einsortieren nach Regeln, Rückgängig, Suche,
Infobereich mit Tastenkürzel, Sicherung als ZIP und Installer ohne Adminrechte.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 20:19:32 +02:00

106 lines
3.2 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System.IO;
namespace DeskCore;
/// <summary>Eine rückgängig machbare Aktion, bestehend aus mehreren Einzelschritten.</summary>
public class UndoEntry(string description)
{
public string Description { get; } = description;
private readonly List<Func<string?>> _steps = [];
/// <summary>Elemente, die beim Löschen zwischengeparkt wurden – gehen später in den Papierkorb.</summary>
public List<string> HeldPaths { get; } = [];
public bool IsEmpty => _steps.Count == 0;
/// <summary>Schritt zum Rückgängigmachen; gibt eine Fehlermeldung oder null zurück.</summary>
public void Add(Func<string?> 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<string> Run()
{
var errors = new List<string>();
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<UndoEntry> _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<string> Errors)? Undo()
{
if (_stack.Last is not { } last) return null;
_stack.RemoveLast();
var errors = last.Value.Run();
Changed?.Invoke();
return (last.Value.Description, errors);
}
/// <summary>Beim Beenden: alles Zwischengeparkte in den Papierkorb.</summary>
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();
}
}