hu.webarticum.chm.LinearHistory Maven / Gradle / Ivy
package hu.webarticum.chm;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
/**
* Traditional linear history implementation.
*
* All roll-backed command will be removed after a new command added.
* Optionally continuously keeps size under a specified capacity.
*/
public class LinearHistory implements History {
private int capacity;
private LinkedList queue = new LinkedList();
private int position = 0;
private final List listeners = new ArrayList(1);
public LinearHistory() {
this(-1);
}
/**
* @param capacity maximum number of commands in this history
*/
public LinearHistory(int capacity) {
this.capacity = capacity;
}
@Override
public Iterator iterator() {
return Collections.unmodifiableList(queue).iterator();
}
@Override
public boolean isEmpty() {
return queue.isEmpty();
}
@Override
public boolean contains(Command command) {
return queue.contains(command);
}
@Override
public boolean addAndExecute(Command command) {
if (command.execute()) {
while (queue.size() > position) {
queue.remove(position);
}
queue.add(command);
position++;
onChanged(Listener.OperationType.INSERT);
return true;
} else {
return false;
}
}
@Override
public boolean hasNext() {
return (queue.size() > position);
}
@Override
public Command getNext() {
if (hasNext()) {
return queue.get(position);
} else {
return null;
}
}
@Override
public boolean executeNext() {
if (!hasNext()) {
return false;
} else {
Command command = getNext();
if (!command.execute()) {
return false;
} else {
position++;
onChanged(Listener.OperationType.REDO);
return true;
}
}
}
@Override
public boolean hasPrevious() {
return (position > 0);
}
@Override
public Command getPrevious() {
if (hasPrevious()) {
return queue.get(position - 1);
} else {
return null;
}
}
@Override
public boolean rollBackPrevious() {
if (!hasPrevious()) {
return false;
} else {
Command command = getPrevious();
if (!command.rollBack()) {
return false;
} else {
position--;
onChanged(Listener.OperationType.UNDO);
return true;
}
}
}
@Override
public boolean moveBefore(Command command) {
return moveTo(command, true);
}
@Override
public boolean moveAfter(Command command) {
return moveTo(command, false);
}
private boolean moveTo(Command command, boolean before) {
int commandPosition = queue.indexOf(command);
if (commandPosition == position) {
return true;
} else if (commandPosition == (-1)) {
return false;
}
int targetPosition = before ? commandPosition : commandPosition + 1;
if (targetPosition > position) {
for (int i = position; i < targetPosition; i++) {
if (!queue.get(i).execute()) {
position = i;
return false;
}
}
} else if (targetPosition < position) {
for (int i = position - 1; i >= targetPosition; i--) {
if (!queue.get(i).rollBack()) {
position = i + 1;
return false;
}
}
}
position = targetPosition;
onChanged(Listener.OperationType.MOVE);
return true;
}
@Override
public void addListener(Listener listener) {
listeners.add(listener);
}
@Override
public boolean removeListener(Listener listener) {
return listeners.remove(listener);
}
/**
* Changes the capacity of this history.
*
* If the given capacity is less then the current size,
* then a clean will be run.
*
* @param capacity
*/
public void setCapacity(int capacity) {
this.capacity = capacity;
gc();
}
private void onChanged(Listener.OperationType operationType) {
gc();
for (Listener listener: listeners) {
listener.changed(this, operationType);
}
}
private void gc() {
if (capacity >= 0) {
while (queue.size() > capacity) {
queue.removeFirst();
position--;
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy