Im Rückwärtsgang

Vorschläge zur Realisierung einer Programm-unabhängigen Undo-Funktion

Veikko Krypczyk

Ein entscheidender Vorteil der Bearbeitung von Dokumenten mittels des PCs ist unter anderem die leichte Änderbarkeit und Anpassbarkeit. Beispielsweise kann man in Textverarbeitungsprogrammen problemlos einzelne Wörter oder Absätze hinzufügen, verschieben oder löschen. Entscheidet man sich jedoch anders, können vorgenommene Änderungen auch problemlos wieder rückgängig gemacht werden. Im nachfolgenden Artikel soll die Problematik der Realisierung einer solchen „Rückgängig (Undo)-Funktion“ etwas näher betrachtet werden. Dabei soll neben einem theoretischen Ansatz auch ein möglicher Realisierungsvorschlag in Form eines Rahmens für eine Klasse entwickelt werden.

Die Gründe für die Realisierung einer solchen Undo-Funktion liegen unmittelbar auf der Hand. Denken Sie an ein Konstruktionsprogramm, wo der Entwicklungsingenieur Änderungen und Erweiterungen an der bestehenden Zeichnung vornehmen kann. Sollte nicht das gewünschte Ergebnis erreicht worden sein, kann in einzelnen Schritten oder in Form einer Blockauswahl zu einem früheren Arbeitsergebnis zurückgekehrt werden. Ähnliche Situationen finden sich in einer Vielzahl von Anwendungssoftware wieder. Eine Undo-Funktion gehört damit (wo sinnvoll) zu einem anwenderfreundlichen Programm und erhöht in nicht unbedeutenden Maße die Akzeptanz einer Software. Man kann auch sagen, dass der Anwender sie heute als Standard erwarten kann.

Die Aufgabe des Softwareentwicklers ist es nun, ein solches „Sicherungsnetz“ für den Benutzer in ein neues Programm oder in eine bestehende Programmfunktionalität zu integrieren. Der folgende Vorschlag soll Anregungen und Lösungen für die Umsetzung einer Undo-Funktion liefern. Der Konzeptvorschlag ist dem Grunde nach unabhängig von der verwendeten Entwicklungsumgebung und Programmiersprache. Hier wird auf Delphi zurückgegriffen. Mit leichten sprachsyntaktischen Anpassungen ist ein Einsatz in anderen Programmiersprachen (z.B. C# und Java) ohne weiteres möglich.

Anwendungsbereich

Optimal wäre es, ein Konzept für eine allgemeingültige Undo-Funktion zu erstellen und damit die Implementierung für (fast) jeden Zweck von Anwendungsprogramm zu ermöglichen. Programme sind vor diesem Hintergrund jedoch wie folgt einzuteilen:

  • Dokumentenbasierte Anwendungen, die keine Veränderung von Datensätzen in Datenbanken vornehmen.
  • Datenbankgestützte Anwendungen, die Transaktionen und Mutationen in einer Datenbank ausführen.

Für letzte Klasse von Anwendungen ist das nachfolgend beschriebene Konzept nicht geeignet. Der Fokus des hier beschriebenen Ansatzes richtet sich auf klassische Applikationen. Hier werden einzelne Dokumente erstellt und verändert. Beispiele solcher Anwendungen sind: Textverarbeitungen, Editoren, graphische Anwendungen und sonstige dokumentenbasierte Anwendungen. Zentraler gemeinsamer Bestandteil dieser Anwendungen ist die Möglichkeit, die erstellten Dokumente in einer (einzelnen) Datei zu speichern und aus dieser wieder zu laden. Der eigentliche Kontext der Anwendung ist dabei sekundär.

Anforderungen

Formulieren wir jetzt den (gewünschten) Funktionsumfang an einen Undo-Befehl und erläutern diese kurz.

  • Hauptaufgabe der Undo-Funktion besteht natürlich darin, Änderung des Dokuments wieder rückgängig machen zu können. Diese Änderungen können durch den Benutzer des Programms ausgelöst worden sein (z.B. der Anwender hat neue Werte innerhalb eines Dialogfeldes erfasst oder eine Zeichenoperation angestoßen). Eine zweite Alternative besteht darin, dass die Software aufgrund eines bestimmten Zustands Aktionen ausgelöst hat (z.B. Rechenvorgänge), die ebenfalls zu einer Veränderung des Dokuments führen. Beide Aktionen sollten mittels der Undo-Funktion annulliert werden können.
  • Die Anzahl der rücknehmbaren Schritte soll sowohl flexibel durch den Programmierer als auch durch den Anwender gestaltet werden können. In einigen Programmen macht es Sinn, die Schrittanzahl im Vorfeld auf ein vernünftiges Niveau einzustellen. Andererseits kann diese Option auch dem Anwender im Rahmen der Konfiguration des Programms (üblicherweise unter Extras | Optionen) überlassen werden.
  • Darüber hinaus sollte die Möglichkeit bestehen, einzelne Schritte durch einen Hinweistext näher zu beschreiben. Hier erhält der Anwender bei der Auswahl und beim Aufruf der Undo-Funktion einen Hinweis, welche Aktion damit widerrufen werden kann.
  • Der Anwender muss die Möglichkeit besitzen, auch gleichzeitig mehrere Aktionen zu widerrufen.
  • Obligatorisch sind eine benutzerfreundliche Präsentation und Bedienbarkeit der eben beschriebenen Funktionalitäten und eine einfache Integration in eine bestehende Benutzeroberfläche.

Die Hauptanforderung aus Sicht des Softwareentwicklers besteht darin, dass ein derartig flexibles Konzept erstellt wird, dass es auch noch nachträglich in ein bestehendes Anwendungsgerüst eingebaut werden kann.

Theoretischer Ansatz

Auf der Suche nach einem Ansatz für die Umsetzung einer Undo-Funktionalität für ein Grafikprogramm wurden verschiedene Ansätze geprüft. Ein möglicher Ansatz wäre es, Aktionen des Benutzers am Dokument zu protokollieren und bei Notwendigkeit die entsprechend entgegengesetzt gerichtete Operation aufzurufen.
Konstruieren wir zum Verständnis ein kleines Beispiel: Der Anwender zeichnet im aktiven Dokument des Programms eine Linie. Es wird der Befehl Linie zeichnen protokolliert. Soll die Aktion widerrufen werden, so könnte die Liste der gezeichneten Objekte um die zuletzt gezeichnete Linie bereinigt werden. Damit wäre der Zustand vor dem Zeichenbefehl wieder hergestellt.

Dieser eben grob beschriebene Ansatz hat insbesondere aus Sicht der Implementierung einen gravierenden Nachteil. Je nach Typ und Umfang des Programms ist eine Vielzahl von unterschiedlichen Operationen zu unterscheiden. Für all diese Fälle wären dann entsprechende Vorkehrungen für eine Wiederherstellung des ursprünglichen Zustandes zu implementieren. Umsetzung und Wartbarkeit gestalten sich dann mehr als schwierig.

Weiterhin würde dieser Ansatz nicht im Geringsten der Forderung nach einer vom Anwendungstyp unabhängigen Realisierung nahe kommen. Für jede Art von Programm müssten die einzelnen Programmoperationen analysiert und entsprechende „Gegenmaßnahmen“ eingebaut werden. Von einer einfachen und unkomplizierten Umsetzung kann damit keine Rede mehr sein. Vorteilhaft erscheint an dieser Methode lediglich, dass der Umfang der sich zu merkenden Änderungen (also die vorgenommenen Programmaktionen) klein bleibt und damit der Ressourcenverbrauch minimal ist. Dieses Prinzip findet Anwendung, wenn Datenbankzustände nach einer Störung des Systems wiederhergestellt werden müssen. Mutationen des Datenbankbestands werden grob gesagt ab einem bestimmten Punkt protokolliert und bei einem Problem erneut ausgeführt. Damit ist ein vollständiger Datenbankabzug nur in größeren Intervallen nötig.

Aufgrund der beschriebenen Probleme und der Forderung nach einer universellen Einsetzbarkeit wurde deshalb ein anderer Ansatz gewählt. Immer wenn eine Änderung am Dokument vorgenommen wurde, wird ein aktueller Zustand des Dokuments gespeichert und in der Rückgängig-Liste zur Verwaltung eingetragen. Sollen eine oder mehrere Aktionen widerrufen werden, so wird der temporäre Zwischenstand des Dokuments im Hintergrund neu geladen und zwischenzeitlich vorgenommene Änderungen sind damit aufgehoben. In diesem Sinne wird also ein vollständiges Backup des Dokuments vorgenommen.

Es stellt sich nun die Frage, wo eine (temporäre) Version des Dokuments abgelegt werden kann. Hier bieten sich unmittelbar zwei Varianten an: Als erstes wäre die Ablage des Dokuments im Arbeitsspeicher zu nennen. Alternativ würde sich die Speicherung als temporäre Datei anbieten. Prinzipiell sind beide Varianten geeignet. Bezüglich Variante der Ablage im Arbeitsspeicher ist die hohe Verarbeitungsgeschwindigkeit positiv zu bewerten. Dagegen spricht eine starke Ressourcenbelastung in Form von Speicherbelegung. Dieses dürfte jedoch nur dann zutreffen, wenn die Größe der zu speichernden Dokumente ein gewisses Maß überschreitet. Beispielsweise können Bitmap-Dateien einige Megabyte an Größe beanspruchen. Abhängig ist der Ressourcenverbrauch auch von der Anzahl der vorzuhaltenden Schritte für die Undo-Funktion und damit in diesem Punkt beeinflussbar.

Betrachten wir die andere Möglichkeit. Hier soll die Speicherung der Dokumentenzustände als Dateien auf dem lokalen Systemlaufwerk erfolgen. Kritisch kann sich hier der Zeitfaktor für das Speichern und Laden auswirken. Der Speicherplatzverbrauch ist eher sekundär bei heutigen Festplattengrößen.

Zusammengefasst kann an dieser Stelle festgehalten werden, dass für die meisten Anwendungsprogramme beide Varianten möglich sind. Nachfolgend wird für die Umsetzung auf die Variante der physischen Speicherung auf der Festplatte zurückgegriffen. Hinsichtlich der praktischen Umsetzung ist dieses nur für die Speicher- und Laderoutinen von Interesse. Die modernen Programmiersprachen bieten auch für die Ablage der Daten im Speicher entsprechende Unterstützung an (Stichwort: Stream-Objekte). In Abbildung 1 wird das Prinzip unserer Undo-Funktion dargestellt.

Abb. 1: Prinzip der Undo-Funktion

Weiterhin muss die Frage beantwort werden, an welcher Stelle das Anwendungsprogramm eine automatische Zwischenspeicherung des Dokuments vornimmt. Dieses ist abhängig von der Art des Programms, der Menge der zu bearbeitenden Daten und der Interaktionsgeschwindigkeit zwischen Benutzer und Software. Es ist denkbar, dass verwandte Operationen (z.B. alle Eingaben innerhalb eines Dialogfeldes) zu einem Block zusammengefasst werden. Kommt es zu einer Änderung innerhalb dieses Blocks, wird ein Speicherpunkt für den Befehl Rückgängig angelegt. Wird die Aktion durch den Anwender widerrufen, wird der gesamte Vorgang annulliert. Dabei können dann einzelne Aktionen innerhalb des Blocks nicht berücksichtigt werden. Hier ist nach dem Prinzip zwischen Aufwand und Nutzen – unter Berücksichtigung entsprechender Verarbeitungsgeschwindigkeit – die optimale Größe einer Aktion auszuloten. Diese führt dann zum Eintrag in die Rückgängig-Liste.

Als zentrale Voraussetzungen für die Umsetzung der hier vorgeschlagenen Methode ist festzustellen, dass entsprechende Save- und Load-Routinen für das Dokument existieren. Diese können bei Speicherung innerhalb des Dateisystems direkt Verwendung finden oder müssen für eine Dokumentenablage im Arbeitsspeicher angepasst werden.

Geschrieben von
Veikko Krypczyk
Kommentare

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.