/******************************************************************************* * Copyright (c) 2007 Exadel, Inc. and Red Hat, Inc. * Distributed under license by Red Hat, Inc. All rights reserved. * This program is made available under the terms of the * Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Exadel, Inc. and Red Hat, Inc. - initial API and implementation ******************************************************************************/ package org.jboss.tools.common.model.undo; import org.jboss.tools.common.model.XModel; import org.jboss.tools.common.model.XModelObject; import org.jboss.tools.common.model.plugin.ModelPlugin; public class XUndoManager { private XModel model = null; private XUndoableImpl start; private XUndoableImpl current; private int transaction = -1; private Object listener = null; public XUndoManager() { reset(); } public void setModel(XModel model) { this.model = model; } public void reset() { start = new XUndoableT(null); current = start; fire(); } public void undo() { if(!canUndo()) return; current.undo(); current = current.prev(); } public void redo() { if(!canRedo()) return; current = current.next(); current.redo(); } public boolean canUndo() { return (current != start && current.canUndo()); } public boolean canRedo() { return (current.next() != null && current.next().canRedo()); } public void addUndoable(XUndoable u) { XUndoableImpl w = (u instanceof XUndoableImpl) ? (XUndoableImpl)u : new XUndoableT(u); if(current.merge(w)) return; current.setNext(w); current = w; if(transaction >= 0) ++transaction; reduce(); fire(); } private void reduce() { if(transaction >= 0) return; int capacity = 10; XModelObject root = model.getRoot("Preferences"); //$NON-NLS-1$ if(root!=null) { String c = root.getAttributeValue("undo capacity"); //$NON-NLS-1$ try { capacity = Integer.parseInt(c); } catch (NumberFormatException e) { //ignore } } if(capacity == 0) { start.setNext(null); current = start; return; } int i = 0; XUndoableImpl c = current; while(true) { ++i; if(c == start) return; if(i >= capacity) { start.setNext(c); return; } c = c.prev(); } } public XUndoList getList() { XUndoList list = new XUndoList(this); XUndoableImpl u = start; int s = -1; if(u == current) list.setCurrent(s); while(u.next() != null) { u = u.next(); ++s; if(u == current) list.setCurrent(s); XUndoItem item = new XUndoItem(u.getDescription()); item.setIcons(u.icons()); list.add(item); } return list; } public void beginTransaction() { transaction = 0; } public int getTransactionStatus() { return transaction; } public void commitTransaction() { for (int i = 0; i < transaction; i++) current = current.prev(); current.setNext(null); transaction = -1; } public void rollbackTransaction() { for (int i = 0; i < transaction; i++) undo(); current.setNext(null); transaction = -1; fire(); } public void rollbackTransactionInProgress() { if(current.next() != null || !(current instanceof XTransactionUndo)) return; XTransactionUndo t = (XTransactionUndo)current; if(!t.isInProgress()) return; if(t.canUndo()) t.undo(); current = t.prev(); current.setNext(null); fire(); } public void addListener(Object listener) { this.listener = listener; } private void fire() { if(listener == null) return; synchronized (listener) { listener.notify(); } } } class XUndoableT extends XUndoableImpl { private XUndoable delegate = null; public XUndoableT(XUndoable delegate) { this.delegate = delegate; } public void doUndo() {} public void doRedo() {} public boolean canUndo() { return (delegate != null && delegate.canUndo()); } public boolean canRedo() { return (delegate != null && delegate.canRedo()); } }