001: /*******************************************************************************
002: * Copyright (c) 2000, 2006 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.pde.internal.ui.editor;
011:
012: import java.util.List;
013: import java.util.Vector;
014:
015: import org.eclipse.jface.action.IAction;
016: import org.eclipse.osgi.util.NLS;
017: import org.eclipse.pde.core.IModelChangeProvider;
018: import org.eclipse.pde.core.IModelChangedEvent;
019: import org.eclipse.pde.core.IModelChangedListener;
020: import org.eclipse.pde.internal.ui.PDEUIMessages;
021: import org.eclipse.ui.forms.editor.IFormPage;
022:
023: public abstract class ModelUndoManager implements IModelUndoManager,
024: IModelChangedListener {
025: private boolean ignoreChanges;
026: private List operations;
027: private int undoLevelLimit = 10;
028: private int cursor = -1;
029: private IAction undoAction;
030: private IAction redoAction;
031: private PDEFormEditor editor;
032:
033: public ModelUndoManager(PDEFormEditor editor) {
034: this .editor = editor;
035: operations = new Vector();
036: }
037:
038: /*
039: * @see IModelUndoManager#connect(IModelChangeProvider)
040: */
041: public void connect(IModelChangeProvider provider) {
042: provider.addModelChangedListener(this );
043: if (operations == null)
044: initialize();
045: }
046:
047: /*
048: * @see IModelUndoManager#disconnect(IModelChangeProvider)
049: */
050: public void disconnect(IModelChangeProvider provider) {
051: provider.removeModelChangedListener(this );
052: }
053:
054: private void initialize() {
055: operations = new Vector();
056: cursor = -1;
057: updateActions();
058: }
059:
060: /*
061: * @see IModelUndoManager#isUndoable()
062: */
063: public boolean isUndoable() {
064: return cursor >= 0;
065: }
066:
067: /*
068: * @see IModelUndoManager#isRedoable()
069: */
070: public boolean isRedoable() {
071: if (operations == null)
072: initialize();
073: return (cursor + 1) < operations.size();
074: }
075:
076: /*
077: * @see IModelUndoManager#undo()
078: */
079: public void undo() {
080: IModelChangedEvent op = getCurrentOperation();
081: if (op == null)
082: return;
083: ignoreChanges = true;
084: openRelatedPage(op);
085: execute(op, true);
086: cursor--;
087: updateActions();
088: ignoreChanges = false;
089: }
090:
091: /*
092: * @see IModelUndoManager#redo()
093: */
094: public void redo() {
095: cursor++;
096: IModelChangedEvent op = getCurrentOperation();
097: if (op == null)
098: return;
099: ignoreChanges = true;
100: openRelatedPage(op);
101: execute(op, false);
102: ignoreChanges = false;
103: updateActions();
104: }
105:
106: protected abstract String getPageId(Object object);
107:
108: protected abstract void execute(IModelChangedEvent op, boolean undo);
109:
110: private void openRelatedPage(IModelChangedEvent op) {
111: Object obj = op.getChangedObjects()[0];
112: String pageId = getPageId(obj);
113: if (pageId != null) {
114: IFormPage cpage = editor.getActivePageInstance();
115: IFormPage newPage = editor.findPage(pageId);
116: if (cpage != newPage)
117: editor.setActivePage(newPage.getId());
118: }
119: }
120:
121: /*
122: * @see IModelChangedListener#modelChanged(IModelChangedEvent)
123: */
124: public void modelChanged(IModelChangedEvent event) {
125: if (ignoreChanges)
126: return;
127:
128: if (event.getChangeType() == IModelChangedEvent.WORLD_CHANGED) {
129: initialize();
130: return;
131: }
132: addOperation(event);
133: }
134:
135: private IModelChangedEvent getCurrentOperation() {
136: if (cursor == -1 || cursor == operations.size())
137: return null;
138: return (IModelChangedEvent) operations.get(cursor);
139: }
140:
141: private IModelChangedEvent getNextOperation() {
142: int peekCursor = cursor + 1;
143: if (peekCursor >= operations.size())
144: return null;
145: return (IModelChangedEvent) operations.get(peekCursor);
146: }
147:
148: private void addOperation(IModelChangedEvent operation) {
149: operations.add(operation);
150: int size = operations.size();
151: if (size > undoLevelLimit) {
152: int extra = size - undoLevelLimit;
153: // trim
154: for (int i = 0; i < extra; i++) {
155: operations.remove(i);
156: }
157: }
158: cursor = operations.size() - 1;
159: updateActions();
160: }
161:
162: public void setActions(IAction undoAction, IAction redoAction) {
163: this .undoAction = undoAction;
164: this .redoAction = redoAction;
165: updateActions();
166: }
167:
168: private void updateActions() {
169: if (undoAction != null && redoAction != null) {
170: undoAction.setEnabled(isUndoable());
171: undoAction.setText(getUndoText());
172: redoAction.setEnabled(isRedoable());
173: redoAction.setText(getRedoText());
174: }
175: }
176:
177: private String getUndoText() {
178: IModelChangedEvent op = getCurrentOperation();
179: if (op == null) {
180: return PDEUIMessages.UpdateManager_noUndo;
181: }
182: return NLS.bind(PDEUIMessages.UpdateManager_undo,
183: getOperationText(op));
184: }
185:
186: private String getRedoText() {
187: IModelChangedEvent op = getNextOperation();
188: if (op == null) {
189: return PDEUIMessages.UpdateManager_noRedo;
190: }
191: return NLS.bind(PDEUIMessages.UpdateManager_redo,
192: getOperationText(op));
193: }
194:
195: private String getOperationText(IModelChangedEvent op) {
196: String opText = ""; //$NON-NLS-1$
197: switch (op.getChangeType()) {
198: case IModelChangedEvent.INSERT:
199: opText = PDEUIMessages.UpdateManager_op_add;
200: break;
201: case IModelChangedEvent.REMOVE:
202: opText = PDEUIMessages.UpdateManager_op_remove;
203: break;
204: case IModelChangedEvent.CHANGE:
205: opText = PDEUIMessages.UpdateManager_op_change;
206: break;
207: }
208: return opText;
209: }
210:
211: public void setUndoLevelLimit(int limit) {
212: this .undoLevelLimit = limit;
213: }
214:
215: public void setIgnoreChanges(boolean ignore) {
216: this.ignoreChanges = ignore;
217: }
218: }
|