| /* CompoundEdit.java -- Combines multiple UndoableEdits. |
| Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. |
| |
| This file is part of GNU Classpath. |
| |
| GNU Classpath 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 2, or (at your option) |
| any later version. |
| |
| GNU Classpath 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 GNU Classpath; see the file COPYING. If not, write to the |
| Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
| 02110-1301 USA. |
| |
| Linking this library statically or dynamically with other modules is |
| making a combined work based on this library. Thus, the terms and |
| conditions of the GNU General Public License cover the whole |
| combination. |
| |
| As a special exception, the copyright holders of this library give you |
| permission to link this library with independent modules to produce an |
| executable, regardless of the license terms of these independent |
| modules, and to copy and distribute the resulting executable under |
| terms of your choice, provided that you also meet, for each linked |
| independent module, the terms and conditions of the license of that |
| module. An independent module is a module which is not derived from |
| or based on this library. If you modify this library, you may extend |
| this exception to your version of the library, but you are not |
| obligated to do so. If you do not wish to do so, delete this |
| exception statement from your version. */ |
| |
| |
| package javax.swing.undo; |
| |
| import java.util.Vector; |
| |
| /** |
| * An editing action that consists of multiple |
| * <code>UndoableEdits</code>. |
| * |
| * <p>The use of a <code>CompoundEdit</code> is divided in two separate |
| * phases.</p> |
| * |
| * <ol> |
| * <li>In the first phase, the <code>CompoundEdit</code> is |
| * initialized. After a new instance of <code>CompoundEdit</code> has |
| * been created, {@link #addEdit(UndoableEdit)} is called for each |
| * element of the compound. To terminate the initialization phase, |
| * call {@link #end()}.</li> |
| * <li>In the second phase, the the <code>CompoundEdit</code> can be |
| * used, typically by invoking {@link #undo()} and |
| * {@link #redo()}.</li> |
| * </ol> |
| * |
| * @author Andrew Selkirk (aselkirk@sympatico.ca) |
| * @author Sascha Brawer (brawer@dandelis.ch) |
| */ |
| public class CompoundEdit |
| extends AbstractUndoableEdit |
| { |
| /** |
| * The identifier of this class in object serialization. Determined |
| * using the serialver tool of Sun J2SE 1.4.1_01. |
| */ |
| private static final long serialVersionUID = -6512679249930119683L; |
| |
| |
| /** |
| * The <code>UndoableEdit</code>s being combined into a compound |
| * editing action. |
| */ |
| protected Vector edits; |
| |
| |
| /** |
| * Indicates whether the creation of this CompoundEdit is still in |
| * progress. Initially, the value of this flag is |
| * <code>true</code>. The {@link #end()} method changes the flag to |
| * <code>false</code>. |
| */ |
| private boolean inProgress; |
| |
| |
| /** |
| * Constructs a new CompoundEdit. |
| */ |
| public CompoundEdit() |
| { |
| edits = new Vector(); |
| inProgress = true; |
| } |
| |
| |
| /** |
| * Undoes all edits that are part of of this |
| * <code>CompoundEdit</code>. The compound elements will receive the |
| * <code>undo</code> message in the reverse order of addition. |
| * |
| * @throws CannotUndoException if {@link #canUndo()} returns |
| * <code>false</code>. This can happen if {@link #end()} has not |
| * been called on this <code>CompoundEdit</code>, or if this edit |
| * has already been undone. |
| * |
| * @see #canUndo() |
| * @see #redo() |
| */ |
| public void undo() |
| throws CannotUndoException |
| { |
| // AbstractUndoableEdit.undo() will throw a CannotUndoException if |
| // canUndo returns false. |
| super.undo(); |
| |
| for (int i = edits.size() - 1; i >= 0; i--) |
| ((UndoableEdit) edits.elementAt(i)).undo(); |
| } |
| |
| |
| /** |
| * Redoes all edits that are part of of this |
| * <code>CompoundEdit</code>. The compound elements will receive the |
| * <code>undo</code> message in the same order as they were added. |
| * |
| * @throws CannotRedoException if {@link #canRedo()} returns |
| * <code>false</code>. This can happen if {@link #end()} has not |
| * been called on this <code>CompoundEdit</code>, or if this edit |
| * has already been redone. |
| * |
| * @see #canRedo() |
| * @see #undo() |
| */ |
| public void redo() |
| throws CannotRedoException |
| { |
| // AbstractUndoableEdit.redo() will throw a CannotRedoException if |
| // canRedo returns false. |
| super.redo(); |
| |
| for (int i = 0; i < edits.size(); i++) |
| ((UndoableEdit) edits.elementAt(i)).redo(); |
| } |
| |
| |
| /** |
| * Returns the the <code>UndoableEdit</code> that was last added to |
| * this compound. |
| */ |
| protected UndoableEdit lastEdit() |
| { |
| if (edits.size() == 0) |
| return null; |
| else |
| return (UndoableEdit) edits.elementAt(edits.size() - 1); |
| } |
| |
| |
| /** |
| * Informs this edit action, and all compound edits, that they will |
| * no longer be used. Some actions might use this information to |
| * release resources such as open files. Called by {@link |
| * UndoManager} before this action is removed from the edit queue. |
| * |
| * <p>The compound elements will receive the |
| * <code>die</code> message in the reverse order of addition. |
| */ |
| public void die() |
| { |
| for (int i = edits.size() - 1; i >= 0; i--) |
| ((UndoableEdit) edits.elementAt(i)).die(); |
| |
| super.die(); |
| } |
| |
| |
| /** |
| * Incorporates another editing action into this one, thus forming a |
| * combined edit. |
| * |
| * <p>If this edit’s {@link #end()} method has been called |
| * before, <code>false</code> is returned immediately. Otherwise, |
| * the {@linkplain #lastEdit() last added edit} is given the |
| * opportunity to {@linkplain UndoableEdit#addEdit(UndoableEdit) |
| * incorporate} <code>edit</code>. If this fails, <code>edit</code> |
| * is given the opportunity to {@linkplain |
| * UndoableEdit#replaceEdit(UndoableEdit) replace} the last added |
| * edit. If this fails as well, <code>edit</code> gets added as a |
| * new compound to {@link #edits}. |
| * |
| * @param edit the editing action being added. |
| * |
| * @return <code>true</code> if <code>edit</code> could somehow be |
| * incorporated; <code>false</code> if <code>edit</code> has not |
| * been incorporated because {@link #end()} was called before. |
| */ |
| public boolean addEdit(UndoableEdit edit) |
| { |
| UndoableEdit last; |
| |
| // If end has been called before, do nothing. |
| if (!inProgress) |
| return false; |
| |
| last = lastEdit(); |
| |
| // If edit is the very first edit, just add it to the list. |
| if (last == null) |
| { |
| edits.add(edit); |
| return true; |
| } |
| |
| // Try to incorporate edit into last. |
| if (last.addEdit(edit)) |
| return true; |
| |
| // Try to replace last by edit. |
| if (edit.replaceEdit(last)) |
| { |
| edits.set(edits.size() - 1, edit); |
| return true; |
| } |
| |
| // If everything else has failed, add edit to the list of compound |
| // edits. |
| edits.add(edit); |
| return true; |
| } |
| |
| |
| /** |
| * Informs this <code>CompoundEdit</code> that its construction |
| * phase has been completed. After this method has been called, |
| * {@link #undo()} and {@link #redo()} may be called, {@link |
| * #isInProgress()} will return <code>false</code>, and all attempts |
| * to {@linkplain #addEdit(UndoableEdit) add further edits} will |
| * fail. |
| */ |
| public void end() |
| { |
| inProgress = false; |
| } |
| |
| |
| /** |
| * Determines whether it would be possible to undo this editing |
| * action. The result will be <code>true</code> if {@link #end()} |
| * has been called on this <code>CompoundEdit</code>, {@link #die()} |
| * has not yet been called, and the edit has not been undone |
| * already. |
| * |
| * @return <code>true</code> to indicate that this action can be |
| * undone; <code>false</code> otherwise. |
| * |
| * @see #undo() |
| * @see #canRedo() |
| */ |
| public boolean canUndo() |
| { |
| return !inProgress && super.canUndo(); |
| } |
| |
| |
| /** |
| * Determines whether it would be possible to redo this editing |
| * action. The result will be <code>true</code> if {@link #end()} |
| * has been called on this <code>CompoundEdit</code>, {@link #die()} |
| * has not yet been called, and the edit has not been redone |
| * already. |
| * |
| * @return <code>true</code> to indicate that this action can be |
| * redone; <code>false</code> otherwise. |
| * |
| * @see #redo() |
| * @see #canUndo() |
| */ |
| public boolean canRedo() |
| { |
| return !inProgress && super.canRedo(); |
| } |
| |
| |
| /** |
| * Determines whether the initial construction phase of this |
| * <code>CompoundEdit</code> is still in progress. During this |
| * phase, edits {@linkplain #addEdit(UndoableEdit) may be |
| * added}. After initialization has been terminated by calling |
| * {@link #end()}, {@link #undo()} and {@link #redo()} can be used. |
| * |
| * @return <code>true</code> if the initialization phase is still in |
| * progress; <code>false</code> if {@link #end()} has been called. |
| * |
| * @see #end() |
| */ |
| public boolean isInProgress() |
| { |
| return inProgress; |
| } |
| |
| |
| /** |
| * Determines whether this editing action is significant enough for |
| * being seperately undoable by the user. A typical significant |
| * action would be the resizing of an object. However, changing the |
| * selection in a text document would usually not be considered |
| * significant. |
| * |
| * <p>A <code>CompoundEdit</code> is significant if any of its |
| * elements are significant. |
| */ |
| public boolean isSignificant() |
| { |
| for (int i = edits.size() - 1; i >= 0; i--) |
| if (((UndoableEdit) edits.elementAt(i)).isSignificant()) |
| return true; |
| |
| return false; |
| } |
| |
| |
| /** |
| * Returns a human-readable, localized name that describes this |
| * editing action and can be displayed to the user. |
| * |
| * <p>The implementation delegates the call to the {@linkplain |
| * #lastEdit() last added edit action}. If no edit has been added |
| * yet, the inherited implementation will be invoked, which always |
| * returns an empty string. |
| */ |
| public String getPresentationName() |
| { |
| UndoableEdit last; |
| |
| last = lastEdit(); |
| if (last == null) |
| return super.getPresentationName(); |
| else |
| return last.getPresentationName(); |
| } |
| |
| |
| /** |
| * Calculates a localized message text for presenting the undo |
| * action to the user. |
| * |
| * <p>The implementation delegates the call to the {@linkplain |
| * #lastEdit() last added edit action}. If no edit has been added |
| * yet, the {@linkplain |
| * AbstractUndoableEdit#getUndoPresentationName() inherited |
| * implementation} will be invoked. |
| */ |
| public String getUndoPresentationName() |
| { |
| UndoableEdit last; |
| |
| last = lastEdit(); |
| if (last == null) |
| return super.getUndoPresentationName(); |
| else |
| return last.getUndoPresentationName(); |
| } |
| |
| |
| /** |
| * Calculates a localized message text for presenting the redo |
| * action to the user. |
| * |
| * <p>The implementation delegates the call to the {@linkplain |
| * #lastEdit() last added edit action}. If no edit has been added |
| * yet, the {@linkplain |
| * AbstractUndoableEdit#getRedoPresentationName() inherited |
| * implementation} will be invoked. |
| */ |
| public String getRedoPresentationName() |
| { |
| UndoableEdit last; |
| |
| last = lastEdit(); |
| if (last == null) |
| return super.getRedoPresentationName(); |
| else |
| return last.getRedoPresentationName(); |
| } |
| |
| |
| /** |
| * Calculates a string that may be useful for debugging. |
| */ |
| public String toString() |
| { |
| return super.toString() |
| + " inProgress: " + inProgress |
| + " edits: " + edits; |
| } |
| } |