KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > openide > awt > UndoRedo


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19 package org.openide.awt;
20
21 import org.openide.util.RequestProcessor;
22 import org.openide.util.Task;
23
24 import java.util.LinkedList JavaDoc;
25
26 import javax.swing.event.*;
27 import javax.swing.undo.*;
28
29
30 /** Undo and Redo manager for top components and workspace elements.
31  * It allows <code>UndoAction</code> and <code>RedoAction</code> to listen to editing changes of active
32  * components and to changes in their ability to do undo and redo.
33  *
34  * <p>
35  * <b>Related links:</b>
36  * <ul>
37  * <li><a HREF="@org-openide-actions@/org/openide/actions/UndoAction.html">org.openide.actions.UndoAction</a></li>
38  * <li><a HREF="@org-openide-actions@/org/openide/actions/RedoAction.html">org.openide.actions.RedoAction</a></li>
39  * <li><a HREF="@org-openide-windows@/org/openide/windows/TopComponent.html#getUndoRedo()">org.openide.windows.TopComponent.getUndoRedo()</a></li>
40  * </ul>
41  *
42  * @author Jaroslav Tulach
43 */

44 public interface UndoRedo {
45     /** Empty implementation that does not allow
46     * any undo or redo actions.
47     */

48     public static final UndoRedo NONE = new Empty();
49
50     /** Test whether the component currently has edits which may be undone.
51     * @return <code>true</code> if undo is allowed
52     */

53     public boolean canUndo();
54
55     /** Test whether the component currently has undone edits which may be redone.
56     * @return <code>true</code> if redo is allowed
57     */

58     public boolean canRedo();
59
60     /** Undo an edit.
61     * @exception CannotUndoException if it fails
62     */

63     public void undo() throws CannotUndoException;
64
65     /** Redo a previously undone edit.
66     * @exception CannotRedoException if it fails
67     */

68     public void redo() throws CannotRedoException;
69
70     /** Add a change listener.
71     * The listener will be notified every time the undo/redo
72     * ability of this object changes.
73     * @param l the listener to add
74     */

75     public void addChangeListener(ChangeListener l);
76
77     /** Remove a change listener.
78     * @param l the listener to remove
79     * @see #addChangeListener
80     */

81     public void removeChangeListener(ChangeListener l);
82
83     /** Get a human-presentable name describing the
84     * undo operation.
85     * @return the name
86     */

87     public String JavaDoc getUndoPresentationName();
88
89     /** Get a human-presentable name describing the
90     * redo operation.
91     * @return the name
92     */

93     public String JavaDoc getRedoPresentationName();
94
95     /** An undo manager which fires a change event each time it consumes a new undoable edit.
96     */

97     public static class Manager extends UndoManager implements UndoRedo {
98         static final long serialVersionUID = 6721367974521509720L;
99
100         /** listener list */
101         private final EventListenerList list = new EventListenerList();
102
103         /** vector of Edits to run */
104         private LinkedList JavaDoc<UndoableEditEvent> runus = new LinkedList JavaDoc<UndoableEditEvent>(); // for fix of #8692
105

106         /** task that clears the queue */
107         private Task task = Task.EMPTY; // for fix of #8692
108

109         /** Called from undoableEditHappened() inner class */
110         private void superUndoableEditHappened(UndoableEditEvent ue) {
111             super.undoableEditHappened(ue);
112         }
113
114         /** Called from discardAllEdits() inner class */
115         private void superDiscardAllEdits() {
116             super.discardAllEdits();
117         }
118
119         /** Consume an undoable edit.
120         * Delegates to superclass and notifies listeners.
121         * @param ue the edit
122         */

123         public void undoableEditHappened(final UndoableEditEvent ue) {
124             /* Edits are posted to request processor and the deadlock
125              * in #8692 between undoredo and document that fires
126              * the undoable edit should be avoided this way.
127              */

128             synchronized (runus) {
129                 runus.add(ue);
130             }
131
132             updateTask();
133         }
134
135         /** Discard all the existing edits from the undomanager. */
136         public void discardAllEdits() {
137             synchronized (runus) {
138                 runus.add(null);
139             }
140
141             updateTask();
142         }
143
144         public boolean canUndo() {
145             /* First it must be checked that there are
146              * undoable edits waiting to be added to undoredo.
147              */

148             boolean empty;
149
150             synchronized (runus) {
151                 empty = runus.isEmpty();
152             }
153
154             if (!empty) {
155                 task.waitFinished();
156             }
157
158             return super.canUndo();
159         }
160
161         private void fireChange() {
162             Object JavaDoc[] l = list.getListenerList();
163
164             if (l.length == 0) {
165                 return;
166             }
167
168             ChangeEvent ev = new ChangeEvent(this);
169
170             for (int i = l.length - 1; i >= 0; i -= 2) {
171                 ((ChangeListener) l[i]).stateChanged(ev);
172             }
173         }
174
175         private void updateTask() {
176             /* The following task is finished when there are no
177              * undoable edits waiting to be added to undoredo.
178              */

179             class R implements Runnable JavaDoc {
180                 public void run() {
181                     for (;;) {
182                         UndoableEditEvent ue;
183
184                         synchronized (runus) {
185                             if (runus.isEmpty()) {
186                                 break;
187                             }
188
189                             ue = runus.removeFirst();
190                         }
191
192                         if (ue == null) {
193                             superDiscardAllEdits();
194                         } else {
195                             superUndoableEditHappened(ue);
196                         }
197
198                         fireChange();
199                     }
200                 }
201             }
202
203             R r = new R();
204             r.run();
205
206             //Use internal not default RequestProcessor to solve deadlock #10826
207
//task = internalRequestProcessor.post (r, 0, Thread.MAX_PRIORITY);
208
}
209
210         /* Attaches change listener to the this object.
211         * The listener is notified everytime the undo/redo
212         * ability of this object changes.
213         */

214
215         //#32313 - synchronization of this method was removed
216
public void addChangeListener(ChangeListener l) {
217             list.add(ChangeListener.class, l);
218         }
219
220         /* Removes the listener
221         */

222         public void removeChangeListener(ChangeListener l) {
223             list.remove(ChangeListener.class, l);
224         }
225
226         public String JavaDoc getUndoPresentationName() {
227             return this.canUndo() ? super.getUndoPresentationName() : ""; // NOI18N
228
}
229
230         public String JavaDoc getRedoPresentationName() {
231             return this.canRedo() ? super.getRedoPresentationName() : ""; // NOI18N
232
}
233     }
234
235     // XXX cannot be made private in an interface, consider removing later
236

237     /** Empty implementation that does not support any undoable edits.
238     * @deprecated Use {@link UndoRedo#NONE} rather than instantiating this.
239     */

240     public static final class Empty extends Object JavaDoc implements UndoRedo {
241         public boolean canUndo() {
242             return false;
243         }
244
245         public boolean canRedo() {
246             return false;
247         }
248
249         public void undo() throws CannotUndoException {
250             throw new CannotUndoException();
251         }
252
253         public void redo() throws CannotRedoException {
254             throw new CannotRedoException();
255         }
256
257         public void addChangeListener(ChangeListener l) {
258         }
259
260         public void removeChangeListener(ChangeListener l) {
261         }
262
263         public String JavaDoc getUndoPresentationName() {
264             return ""; // NOI18N
265
}
266
267         public String JavaDoc getRedoPresentationName() {
268             return ""; // NOI18N
269
}
270     }
271 }
272
Popular Tags