/*
* JBoss, Home of Professional Open Source.
*
* See the LEGAL.txt file distributed with this work for information regarding copyright ownership and licensing.
*
* See the AUTHORS.txt file distributed with this work for a full listing of individual contributors.
*/
package org.teiid.designer.ui.undo;
import java.util.ArrayList;
import java.util.Collection;
import java.util.EventObject;
import java.util.Iterator;
import java.util.List;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.commands.operations.AbstractOperation;
import org.eclipse.core.commands.operations.IOperationHistory;
import org.eclipse.core.commands.operations.IUndoContext;
import org.eclipse.core.commands.operations.OperationHistoryFactory;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.ListenerList;
import org.eclipse.core.runtime.Status;
import org.eclipse.emf.ecore.resource.Resource;
import org.teiid.designer.core.ModelerCore;
import org.teiid.designer.core.container.Container;
import org.teiid.designer.core.transaction.Undoable;
import org.teiid.designer.core.transaction.UndoableListener;
import org.teiid.designer.core.workspace.ModelResource;
import org.teiid.designer.ui.UiConstants;
import org.teiid.designer.ui.editors.ModelEditorManager;
import org.teiid.designer.ui.viewsupport.ModelUtilities;
/**
* ModelerUndoManager is the manager of all UndoableEdits that are generated from ModelerCore.
*
* @since 8.0
*/
public class ModelerUndoManager implements UndoableListener, IUndoManager {
private class ModelerUndoOperation extends AbstractOperation {
private final Undoable edit;
/**
* Create a new operation
*
* @param edit
*/
public ModelerUndoOperation(Undoable edit) {
super(edit.getPresentationName());
this.edit = edit;
addContext(undoContext);
}
@Override
public IStatus execute(IProgressMonitor monitor, IAdaptable info) {
// Changes executed as modelling is processed, so executing one has no
// effect.
return Status.OK_STATUS;
}
@Override
public IStatus redo(IProgressMonitor monitor, IAdaptable info) throws ExecutionException {
IStatus status = null;
// Start txn
boolean requiredStart = ModelerCore.startTxn(false, false, "Redo Edit", this); //$NON-NLS-1$
try {
// redo this edit and put it on the undo stack
edit.redo();
status = Status.OK_STATUS;
}
catch (Exception e) {
String message = UiConstants.Util.getString("ModelerUndoManager.redoErrorMessage", edit.toString()); //$NON-NLS-1$
UiConstants.Util.log(IStatus.ERROR, e, message);
status = IOperationHistory.OPERATION_INVALID_STATUS;
throw new ExecutionException(message);
}
finally {
// If we start txn, commit it
if (requiredStart) {
if (status != null && status.isOK()) {
ModelerCore.commitTxn();
} else {
ModelerCore.rollbackTxn();
}
}
fireEvent();
}
return status;
}
@Override
public IStatus undo(IProgressMonitor monitor, IAdaptable info) throws ExecutionException {
IStatus status = null;
// Start txn
boolean requiredStart = ModelerCore.startTxn(false, false, "Undo Edit", this); //$NON-NLS-1$
try {
edit.undo();
// insure editors are opened for all changed resources
openAllEditors(edit.getResources());
status = Status.OK_STATUS;
}
catch (Exception e) {
String message = UiConstants.Util.getString("ModelerUndoManager.undoErrorMessage", edit.toString()); //$NON-NLS-1$
UiConstants.Util.log(IStatus.ERROR, e, message);
status = IOperationHistory.OPERATION_INVALID_STATUS;
throw new ExecutionException(message);
}
finally {
// If we start txn, commit it
if (requiredStart) {
if (status != null && status.isOK()) {
ModelerCore.commitTxn();
} else {
ModelerCore.rollbackTxn();
}
}
fireEvent();
}
return status;
}
}
// ============================================
// Static Variables
private static ModelerUndoManager instance = new ModelerUndoManager();
// ============================================
// Static Methods
/**
* Get the singleton instance
*
* @return instance
*/
public static ModelerUndoManager getInstance() {
return instance;
}
// ============================================
// Instance Variables
/**
* The registered modeller listeners.
*/
private ListenerList modellerUndoListeners;
/**
* The operation history being used to store the undo history.
*/
private IOperationHistory operationHistory;
/**
* The undo context for this modeller undo manager.
*/
private IUndoContext undoContext;
// ============================================
// Constructors
/*
* Create a ModelerUndoManager for the specified WorkspaceController
* @param controller the WorkspaceController which provides the event channel for this class
*/
private ModelerUndoManager() {
operationHistory = OperationHistoryFactory.getOperationHistory();
modellerUndoListeners = new ListenerList(ListenerList.IDENTITY);
try {
Container modelContainer = ModelerCore.getModelContainer();
undoContext = (IUndoContext) ModelerCore.getWorkspace().getAdapter(IUndoContext.class);
modelContainer.addUndoableEditListener(this);
} catch (CoreException e) {
UiConstants.Util.log(e);
}
}
// ============================================
// Methods
/**
* Add undo listener
*
* @param listener
*/
public void addUndoListener( ModelerUndoListener listener ) {
modellerUndoListeners.add(listener);
}
/**
* Remove undo listener
*
* @param listener
*/
public void removeUndoListener( ModelerUndoListener listener ) {
modellerUndoListeners.remove(listener);
}
/**
* @return undo context
*/
public IUndoContext getUndoContext() {
return undoContext;
}
@Override
public boolean canRedo() {
return OperationHistoryFactory.getOperationHistory().canRedo(undoContext);
}
@Override
public boolean canUndo() {
return OperationHistoryFactory.getOperationHistory().canUndo(undoContext);
}
@Override
public void redo(IProgressMonitor monitor) throws ExecutionException {
if (! canRedo())
return;
try {
monitor.beginTask("Starting redo operation", 1); //$NON-NLS-1$
OperationHistoryFactory.getOperationHistory().redo(getUndoContext(), null, null);
}
finally {
monitor.done();
}
}
@Override
public void undo(IProgressMonitor monitor) throws ExecutionException {
if (! canUndo())
return;
try {
monitor.beginTask("Starting redo operation", 1); //$NON-NLS-1$
OperationHistoryFactory.getOperationHistory().undo(getUndoContext(), null, null);
}
finally {
monitor.done();
}
}
@Override
public void process( Undoable edit ) {
if (!edit.canUndo()) {
return;
}
ModelerUndoOperation operation = new ModelerUndoOperation(edit);
operationHistory.add(operation);
fireEvent();
}
private void fireEvent() {
EventObject event = new EventObject(getInstance());
for (Object listener : modellerUndoListeners.getListeners()) {
((ModelerUndoListener) listener).processEvent(event);
}
}
private void openAllEditors( Collection resources ) {
List changedResources = new ArrayList(resources);
Resource nextRes = null;
ModelResource mr = null;
for (Iterator iter = changedResources.iterator(); iter.hasNext();) {
nextRes = (Resource)iter.next();
mr = ModelUtilities.getModelResource(nextRes, true);
if (mr != null) {
ModelEditorManager.activate(mr, true);
}
}
}
@Override
public String getRedoLabel() {
// Nothing to do
return null;
}
@Override
public String getUndoLabel() {
// Nothing to do
return null;
}
}