/* * Copyright 2003-2010 Tufts University Licensed under the * Educational Community License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may * obtain a copy of the License at * * http://www.osedu.org/licenses/ECL-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an "AS IS" * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express * or implied. See the License for the specific language governing * permissions and limitations under the License. */ package tufts.vue; abstract class Undoable { public final Object old; // old property value: protected so is visible in sub-classed undo method public Undoable(Object old) { this.old = old; } public Undoable() { old = null; } /** * If your type isn't one we've provided an automatic convenience * conversion for, just override undo(), grab the old value * yourself (it's not private so subclasses can get it) and do a * cast. The convenience conversions just keep the inline class * definitions cleaner & less cluttered. */ void undo() { if (old instanceof Boolean) undo(((Boolean) old).booleanValue()); else if (old instanceof Integer) undo(((Integer) old).intValue()); else if (old instanceof String) undo(((String) old)); else if (old instanceof Float) undo(((Float) old).floatValue()); else if (old instanceof Double) undo(((Double) old).doubleValue()); else if (old instanceof Object[]) undo((Object[]) old); else throw new TypeException(this + ": no automatic type converter for old value of type " + old.getClass() + ": override undo() instead."); } /** * Only one of these will ever be called. Your subclass * should either override one of these, or the generic * undo() above and do your own cast of the old value. */ void undo(boolean b) { throw new TypeException(); } void undo(int i) { throw new TypeException(); } void undo(float f) { throw new TypeException(); } void undo(double d) { throw new TypeException(); } void undo(String s) { throw new TypeException(); } void undo(Object[] a) { throw new TypeException(); } class TypeException extends RuntimeException { TypeException(String msg) { super(msg); } TypeException() { this(Undoable.this + ": must override undo(<type> arg) with argument matching old value type " + old.getClass()); } } @Override public String toString() { java.lang.reflect.Method m = getClass().getEnclosingMethod(); String s = "Undoable:" + getClass().getName() + (m==null?"":("/"+m.getName())); if (old instanceof Object[]) s += "{" + java.util.Arrays.asList((Object[])old) + "}"; else if (old != null) s += "[" + old + "]"; return s; } /* // if can figure out how to make this a static class when created in-line, // can make this a bit more memory efficient as each subclass instance doesn't // need to keep a "this" reference to it's containing class as the undo // manager is already doing that, tho it sure makes the code look // short and sweet to do it this way. void doUndo(LWComponent c) { if (DEBUG.UNDO) System.out.println(this + " restoring " + old); undo(c); } abstract void undo(LWComponent c); */ }