de.tsl2.nano.incubation.repeat.impl.CommandManager Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of tsl2.nano.repeatable Show documentation
Show all versions of tsl2.nano.repeatable Show documentation
TSL2 Framework Repeatable (generic Undo/Redo and Macro mechanism)
/*
* File: $HeadURL$
* Id : $Id$
*
* created by: Tom, Thomas Schneider
* created on: 21.11.2014
*
* Copyright: (c) Thomas Schneider 2014, all rights reserved
*/
package de.tsl2.nano.incubation.repeat.impl;
import java.util.Deque;
import java.util.concurrent.LinkedBlockingDeque;
import de.tsl2.nano.incubation.repeat.IChange;
import de.tsl2.nano.incubation.repeat.ICommand;
import de.tsl2.nano.incubation.repeat.ICommandManager;
/**
* simple implementation of undo/redo and macro mechanism. you have to implement one simple method
* {@link ACommand#runWith(IChange...)} to have undo/redo and macros.
*
* call {@link #doIt(ICommand...)} for each command that should be executed and perhaps un-done through {@link #undo()}.
* only if at least one {@link #undo()} was called, a {@link #redo()} is possible.
*
* Example, creating, deleting a bean and changing its attributes through reflection.
*
*
* @Override
* public void runWith(IChange... changes) {
* for (int i = 0; i < changes.length; i++) {
* if (changes[i].getItem() != null) {
* //while the context can change on item=null, we have to do it inside the loop
* Class<?> type = getContext().getClass();
* BeanClass<Serializable> b = (BeanClass<Serializable>) BeanClass.getBeanClass(type);
* b.setValue(getContext(), (String) changes[i].getItem(), changes[i].getNew());
* } else {
* setContext((Serializable) changes[i].getNew());
* }
* }
* }
*
*
* Macros are available through {@link MacroRecorder}. Call {@link #getRecorder()}
* {@link MacroRecorder#record(String, ICommand...)} with an id (no commands) to start the recording. If recording
* should be finished, call the stop() method and the play(CONTEXT) method to do a replay on the given context object.
*
* @author Tom, Thomas Schneider
* @version $Revision$
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
public class CommandManager implements ICommandManager {
Deque> done;
Deque> undone;
MacroRecorder recorder;
/**
* constructor
*/
public CommandManager() {
this(Integer.MAX_VALUE);
}
/**
* constructor
*
* @param capacity
*/
public CommandManager(int capacity) {
super();
done = new LinkedBlockingDeque>(capacity);
undone = new LinkedBlockingDeque>(capacity);
recorder = new MacroRecorder(capacity);
}
@Override
public boolean doIt(ICommand>... cmd) {
Boolean hasDone = null;
for (int i = 0; i < cmd.length; i++) {
cmd[i].run();
hasDone = (hasDone == null ? true : hasDone) & done.add(cmd[i]);
}
if (recorder.isRecording()) {
recorder.record(null, cmd);
}
return hasDone != null && hasDone;
}
/**
* getDone
* @return all done commands (through calling {@link #doIt(ICommand...)}).
*/
Deque> getDone() {
return done;
}
@Override
public ICommand> undo() {
ICommand> cmd = done.size() > 0 ? done.pollLast() : null;
if (cmd != null) {
undone.add(cmd);
cmd.undo();
}
return cmd;
}
@Override
public ICommand> redo() {
ICommand> cmd = undone.poll();
if (cmd != null) {
doIt(cmd);
}
return cmd;
}
@Override
public boolean canUndo() {
return done.size() > 0;
}
@Override
public boolean canRedo() {
return undone.size() > 0;
}
/**
* getRecorder
*
* @return
*/
public MacroRecorder getRecorder() {
return recorder;
}
}