W swoim programie chciałem dołączyć funkcję undo i redo. Ponieważ nigdy czegoś takiego nie robiłem poszukałem w internecie i znalazłem następujący art http://www.algosome.com/articles/implementing-undo-redo-java.html
Problem w tym że dziwnie to działa bo podaję na manager tę nieszczęsną wartość 2 więc i potem wykonuję undo więc logika podpowiada że powinno wypisać 1 a nie dwa. Czy ja czegoś tu nie rozumiem ?
Jeżeli masz już określone, że chcesz w ten sposób robić np. z polem tekstowym, to wystarczy naszykować jakąś tablicę klasy Document. Jeśli chcesz zapamiętywać np. 50 zmian, klasę robisz 50-elementową. Po każdej zmianie, w indeksie 0 tablicy wstawiasz nowy obiekt klasy Document wyciągnięty z pola tekstowego, pozostałe przesuwasz, a ostatni kasujesz. Możesz zrobić tak, że w przypadku edycji tekstu każdą dłuższą przerwę w pisaniu (np. 3 sekundy) lub pojawienie się znaku (przecinka, kropki, średnika) uznać za zakończenie aktualnej edycji i wykonanie tego przesunięcia. Później, w razie cofania edycji, pobierasz te poprzednie elementy tablicy, a "usunięte" zapisujesz w innej, tymczasowej. Gdy użytkownik postanowi przywrócić cofnięte, skorzysta z tymczasowej tablicy, a jeżeli po cofnięciu wykona jakąś edycję, to tymczasowa tablica zmienia się w null.
To jest przykład z polem tekstowym, w praktyce możesz zrobić coś podobnego praktycznie wszędzie, nie musząc się bawić w tworzenie jakichś interfejsów i klas implementujących te interfejsy.
Jako że muszę śledzić nie pole tekstowe a listę elementów to standardowe rozwiązania ze swinga mnie nie urządzają. Poza tym nie korzystam ze swinga tylko z JavaFX. Przysiadłem i udało mi się naklepać następującego twora.
public class ChangeManager<K> {
int size = 0;
Node<K> root;
Node<K> current;
public ChangeManager(K item) {
size++;
root = new Node<>(null, null, item);
current = root;
}
public void addChange(K item){
size++;
Node<K> tep = current;
current = new Node<>(tep, null, item);
tep.nastepny = current;
}
public boolean canUndo(){
if(current.poprzedni!=null)return true;
return false;
}
public boolean canRedo(){
if(current.nastepny!=null)return true;
return false;
}
public K undo(){
if(canUndo()){
size--;
current = current.poprzedni;
return current.obiekt;
}else{
throw new UnsupportedOperationException("Nothing to undo");
}
}
public K redo(){
if(canRedo()){
size++;
current = current.nastepny;
return current.obiekt;
}else{
throw new UnsupportedOperationException("Nothing to redo");
}
}
public int getSize(){
return size;
}
private class Node<K>{
Node<K> poprzedni;
Node<K> nastepny;
K obiekt;
public Node(Node<K> poprzedni, Node<K> nastepny, K obiekt) {
this.poprzedni = poprzedni;
this.nastepny = nastepny;
this.obiekt = obiekt;
}
}
}
Brakuje jeszcze metody do przycinania listy ale to chyba każdy sobie napisze. Mam nadzieję że komuś się przyda w przyszłości.