/************************************************************************** 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; } }