1 package ini
.trakem2
.utils
;
3 import java
.util
.ArrayList
;
5 import java
.util
.Iterator
;
7 /** A class to represent a generic undo/redo history.
8 * Keeps a list of objects and the current index.
9 * When adding, and the index not being at the last slot, the list is cleared from that point onward.
11 * All added objects must implement the History.Step interface.
13 public class History
{
17 List
<Step
> list
= new ArrayList
<Step
>();
19 /** New unlimited history list. */
22 public History(final int max_size
) {
23 this.max_size
= max_size
;
26 /** Append a new step. If max_size is set, resizes the list if larger than max_size,
27 * and returns all removed elements. Otherwise returns an empty list. */
28 synchronized public List
<Step
> add(final Step step
) {
29 //Utils.log2("adding one step: index= " + index);
31 if (list
.size() > 0) list
.clear();
33 // Crop list: from start to index, inclusive
34 list
= list
.subList(0, index
+1);
36 // TODO above some steps may not be returned!
38 // Check if step is identical to last step in queue
39 if (list
.size() > 0 && list
.get(list
.size()-1).isIdentical(step
)) {
40 //Utils.log2("History: skipping adding and identical undo step");
41 return new ArrayList
<Step
>();
47 //Utils.log2("Added step: index=" + index + " list.size=" + list.size());
49 if (-1 != max_size
) return resize(max_size
);
50 return new ArrayList
<Step
>();
53 /** Appends a step at the end of the list, without modifying the current index.
54 * If max_size is set, resizes the list if larger than max_size. */
55 synchronized public List
<Step
> append(final Step step
) {
56 if (list
.size() > 0) {
57 if (list
.get(list
.size()-1).isIdentical(step
)) {
58 //Utils.log2("History: skipping appending an identical undo step.");
59 return new ArrayList
<Step
>();
63 if (-1 != max_size
) return resize(max_size
);
64 return new ArrayList
<Step
>();
67 synchronized public Step
getCurrent() {
68 if (-1 == index
) return null;
69 return list
.get(index
);
72 /** Returns null if there aren't any more steps to undo. */
73 synchronized public Step
undoOneStep() {
74 if (index
< 0) return null;
75 // Return the current Step at index, then decrease index.
76 if (index
> 0) index
--; // cannot go beyond index 0, the first step
77 return list
.get(index
);
80 /** Returns null if there aren't any more steps to redo. */
81 synchronized public Step
redoOneStep() {
82 if (list
.size() == (index
+1)) return null;
83 return list
.get(++index
);
86 /** Empty all elements from each Step in the list that match the given id, and return them. */
87 synchronized public List
remove(final long id
) {
88 final List al
= new ArrayList();
89 for (final Step step
: list
) {
90 List rm
= step
.remove(id
);
91 if (null != rm
) al
.addAll(rm
);
96 /** Resize to maximum the given size, removing from the beginning. Returns all removed elements, or an empty list if none. */
97 synchronized public List
<Step
> resize(final int size
) {
98 final List
<Step
> al
= new ArrayList
<Step
>();
99 if (list
.size() < size
) return al
;
102 final int cut
= list
.size() - size
;
103 if (index
< cut
) index
= 0;
106 al
.addAll(list
.subList(0, cut
));
107 list
= list
.subList(cut
, list
.size());
111 /** Remove all steps from the list and return them. */
112 synchronized public List
<Step
> clear() {
113 final ArrayList
<Step
> al
= new ArrayList
<Step
>();
119 /** Returns a list with all undo steps. */
120 synchronized public List
<Step
> getAll() {
121 return new ArrayList
<Step
>(list
);
124 synchronized public Step
get(final int i
) {
125 if (i
< 0 || i
>= list
.size()) return null;
129 /** Cut the list after the index, leaving from 0 to index, inclusive, inside.
130 * Returns removed steps. */
131 synchronized public List
<Step
> clip() {
132 final ArrayList
<Step
> al
= new ArrayList
<Step
>();
133 if (indexAtEnd()) return al
;
134 al
.addAll(list
.subList(index
+1, list
.size()));
135 list
= list
.subList(0, index
+1);
139 synchronized public int size() {
143 synchronized public int index() {
147 synchronized public boolean indexAtStart() {
151 synchronized public boolean indexAtEnd() {
152 return (index
+ 1) == list
.size();
155 synchronized public boolean canUndo() {
159 synchronized public boolean canRedo() {
160 return index
< (list
.size() -1);
163 public interface Step
<T
> {
164 /** Remove objects in this step that have the given id,
165 * and return a list of them. */
166 public List
<T
> remove(final long id
);
167 public boolean isEmpty();
168 public boolean isIdentical(final Step step
);