created mirror
This commit is contained in:
commit
6764738d92
600 files changed
+87187
No files matched your search
@@ -0,0 +1,220 @@
|
||||
/*
|
||||
UndoList.java
|
||||
*
|
||||
* Copyright (c) 2000, Ted Nelson and Tuomas Lukka
|
||||
*
|
||||
* You may use and distribute under the terms of either the GNU Lesser
|
||||
* General Public License, either version 2 of the license or,
|
||||
* at your choice, any later version. Alternatively, you may use and
|
||||
* distribute under the terms of the XPL.
|
||||
*
|
||||
* See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of
|
||||
* the licenses.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the README
|
||||
* file for more details.
|
||||
*
|
||||
*/
|
||||
/*
|
||||
* Written by Tuomas Lukka
|
||||
*/
|
||||
|
||||
package org.gzigzag;
|
||||
/** An operation on the write-cache list that can be undone
|
||||
* or committed.
|
||||
* At commit time, the operations are traversed in reverse order
|
||||
* so that the committables can remove unnecessary ones from the list.
|
||||
* Commit time may need the undoables to be informed prior to beginning
|
||||
* and definitely after committing.
|
||||
* <p>
|
||||
* The operations are cleverly stored to minimize memory use:
|
||||
* an array of Object refs, some of which are operations and after
|
||||
* them their parameters. The parameters are not stored in the operation
|
||||
* objects in order to avoid creating a new object instance per undoable
|
||||
* operation.
|
||||
* <p>
|
||||
* NOTE: this means that a parameter to an operation CANNOT IMPLEMENT
|
||||
* UndoList.Op itself! That would break the chain. It would need to be
|
||||
* e.g. wrapped into an array.
|
||||
* <p>
|
||||
* So the orders are: undo in reverse, redo in original order and
|
||||
* commit in reverse.
|
||||
*/
|
||||
|
||||
public class UndoList {
|
||||
String rcsid = "$Id: UndoList.java,v 1.10 2000/10/26 18:09:29 tjl Exp $";
|
||||
public static boolean dbg = false;
|
||||
final static void p(String s) { if(dbg) System.out.println(s); }
|
||||
final static void pa(String s) { System.out.println(s); }
|
||||
|
||||
/** An undoable operation.
|
||||
* Classes implementing this class can either be real
|
||||
* operations or simply classes of operations that take
|
||||
* their parameters from the Object array, in order
|
||||
* to save space and use only one instance of the Op object.
|
||||
* @see UndoList
|
||||
* @see ZZCacheDimension
|
||||
*/
|
||||
public interface Op {
|
||||
/** Undo the operation.
|
||||
*/
|
||||
void undo(Object[] list, int nth);
|
||||
/** Redo the operation.
|
||||
*/
|
||||
void redo(Object[] list, int nth);
|
||||
/** Commit the operation.
|
||||
* The operation need not be undoable after a commit.
|
||||
*/
|
||||
void commit(Object[] list, int nth);
|
||||
}
|
||||
|
||||
Object[] ops = new Object[2000];
|
||||
int nops = 0;
|
||||
|
||||
int stamp0;
|
||||
|
||||
int[] stamps = new int[64];
|
||||
int nstamps = 0;
|
||||
|
||||
int nundoes = 0;
|
||||
|
||||
UndoList(int inittime) {
|
||||
stamp0 = inittime;
|
||||
makeStampRoom(1);
|
||||
stamps[nstamps++] = 0;
|
||||
}
|
||||
|
||||
/** Place a timestamp into the operation list.
|
||||
* Undo and redo work on stamped boundaries.
|
||||
* If no operations since last stamp, returns last stamp.
|
||||
*/
|
||||
public int stamp() {
|
||||
p("STAMP!");
|
||||
if(nundoes != 0) return -1;
|
||||
if(stamps[nstamps-1] == nops)
|
||||
return stamp0 + nstamps-1;
|
||||
makeStampRoom(1);
|
||||
stamps[nstamps++] = nops;
|
||||
return stamp0 + nstamps-1;
|
||||
}
|
||||
|
||||
/** Commit the changes up to the present.
|
||||
* Returns the new timestamp.
|
||||
*/
|
||||
public int commit() {
|
||||
finalizeUndo();
|
||||
|
||||
int stampno = stamp();
|
||||
for(int i=nops-1; i>=0; i--) {
|
||||
if(ops[i] instanceof Op)
|
||||
((Op)ops[i]).commit(ops, i);
|
||||
}
|
||||
|
||||
nops = 0;
|
||||
nstamps = 0;
|
||||
nundoes = 0;
|
||||
stamp0 = stampno;
|
||||
stamps[nstamps++] = 0;
|
||||
return stampno;
|
||||
}
|
||||
|
||||
/** Undo operations until the previous timestamp, if possible.
|
||||
* After committing, undo won't work until you stamp again.
|
||||
*/
|
||||
public void undo() {
|
||||
try {
|
||||
int curop = stamps[nstamps-1 - nundoes];
|
||||
p("Undo: "+curop+" "+nstamps+" "+nundoes);
|
||||
// Nothing to do.
|
||||
if(curop == 0) {
|
||||
ZZLogger.log("Can't undo further");
|
||||
return;
|
||||
}
|
||||
int prevop = stamps[nstamps-1 - nundoes - 1];
|
||||
for(int i = curop - 1; i >= prevop; i--) {
|
||||
if(ops[i] instanceof Op) {
|
||||
p("Undo: "+i+" "+ops[i]);
|
||||
((Op)ops[i]).undo(ops, i);
|
||||
}
|
||||
}
|
||||
nundoes += 1;
|
||||
} catch(Exception e) {
|
||||
ZZLogger.exc(e);
|
||||
throw new ZZFatalError("Exception while undoing");
|
||||
}
|
||||
}
|
||||
|
||||
/** Redo operations until the next timestamp, after undo has been
|
||||
* used. Any changes meanwhile make this impossible (branches later??).
|
||||
*/
|
||||
public void redo() {
|
||||
if(nundoes <= 0) {
|
||||
ZZLogger.log("Nothing to redo");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
int curop = stamps[nstamps-1 - nundoes];
|
||||
int nextop = stamps[nstamps-1 - nundoes + 1];
|
||||
for(int i = curop; i < nextop; i++) {
|
||||
if(ops[i] instanceof Op) {
|
||||
p("Undo op: "+i);
|
||||
((Op)ops[i]).redo(ops, i);
|
||||
}
|
||||
}
|
||||
nundoes -= 1;
|
||||
} catch(Exception e) {
|
||||
throw new ZZFatalError("Exception while undoing");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** Finalize the undo: the system will not be able to redo changes
|
||||
* that happened after this.
|
||||
*/
|
||||
public void finalizeUndo() {
|
||||
if(nundoes == 0) return;
|
||||
p("FINALIZE UNDO! "+nundoes);
|
||||
nops = stamps[nstamps-1 - nundoes];
|
||||
nstamps -= nundoes;
|
||||
nundoes = 0;
|
||||
}
|
||||
|
||||
protected final void makeRoom(int n) {
|
||||
if(nops + n >= ops.length) {
|
||||
Object[] opsnew = new Object[ops.length * 2];
|
||||
System.arraycopy(ops, 0, opsnew, 0, nops);
|
||||
ops = opsnew;
|
||||
}
|
||||
}
|
||||
|
||||
protected final void makeStampRoom(int n) {
|
||||
if(nstamps + n >= stamps.length) {
|
||||
int[] stampsnew = new int[stamps.length * 2];
|
||||
System.arraycopy(stamps, 0, stampsnew, 0, nstamps);
|
||||
stamps = stampsnew;
|
||||
}
|
||||
}
|
||||
|
||||
public void add(Op o1, Object o2, Object o3) {
|
||||
if(nundoes != 0) finalizeUndo();
|
||||
makeRoom(3);
|
||||
int i = nops;
|
||||
ops[nops++] = o1;
|
||||
ops[nops++] = o2;
|
||||
ops[nops++] = o3;
|
||||
p("Add 3op: "+i+" "+o1+" "+o2+" "+o3);
|
||||
}
|
||||
public void add(Op o1, Object o2, Object o3, Object o4) {
|
||||
if(nundoes != 0) finalizeUndo();
|
||||
makeRoom(3);
|
||||
int i = nops;
|
||||
ops[nops++] = o1;
|
||||
ops[nops++] = o2;
|
||||
ops[nops++] = o3;
|
||||
ops[nops++] = o4;
|
||||
p("Add 4op: "+i+" "+o1+" "+o2+" "+o3+" "+o4);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in new issue
Block a user