1 /*
2  * Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 package javax.swing.undo;
27 
28 import javax.swing.event.*;
29 import java.util.*;
30 
31 /**
32  * A support class used for managing <code>UndoableEdit</code> listeners.
33  *
34  * @author Ray Ryan
35  */
36 public class UndoableEditSupport {
37     protected int updateLevel;
38     protected CompoundEdit compoundEdit;
39     protected Vector<UndoableEditListener> listeners;
40     protected Object realSource;
41 
42     /**
43      * Constructs an <code>UndoableEditSupport</code> object.
44      */
UndoableEditSupport()45     public UndoableEditSupport() {
46         this(null);
47     }
48 
49     /**
50      * Constructs an <code>UndoableEditSupport</code> object.
51      *
52      * @param r  an <code>Object</code>
53      */
UndoableEditSupport(Object r)54     public UndoableEditSupport(Object r) {
55         realSource = r == null ? this : r;
56         updateLevel = 0;
57         compoundEdit = null;
58         listeners = new Vector<UndoableEditListener>();
59     }
60 
61     /**
62      * Registers an <code>UndoableEditListener</code>.
63      * The listener is notified whenever an edit occurs which can be undone.
64      *
65      * @param l  an <code>UndoableEditListener</code> object
66      * @see #removeUndoableEditListener
67      */
addUndoableEditListener(UndoableEditListener l)68     public synchronized void addUndoableEditListener(UndoableEditListener l) {
69         listeners.addElement(l);
70     }
71 
72     /**
73      * Removes an <code>UndoableEditListener</code>.
74      *
75      * @param l  the <code>UndoableEditListener</code> object to be removed
76      * @see #addUndoableEditListener
77      */
removeUndoableEditListener(UndoableEditListener l)78     public synchronized void removeUndoableEditListener(UndoableEditListener l)
79     {
80         listeners.removeElement(l);
81     }
82 
83     /**
84      * Returns an array of all the <code>UndoableEditListener</code>s added
85      * to this UndoableEditSupport with addUndoableEditListener().
86      *
87      * @return all of the <code>UndoableEditListener</code>s added or an empty
88      *         array if no listeners have been added
89      * @since 1.4
90      */
getUndoableEditListeners()91     public synchronized UndoableEditListener[] getUndoableEditListeners() {
92         return listeners.toArray(new UndoableEditListener[0]);
93     }
94 
95     /**
96      * Called only from <code>postEdit</code> and <code>endUpdate</code>. Calls
97      * <code>undoableEditHappened</code> in all listeners. No synchronization
98      * is performed here, since the two calling methods are synchronized.
99      */
_postEdit(UndoableEdit e)100     protected void _postEdit(UndoableEdit e) {
101         UndoableEditEvent ev = new UndoableEditEvent(realSource, e);
102         Enumeration cursor = ((Vector)listeners.clone()).elements();
103         while (cursor.hasMoreElements()) {
104             ((UndoableEditListener)cursor.nextElement()).
105                 undoableEditHappened(ev);
106         }
107     }
108 
109     /**
110      * DEADLOCK WARNING: Calling this method may call
111      * <code>undoableEditHappened</code> in all listeners.
112      * It is unwise to call this method from one of its listeners.
113      */
postEdit(UndoableEdit e)114     public synchronized void postEdit(UndoableEdit e) {
115         if (updateLevel == 0) {
116             _postEdit(e);
117         } else {
118             // PENDING(rjrjr) Throw an exception if this fails?
119             compoundEdit.addEdit(e);
120         }
121     }
122 
123     /**
124      * Returns the update level value.
125      *
126      * @return an integer representing the update level
127      */
getUpdateLevel()128     public int getUpdateLevel() {
129         return updateLevel;
130     }
131 
132     /**
133      *
134      */
beginUpdate()135     public synchronized void beginUpdate() {
136         if (updateLevel == 0) {
137             compoundEdit = createCompoundEdit();
138         }
139         updateLevel++;
140     }
141 
142     /**
143      * Called only from <code>beginUpdate</code>.
144      * Exposed here for subclasses' use.
145      */
createCompoundEdit()146     protected CompoundEdit createCompoundEdit() {
147         return new CompoundEdit();
148     }
149 
150     /**
151      * DEADLOCK WARNING: Calling this method may call
152      * <code>undoableEditHappened</code> in all listeners.
153      * It is unwise to call this method from one of its listeners.
154      */
endUpdate()155     public synchronized void endUpdate() {
156         updateLevel--;
157         if (updateLevel == 0) {
158             compoundEdit.end();
159             _postEdit(compoundEdit);
160             compoundEdit = null;
161         }
162     }
163 
164     /**
165      * Returns a string that displays and identifies this
166      * object's properties.
167      *
168      * @return a <code>String</code> representation of this object
169      */
toString()170     public String toString() {
171         return super.toString() +
172             " updateLevel: " + updateLevel +
173             " listeners: " + listeners +
174             " compoundEdit: " + compoundEdit;
175     }
176 }
177