Widerrufbare Unternehmensaktivitäten

Wir haben viele verschiedene Arten der Hinzufügung von Aktionen zu der Workbench betrachtet, aber wir haben uns noch nicht mit der Implementierung einer run()-Methode einer Aktion beschäftigt. Der Mechanismus der Methode hängt von der spezifischen in Frage kommenden Aktion ab, aber die Strukturierung des Codes als eine Widerrufbare Unternehmensaktivität ermöglicht der Aktion, an der Unterstützung der Plattform für Widerrufen und Wiederholen teilzunehmen.

Die Plattform stellt ein Framework Widerrufbare Unternehmensaktivitäten in dem Paket org.eclipse.core.commands.operations zur Verfügung. Durch Implementierung des Codes innerhalb einer run()-Methode zur Erstellung einer IUndoableOperation kann die Unternehmensaktivität für Widerrufen und Wiederholen zur Verfügung gestellt werden. Die Konvertierung einer Aktion zur Verwendung von Operationen ist einfach, abgesehen von der Implementierung des Widerruf- und Wiederholverhaltens selbst.

Eine widerrufbare Unternehmensaktivität schreiben

Beginnen wir mit einem sehr einfachen Beispiel. Erinnern Sie sich an das einfache ViewActionDelegate in dem Beispiel-Plug-in für eine Readme-Datei. Nach dem Aufruf startet die Aktion einfach einen Dialog, in dem eine Ausführungsnachricht angezeigt wird.

public void run(org.eclipse.jface.action.IAction action) {
	MessageDialog.openInformation(view.getSite().getShell(),
		MessageUtil.getString("Readme_Editor"),  
		MessageUtil.getString("View_Action_executed")); 
}
Bei der Verwendung von Unternehmensaktivitäten ist die Methode 'run' verantwortlich für die Erstellung einer Unternehmensaktivität, die die Arbeit ausführt, die zuvor in der Methode 'run' ausgeführt wurde, ebenso wie für die Anforderung, dass ein Unternehmensaktivitäten-Protokoll die Aktivität ausführt, so dass sie für die Aktionen 'Rückgängig machen' und 'Widerruf zurücknehmen' beibehalten wird.
public void run(org.eclipse.jface.action.IAction action) {
	IUndoableOperation operation = new ReadmeOperation(
		view.getSite().getShell()); 
	...
	operationHistory.execute(operation, null, null);
}
Die Unternehmensaktivität bindet das alte Verhalten aus der Methode 'run' sowie Widerruf und Wiederholung für die Unternehmensaktivität ein.
class ReadmeOperation extends AbstractOperation {
	Shell shell;
	public ReadmeOperation(Shell shell) {
		super("Readme Operation");
		this.shell = shell;
	}
	public IStatus execute(IProgressMonitor monitor, IAdaptable info) {
		MessageDialog.openInformation(shell,
		MessageUtil.getString("Readme_Editor"),  
		MessageUtil.getString("View_Action_executed"));   
		return Status.OK_STATUS;
	}
	public IStatus undo(IProgressMonitor monitor) {
		MessageDialog.openInformation(shell,
		MessageUtil.getString("Readme_Editor"),  
			"Undoing view action"));   
		return Status.OK_STATUS;
	}
	public IStatus redo(IProgressMonitor monitor) {
		MessageDialog.openInformation(shell,
		MessageUtil.getString("Readme_Editor"),  
			"Redoing view action"));   
		return Status.OK_STATUS;
	}
}

Für einfache Aktionen ist es unter Umständen möglich, die Detailarbeiten in die Operationsklasse zu verschieben. In diesem Fall ist es möglicherweise empfehlenswert, die voranstehenden Aktionsklassen zu einer einzigen Aktionsklasse zu komprimieren, die dann parametrisiert wird. Die Aktion würde dann einfach im Moment, in dem sie ausgeführt wird, die angegebene Operation ausführen. Dies ist weitestgehend eine Anwendungsdesignentscheidung.

Wenn eine Aktion einen Assistenten startet, dann wird die Unternehmensaktivität üblicherweise als Teil der Methode performFinish() des Assistenten oder als finish()-Methode einer Assistentenseite erstellt. Die Konvertierung der Methode finish zur Verwendung von Unternehmensaktivitäten ist der Konvertierung der Methode run ähnlich. Die Methode ist verantwortlich für die Erstellung und Ausführung einer Unternehmensaktivität, die die Arbeit ausführt, die zuvor integriert ausgeführt wurde.

Unternehmensaktivitäten-Protokoll

Bisher haben wir ein Unternehmensaktivitäten-Protokoll verwendet, ohne es wirklich zu erklären. Betrachten wir erneut den Code, der unsere Beispiel-Unternehmensaktivität erstellt.

public void run(org.eclipse.jface.action.IAction action) {
	IUndoableOperation operation = new ReadmeOperation(
		view.getSite().getShell()); 
	...
	operationHistory.execute(operation, null, null);
}
Was alles enthält das Unternehmensaktivitäten-Protokoll? IOperationHistory definiert die Schnittstelle für das Objekt, das alle widerrufbaren Unternehmensaktivitäten protokolliert. Wenn ein Unternehmensaktivitäten-Protokoll eine Unternehmensaktivität ausführt, führt es zuerst die Unternehmensaktivität aus und fügt sie dann dem Widerrufsprotokoll hinzu. Clients, die Unternehmensaktivitäten widerrufen und wiederholen möchten, machen dies mit Hilfe des Protokolls IOperationHistory.

das durch eine Anwendung verwendete Unternehmensaktivitäten-Protokoll kann auf verschiedene Weisen abgerufen werden. Der einfachste Weg ist die Verwendung der OperationHistoryFactory.

IOperationHistory operationHistory = OperationHistoryFactory.getOperationHistory();

Auch die Workbench kann verwendet werden, um das Unternehmensaktivitäten-Protokoll abzurufen. Die Workbench konfiguriert das standardmäßige Unternehmensaktivitäten-Protokoll und stellt auch ein Protokoll für den Zugriff darauf zur Verfügung. Der folgende Ausschnitt zeigt, wie das Unternehmensaktivitäten-Protokoll von der Workbench zu erlangen ist.

IWorkbench workbench = view.getSite().getWorkbenchWindow().getWorkbench();
IOperationHistory operationHistory = workbench.getOperationSupport().getOperationHistory();
Wenn Sie ein Unternehmensaktivitäten-Protokoll erlangt haben, kann es dazu verwendet werden, das Protokoll widerrufbarer und wiederholbarer Unternehmensaktivitäten abzufragen, festzustellen, welches die nächste Unternehmensaktivität für Widerruf oder Wiederholung ist oder bestimmte Unternehmensaktivitäten zu widerrufen oder zu wiederholen. Clients können eine IOperationHistoryListener hinzufügen, um Benachrichtigungen über Änderungen im Protokoll zu erhalten. Andere Protokolle ermöglichen es den Clients, Grenzwerte für das Protokoll zu setzen oder Listener-Funktionen über Änderungen an einer bestimmten Unternehmensaktivität zu benachrichtigen. Bevor wir uns im Einzelnen mit dem Protokoll befassen, müssen wir den Widerrufskontext verstehen.

Widerrufskontexte

Wenn eine Unternehmensaktivität erstellt wird, wird sie einem Widerrufskontext zugeordnet, der den Benutzerkontext beschreibt, in dem die ursprüngliche Unternehmensaktivität ausgeführt worden ist. Der Widerrufskontext hängt üblicherweise von der Ansicht oder dem Editor ab, der die widerrufbare Unternehmensaktivität verursacht hat. Änderungen, die innerhalb eines Editors ausgeführt werden, sind beispielsweise häufig für diesen Editor lokal. In diesem Fall sollte der Editor seinen eigenen Widerrufskontext erstellen und diesen Kontext Operationen zuordnen, die er zum Protokoll hinzufügt. Auf diese Weise werden alle Unternehmensaktivitäten, die in dem Editor ausgeführt werden, als lokal und halb-öffentlich angesehen. Editoren und Ansichten, die mit einem gemeinsamen Modell arbeiten, verwenden oft Widerrufskontexte, die sich auf das Modell beziehen, das sie bearbeiten. Durch Verwendung eines allgemeineren Widerrufskontextes können Unternehmensaktivitäten, die durch eine Ansicht bzw. einen Editor ausgeführt werden, für den Widerruf in anderen Ansichten bzw. Editoren zur Verfügung stehen, die dasselbe Modell bearbeiten.

Das Verhalten der Widerrufskontexte ist relativ einfach; das Protokoll für IUndoContext ist geradezu minimal. Die Hauptaufgabe eines Kontextes ist es, eine bestimmte Unternehmensaktivität als zu diesem Widerrufskontext gehörend zu 'markieren', um sie von Unternehmensaktivitäten zu unterscheiden, die in anderen Widerrufskontexten erstellt worden sind. dadurch ist es dem Unternehmensaktivitäten-Protokoll möglich, das globale Protokoll aller widerrufbaren Unternehmensaktivitäten, die ausgeführt worden sind, zu überwachen, während Ansichten und Editoren das Protokoll unter einem bestimmten Gesichtspunkt mit Hilfe des Widerrufkontextes filtern können.

Widerrufskontexte können durch das Plug-in erstellt werden, das die widerrufbaren Unternehmensaktivitäten erstellt oder der Zugriff darauf kann durch API erfolgen. So stellt die Workbench beispielsweise den Zugriff auf einen Widerrufskontext zur Verfügung, der für Unternehmensaktivitäten in der gesamten Workbench verwendet werden kann. Egal wie sie erlangt werden, sollten Widerrufskontexte zugeordnet werden, wenn eine Unternehmensaktivität erstellt wird. Der folgende Ausschnitt zeigt, wie die ViewActionDelegate des Readme-Plug-ins ihren Unternehmensaktivitäten einen die gesamte Workbench umfassenden Kontext zuordnet.

public void run(org.eclipse.jface.action.IAction action) {
	IUndoableOperation operation = new ReadmeOperation(
		view.getSite().getShell()); 
	IWorkbench workbench = view.getSite().getWorkbenchWindow().getWorkbench();
	IOperationHistory operationHistory = workbench.getOperationSupport().getOperationHistory();
	IUndoContext undoContext = workbench.getOperationSupport().getUndoContext();
	operation.addContext(undoContext);
	operationHistory.execute(operation, null, null);
}

Warum verwenden wir überhaupt Widerrufskontexte? Warum verwenden wir keine separaten Unternehmensaktivitäten-Protokolle für separate Ansichten und Editoren? Die Verwendung separater Unternehmensaktivitäten-Protokolle setzt voraus, dass eine bestimmte Ansicht oder ein bestimmter Editor ein eigenes nicht öffentliches Widerrufsprotokoll führt und das ein Widerruf keine globale Bedeutung in der Anwendung hat. Dies mag auf einige Anwendungen zutreffen und in diesen Fällen sollte jede Ansicht oder seinen eigenen, separaten Widerrufskontext erstellen. Andere Anwendungen wollen vielleicht einen globalen Widerruf implementieren, der für alle Benutzeroperationen zutrifft, ungeachtet der Ursprungsansicht oder des Ursprungseditors. In diesem Fall sollte der Workbench-Kontext durch alle Plug-ins verwendet werden, die dem Protokoll Unternehmensaktivitäten hinzufügen.

In komplizierteren Anwendungen ist der Widerruf weder strikt lokal noch strikt global. Stattdessen gibt es eine gewisse Überschneidung zwischen den Widerrufskontexten. Dies kann durch die Zuordnung mehrere Kontexte zu einer Unternehmensaktivität erreicht werden. Zum Beispiel kann eine IDE-Workbench-Ansicht den gesamten Arbeitsbereich bearbeiten und den Arbeitsbereich als ihren Widerrufskontext ansehen. Ein Editor, der bei einer bestimmten Ressource im Arbeitsbereich geöffnet ist, mag seine Unternehmensaktivitäten meist als lokal ansehen. Jedoch können Unternehmensaktivitäten, die innerhalb des Editors ausgeführt werden, sowohl die bestimmte Ressource als auch den Arbeitsbereich als Ganzes betreffen. (Ein gutes Beispiel für diesen Fall ist die JDT-Refactoring-Unterstützung, die die Ausführung von strukturellen Änderungen an einem Java-Element zulässt, während die Quelldatei bearbeitet wird). In diesen Fällen ist es nützlich, wenn man der Unternehmensaktivität beide Widerrufskontexte hinzufügen kann, so dass der Widerruf aus dem Editor selbst sowie aus den Ansichten, die den Arbeitsbereich bearbeiten, erfolgen kann.

Jetzt, da wir die Funktion eines Widerrufskontextes verstehen, wenden wir uns wieder dem Protokoll für IOperationHistory zu. Der folgende Ausschnitt wird verwendet, um einen Widerruf an einem Kontext auszuführen:

IOperationHistory operationHistory = workbench.getOperationSupport().getOperationHistory();
try {
	IStatus status = operationHistory.undo(myContext, progressMonitor, someInfo);
} catch (ExecutionException e) {
	// handhabt die Ausnahme 
}
Das Protokoll erhält die zuletzt ausgeführte Unternehmensaktivität mit dem gegebenen Kontext und verlangt, dass es sich selbst widerruft. Ein anderes Protokoll kann verwendet werden, um das gesamte Widerrufs- oder Wiederholprotokoll für einen Kontext zu erlangen oder um die Unternehmensaktivität zu finden, die in einem bestimmten Kontext widerrufen oder wiederholt werden wird. Der folgende Ausschnitt erlangt die Bezeichnung für die Unternehmensaktivität, die in einem bestimmten Kontext widerrufen werden wird.
IOperationHistory operationHistory = workbench.getOperationSupport().getOperationHistory();
String label = history.getUndoOperation(myContext).getLabel();

Der globale Widerrufskontext IOperationHistory.GLOBAL_UNDO_CONTEXT kann verwendet werden, um auf das globale Widerrufsprotokoll zu verweisen, d.h. auf alle Operationen im Protokoll, ungeachtet ihrer jeweiligen Kontexte. Der folgende Ausschnitt zeigt das globale Widerrufsprotokoll:

IOperationHistory operationHistory = workbench.getOperationSupport().getOperationHistory();
IUndoableOperation [] undoHistory = operationHistory.getUndoHistory(IOperationHistory.GLOBAL_UNDO_CONTEXT);

Immer wenn eine Unternehmensaktivität unter Verwendung eines Unternehmensaktivitäten-Protokolls ausgeführt, widerrufen oder wiederholt wird, können Clients eine Fortschrittsüberwachung und beliebige zusätzliche Benutzerschnittstelleninformationen zur Verfügung stellen, die für die Ausführung der Unternehmensaktivität erforderlich sein können. Diese Informationen werden an die Unternehmensaktivität selbst übergeben. In unserem ursprünglichen Beispiel hat die Readme-Aktion eine Unternehmensaktivität mit einem Shell-Parameter erstellt, der dazu verwendet werden könnte, den Dialog zu öffnen. Statt die Shell in der Unternehmensaktivität zu speichern, ist es besser, Parameter an die Methoden 'execute', 'undo' und 'redo' zu übergeben, die jede Benutzerschnittstelleninformation, die für die Ausführung der Unternehmensaktivität erforderlich ist, zur Verfügung stellt. Diese Parameter werden an die Unternehmensaktivität selbst übergeben.

public void run(org.eclipse.jface.action.IAction action) {
	IUndoableOperation operation = new ReadmeOperation();
	...
	operationHistory.execute(operation, null, infoAdapter);
}
Der infoAdapter ist ein IAdaptable, das minimal die Shell zur Verfügung stellen kann, die beim Starten des Dialogs verwendet wird. Die Unternehmensaktivität in unserem Beispiel würde diesen Parameter wie folgt verwenden:
	public IStatus execute(IProgressMonitor monitor, IAdaptable info) {
		if (info != null) {
			Shell shell = (Shell)info.getAdapter(Shell.class);
			if (shell != null) {
				MessageDialog.openInformation(shell,
		MessageUtil.getString("Readme_Editor"),  
		MessageUtil.getString("View_Action_executed"));   
		return Status.OK_STATUS;
		}
	}
		// macht etwas anderes...
}

Steuerroutinen für Widerrufs- und Wiederholaktionen

Die Plattform stellt standardmäßig Steuerroutinen für Aktionen, die erneut als Ziele verwendet werden können für Widerruf und Wiederholung zur Verfügung, die durch Ansichten und Editoren konfiguriert werden können, um Unterstützung für Widerruf und Wiederholung für ihren bestimmten Kontext zur Verfügung zu stellen. Wenn die Aktionssteuerroutine erstellt ist, wird ihr ein Kontext zugeordnet, so dass das Unternehmensaktivitäten-Protokoll auf eine Weise gefiltert wird, die dieser bestimmten Ansicht entspricht. Die Aktionssteuerroutinen sorgen für die Aktualisierung der Widerrufs- und Wiederholbezeichner, damit diese die gegenwärtig e Unternehmensaktivität anzeigen, stellen dem Unternehmensaktivitäten-Protokoll die entsprechende Fortschrittsüberwachung und Benutzerschnittstelleninformation zur Verfügung und säubern optional das Protokoll, wenn die gegenwärtige Unternehmensaktivität ungültig ist. Eine Aktionsgruppe, die die Aktionssteuerroutinen erstellt und sie den globalen Widerrufs- und Wiederholaktionen zuordnet, wird ebenfalls zur Verfügung gestellt.

new UndoRedoActionGroup(this.getSite(), undoContext, true);
Der letzte Parameter ist ein Boolescher Wert, der anzeigt, ob die Widerrufs- und Wiederholprotokolle für den angegebenen Kontext entfernt werden sollen, wenn die gegenwärtig für Widerruf und Wiederholung zur Verfügung stehende Unternehmensaktivität nicht mehr gültig ist. Die Einstellung für diesen Parameter bezieht sich auf den zur Verfügung gestellten Widerrufskontext und die Validierungstrategie, die durch Unternehmensaktivitäten mit diesem Kontext verwendet wird.

Anwendungswiderrufmodelle

Zuvor haben wir gesehen, wie der Widerrufskontexte dazu verwendet werden können, verschiedene Arten von Anwendungswiderrufmodellen zu implementieren. Die Fähigkeit, Unternehmensaktivitäten einen oder mehrere Kontexte zuzuordnen, ermöglicht es Anwendungen, Widerrufsstrategien zu implementieren, die strikt lokal für jede Ansicht oder jeden Editor, strikt global über alle Plug-ins oder ein dazwischenliegendes Modell sind. Eine andere Entwurfsentscheidung, die Widerruf und Wiederholen betrifft, ist, ob eine Unternehmensaktivität zu jeder Zeit widerrufen oder wiederholt werden kann oder ob das Modell strikt linear ist, wobei nur die letzte Unternehmensaktivität für den Widerruf oder die Wiederholung in Betracht kommt.

IOperationHistory definiert ein Protokoll, das flexible Widerrufsmodelle ermöglicht, wobei es den individuellen Implementierungen überlassen bleibt zu entscheiden, was zulässig ist. Das Widerrufs- und Wiederholprotokoll, das wir bisher gesehen haben, geht davon aus, dass in einem bestimmten Widerrufskontext nur eine Unternehmensaktivität für Widerruf oder Wiederholung zur Verfügung steht. Ein zusätzliches Protokoll wird zur Verfügung gestellt, das es Clients ermöglicht, eine spezifische Unternehmensaktivität ungeachtet seiner Position in dem Protokoll auszuführen. Das Unternehmensaktivitäten-Protokoll kann so konfiguriert werden, dass das Modell implementiert werden kann, das einer Anwendung entspricht. Das erfolgt mit einer Schnittstelle, die dazu verwendet wird, jede Anfrage auf Widerruf oder Wiederholung vorab zu genehmigen, bevor die Unternehmensaktivität widerrufen oder wiederholt wird.

Genehmigungsfunktionen für Unternehmensaktivitäten

IOperationApprover definiert das Protokoll für die Genehmigung von Widerruf und Wiederholung einer bestimmten Unternehmensaktivität. Eine Genehmigungsfunktion für Unternehmensaktivitäten ist bei einem Unternehmensaktivitäten-Protokoll installiert. Bestimmte Genehmigungsfunktionen für Unternehmensaktivitäten können wiederum alle Unternehmensaktivitäten auf Gültigkeit überprüfen, die Unternehmensaktivitäten nur bestimmter Kontexte überprüfen, oder eine Eingabeaufforderung an den Benutzer ausgeben, wenn unerwartete Bedingungen in einer Unternehmensaktivität entdeckt werden. Der folgende Ausschnitt zeigt, wie eine Anwendung das Unternehmensaktivitäten-Protokoll konfigurieren könnte, um ein um ein lineares Widerrufsmodell für alle Unternehmensaktivitäten umzusetzen.
IOperationHistory history = OperationHistoryFactory.getOperationHistory();

// Setzt eine Genehmigungsfunktion zu dem Protokoll, die einen Widerruf nicht zulassen wird, wenn es sich nicht um die letzte Aktivität handelt
history.addOperationApprover(new LinearUndoEnforcer());

In diesem Fall wird eine durch das Framework zur Verfügung gestellte Genehmigungsfunktion für Unternehmensaktivitäten, LinearUndoEnforcer, zu dem Protokoll installiert, um den Widerruf oder die Wiederherstellung sämtlicher Operationen, bei denen es sich nicht um die letzten Widerruf- oder Wiederherstellungsoperation in allen Widerrufskontexten handelt, zu verhindern.

Eine andere Genehmigungsfunktion für Unternehmensaktivitäten, LinearUndoViolationUserApprover, stellt die gleiche Bedingung fest und fordert den Benutzer auf, anzugeben, ob die Aktivität fortgesetzt werden darf. Diese Genehmigungsfunktion für Unternehmensaktivitäten kann für einen bestimmten Teil der Workbench installiert werden.

IOperationHistory history = OperationHistoryFactory.getOperationHistory();

// Setzt eine Genehmigungsfunktion zu diesem Abschnitt, die eine Eingabeaufforderung an den Benutzer ausgibt, wenn es sich nicht um die letzte Aktivität handelt
IOperationApprover approver = new LinearUndoViolationUserApprover(myUndoContext, myWorkbenchPart);
history.addOperationApprover(approver);

Plug-in-Entwickler können ihre eigenen Genehmigungsfunktionen für Unternehmensaktivitäten zur Implementierung anwendungsspezifischer Widerrufsmodelle und Genehmigungsstrategien entwickeln und installieren.

Widerruf und die IDE-Workbench

Wir haben Codeausschnitte gesehen, die das Workbench-Protokoll für den Zugriff auf das Unternehmensaktivitäten-Protokoll und den Widerrufskontext der Workbench verwenden. Dies wird mit Hilfe von IWorkbenchOperationSupport erreicht, der von der Workbench erlangt werden kann. Die Vorstellung eines die gesamte Workbench umfassenden Widerrufskontexts ist ziemlich allgemein. Es liegt an der Workbench-Anwendung zu entscheiden, welcher spezifische Bereich durch den Widerrufskontext der Workbench einbezogen wird und welche Ansichten oder Editoren den Workbench-Kontext verwenden, wenn die Widerrufunterstützung zur Verfügung gestellt wird.

Im Falle der Eclipse IDE-Workbench, sollte der Workbench-Widerrufskontext jeder Unternehmensaktivität zugeordnet werden, die den IDE-Arbeitsbereich in seiner Gesamtheit beeinflusst. Dieser Kontext wird durch Ansichten verwendet, die den Arbeitsbereich beeinflussen, wie z.B. den Ressourcen-Navigator. Die IDE-Workbench installiert einen Adapter zu dem Arbeitsbereich für IUndoContext, das den Widerrufskontext zurückgibt. Diese modellbasierte Registrierung ermöglicht es Plug-ins, die den Arbeitsbereich beeinflussen, den entsprechenden Widerrufskontext zu erlangen, selbst wenn sie Headless sind und nicht auf Workbench-Klassen verweisen.

// Abruf des Unternehmensaktivitäten-Protokolls
IOperationHistory history = OperationHistoryFactory.getOperationHistory();

// Erlangung des entsprechenden Widerrufskontexts für mein Modell
IUndoContext workspaceContext = (IUndoContext)ResourcesPlugin.getWorkspace().getAdapter(IUndoContext.class);
if (workspaceContext != null) {
	// Erstellt eine Unternehmensaktivität und ordnet sie dem Kontext zu
}

Andere Plug-ins sollten dieselbe Technik für die Registrierung modellbasierter Widerrufskontexte verwenden.