Major cleanup of Utils class.
[trakem2.git] / ini / trakem2 / utils / History.java
blobbed1bf1923055f12f8466d090b3782429b3a202e
1 package ini.trakem2.utils;
3 import java.util.ArrayList;
4 import java.util.List;
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 {
15 int index = -1;
16 int max_size = -1;
17 List<Step> list = new ArrayList<Step>();
19 /** New unlimited history list. */
20 public History() {}
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);
30 if (-1 == index) {
31 if (list.size() > 0) list.clear();
32 } else {
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>();
44 ++index;
45 list.add(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>();
62 list.add(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);
93 return al;
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;
100 // else:
101 // fix index
102 final int cut = list.size() - size;
103 if (index < cut) index = 0;
104 else index -= cut;
105 // cut list
106 al.addAll(list.subList(0, cut));
107 list = list.subList(cut, list.size());
108 return al;
111 /** Remove all steps from the list and return them. */
112 synchronized public List<Step> clear() {
113 final ArrayList<Step> al = new ArrayList<Step>();
114 al.addAll(list);
115 list.clear();
116 return al;
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;
126 return list.get(i);
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);
136 return al;
139 synchronized public int size() {
140 return list.size();
143 synchronized public int index() {
144 return index;
147 synchronized public boolean indexAtStart() {
148 return 0 == index;
151 synchronized public boolean indexAtEnd() {
152 return (index + 1) == list.size();
155 synchronized public boolean canUndo() {
156 return index > -1;
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);