/**************************************************************************
OmegaT - Computer Assisted Translation (CAT) tool
with fuzzy matching, translation memory, keyword search,
glossaries, and translation leveraging into updated projects.
Copyright (C) 2013 Alex Buloichik
Home page: http://www.omegat.org/
Support center: http://groups.yahoo.com/group/OmegaT/
This file is part of OmegaT.
OmegaT is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OmegaT is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
**************************************************************************/
package org.omegat.gui.editor;
import java.util.ArrayList;
import java.util.List;
import javax.swing.event.DocumentEvent;
import javax.swing.event.UndoableEditEvent;
import javax.swing.event.UndoableEditListener;
import javax.swing.text.AbstractDocument;
import org.omegat.util.gui.UIThreadsUtil;
/**
* Class for process undo/redo operations.
*
* We can't use standard UndoManager because OmegaT changes text attributes,
* which affects on standard UndoManager. Instead, TranslationUndoManager
* remember only text changes. But changed text should be stored only on
* UndoableEditEvent, because composed text chars(Japanese, Chinese) should be
* stored as one char.
*
* @author Alex Buloichik (alex73mail@gmail.com)
*/
public class TranslationUndoManager implements UndoableEditListener {
private final EditorTextArea3 editor;
private final List<Change> undos = new ArrayList<Change>();
private final List<Change> redos = new ArrayList<Change>();
private Change currentState;
private boolean inProgress;
public TranslationUndoManager(EditorTextArea3 editor) {
this.editor = editor;
}
public void reset() {
UIThreadsUtil.mustBeSwingThread();
synchronized (this) {
undos.clear();
redos.clear();
currentState = null;
}
remember(0);
}
public void undo() {
UIThreadsUtil.mustBeSwingThread();
Change ch;
synchronized (this) {
if (undos.isEmpty()) {
return;
}
if (currentState != null) {
redos.add(currentState);
}
ch = currentState = undos.remove(undos.size() - 1);
}
if (ch != null) {
// apply
apply(ch);
}
}
public void redo() {
UIThreadsUtil.mustBeSwingThread();
Change ch;
synchronized (this) {
if (redos.isEmpty()) {
return;
}
if (currentState != null) {
undos.add(currentState);
}
ch = currentState = redos.remove(redos.size() - 1);
}
if (ch != null) {
// apply
apply(ch);
}
}
/**
* Apply change.
*/
void apply(Change ch) {
inProgress = true;
try {
editor.controller.replaceEditText(ch.text);
if (ch.caretPos >= 0) {
editor.setCaretPosition(editor.getOmDocument().getTranslationStart() + ch.caretPos);
}
} finally {
inProgress = false;
}
}
/**
* Remember change.
*/
public void remember(int caretPos) {
UIThreadsUtil.mustBeSwingThread();
synchronized (this) {
Change ch = new Change();
ch.text = editor.getOmDocument().extractTranslation();
if (currentState != null) {
if (ch.text.equals(currentState.text)) return;
currentState.caretPos = caretPos;
undos.add(currentState);
}
currentState = ch;
redos.clear();
}
}
public void undoableEditHappened(UndoableEditEvent e) {
UIThreadsUtil.mustBeSwingThread();
if (inProgress || editor.getOmDocument().trustedChangesInProgress) {
return;
}
AbstractDocument.DefaultDocumentEvent event = (AbstractDocument.DefaultDocumentEvent) e.getEdit();
if (event.getType() == DocumentEvent.EventType.CHANGE) {
// attributes changed
return;
}
int caretPos = event.getOffset() - editor.getOmDocument().getTranslationStart();
if (event.getType() == DocumentEvent.EventType.REMOVE) {
caretPos += event.getLength();
}
remember(caretPos);
}
protected static final class Change {
String text;
int caretPos = -1;
}
}