
org.openide.text.StableCompoundEdit Maven / Gradle / Ivy
The newest version!
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.openide.text;
import java.util.ArrayList;
import java.util.List;
import javax.swing.UIManager;
import javax.swing.undo.CannotRedoException;
import javax.swing.undo.CannotUndoException;
import javax.swing.undo.UndoableEdit;
/**
* Similar to Swing's {@link javax.swing.undo.CompoundEdit} but guarantees
* stability of internal state even if undo()/redo() throws an exception.
*
* @author Miloslav Metelka
*/
public class StableCompoundEdit implements UndoableEdit {
private static final int HAS_BEEN_DONE = 1;
private static final int ALIVE = 2;
private static final int IN_PROGRESS = 4;
private int statusBits;
private ArrayList edits; // ArrayList due to trim
public StableCompoundEdit() {
statusBits = HAS_BEEN_DONE | ALIVE | IN_PROGRESS;
edits = new ArrayList(4);
}
public final List getEdits() { // Due to BaseDocumentEvent.replaceEdit()
return edits;
}
@Override
public void die() {
clearStatusBits(ALIVE);
int size = edits.size();
for (int i = size-1; i >= 0; i--) {
edits.get(i).die();
}
}
@Override
public void undo() throws CannotUndoException {
if (!canUndo()) {
throw new CannotUndoException();
}
int i = edits.size() - 1;
try {
for (; i >= 0; i--) {
edits.get(i).undo();
}
clearStatusBits(HAS_BEEN_DONE);
} finally {
if (i != -1) { // i-th edit's undo failed => redo the ones above
int size = edits.size();
while (++i < size) {
edits.get(i).redo();
}
}
}
}
@Override
public boolean canUndo() {
return isAnyStatusBit(ALIVE) && isAnyStatusBit(HAS_BEEN_DONE) && !isInProgress();
}
@Override
public void redo() throws CannotRedoException {
if (!canRedo()) {
throw new CannotRedoException();
}
int i = 0;
int size = edits.size();
try {
for (; i < size; i++) {
edits.get(i).redo();
}
setStatusBits(HAS_BEEN_DONE);
} finally {
if (i != size) { // i-th edit's redo failed => undo the ones below
while (--i >= 0) {
edits.get(i).undo();
}
}
}
}
@Override
public boolean canRedo() {
return isAnyStatusBit(ALIVE) && !isAnyStatusBit(HAS_BEEN_DONE) && !isInProgress();
}
@Override
public boolean addEdit(UndoableEdit anEdit) {
if (!isInProgress()) {
return false;
} else {
UndoableEdit last = lastEdit();
// If this is the first subedit received, just add it.
// Otherwise, give the last one a chance to absorb the new
// one. If it won't, give the new one a chance to absorb
// the last one.
if (last == null) {
edits.add(anEdit);
}
else if (!last.addEdit(anEdit)) {
if (anEdit.replaceEdit(last)) {
edits.remove(edits.size()-1);
}
edits.add(anEdit);
}
return true;
}
}
@Override
public boolean replaceEdit(UndoableEdit anEdit) {
return false;
}
@Override
public boolean isSignificant() {
int size = edits.size();
for (int i = 0; i < size; i++) {
if (edits.get(i).isSignificant()) {
return true; // At least one is significant
}
}
return false; // None is significant
}
@Override
public String getPresentationName() {
UndoableEdit last = lastEdit();
if (last != null) {
return last.getPresentationName();
} else {
return "";
}
}
@Override
public String getUndoPresentationName() {
UndoableEdit last = lastEdit();
if (last != null) {
return last.getUndoPresentationName();
} else {
String name = getPresentationName();
if (!"".equals(name)) {
name = UIManager.getString("AbstractUndoableEdit.undoText")
+ " " + name;
} else {
name = UIManager.getString("AbstractUndoableEdit.undoText");
}
return name;
}
}
@Override
public String getRedoPresentationName() {
UndoableEdit last = lastEdit();
if (last != null) {
return last.getRedoPresentationName();
} else {
String name = getPresentationName();
if (!"".equals(name)) {
name = UIManager.getString("AbstractUndoableEdit.redoText")
+ " " + name;
} else {
name = UIManager.getString("AbstractUndoableEdit.redoText");
}
return name;
}
}
public void end() {
clearStatusBits(IN_PROGRESS);
edits.trimToSize();
}
public boolean isInProgress() {
return isAnyStatusBit(IN_PROGRESS);
}
protected UndoableEdit lastEdit() {
int count = edits.size();
if (count > 0)
return edits.get(count-1);
else
return null;
}
private boolean isAnyStatusBit(int bits) {
return (statusBits & bits) != 0;
}
private void setStatusBits(int bits) {
statusBits |= bits;
}
private void clearStatusBits(int bits) {
statusBits &= ~bits;
}
@Override
public String toString() {
return super.toString()
+ " hasBeenDone: " + isAnyStatusBit(HAS_BEEN_DONE)
+ " alive: " + isAnyStatusBit(ALIVE)
+ " inProgress: " + isInProgress()
+ " edits: " + edits;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy