View Javadoc

1   /*
2    * $Id$
3    *
4    * The contents of this file are subject to the Mozilla Public License 
5    * Version 1.1 (the "License"); you may not use this file except in 
6    * compliance with the License. You may obtain a copy of the License at 
7    * http://www.mozilla.org/MPL/ 
8    *
9    * Software distributed under the License is distributed on an "AS IS" basis, 
10   * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 
11   * for the specific language governing rights and limitations under the License.
12   *
13   * The Original Code is XML Hammer code. (org.xmlhammer.*)
14   *
15   * The Initial Developer of the Original Code is Edwin Dankert. Portions created 
16   * by the Initial Developer are Copyright (C) 2005 - 2006 the Initial Developer. 
17   * All Rights Reserved.
18   *
19   * Contributor(s): Edwin Dankert <edankert@gmail.com>
20   */
21  package org.xmlhammer.gui;
22  
23  import java.util.ArrayList;
24  
25  import javax.swing.event.ChangeEvent;
26  import javax.swing.event.ChangeListener;
27  import javax.swing.event.EventListenerList;
28  import javax.swing.undo.CompoundEdit;
29  import javax.swing.undo.UndoManager;
30  import javax.swing.undo.UndoableEdit;
31  
32  import org.apache.log4j.Logger;
33  
34  public class ProjectUndoManager extends UndoManager {
35      private static final long serialVersionUID = -4923400585127602904L;
36      private EventListenerList listeners = null;
37  
38      private UndoableEdit mark = null;
39      private UndoManager discardableUndoManager = null;
40      private ArrayList<CompoundEdit> compounds = null;
41  
42      private boolean undoing = false;
43      private boolean redoing = false;
44      
45      public ProjectUndoManager() {
46          listeners = new EventListenerList();
47          compounds = new ArrayList<CompoundEdit>();
48          
49          discardableUndoManager = new UndoManager();
50      }
51  
52      @Override
53      public boolean addEdit(UndoableEdit edit) {
54          boolean result = false;
55          
56          if (!undoing && !redoing) {
57              if (compounds.size() == 0) {
58                  Logger.getLogger(getClass()).debug("addEdit("+edit+")");
59      
60                  discardableUndoManager.discardAllEdits();
61                  
62                  result = super.addEdit(edit);
63                  
64                  fireStateChanged();
65              } else {
66                  result = compounds.get(compounds.size()-1).addEdit( edit);
67              }
68          }
69          
70          return result;
71      }
72      
73      public boolean addDiscardableEdit(UndoableEdit edit) {
74          boolean result = false;
75          
76          if (!undoing && !redoing) {
77              result = discardableUndoManager.addEdit(edit);
78              fireStateChanged();
79          }
80          
81          return result;
82      }
83  
84      @Override
85      public void undo() {
86          undoing = true;
87  
88          if (discardableUndoManager.canUndo()) {
89              discardableUndoManager.undo();
90          } else {
91              super.undo();
92          }
93  
94          fireStateChanged();
95          undoing = false;
96      }
97  
98      public void startCompound() {
99          if (!undoing && !redoing) {
100             compounds.add(new CompoundEdit());
101         }
102     }
103 
104     public void endCompound() {
105         if (compounds.size() > 0) {
106             CompoundEdit edit = compounds.remove(compounds.size()-1);
107             edit.end();
108             
109             if (compounds.size() > 0) {
110                 compounds.get(compounds.size()-1).addEdit(edit);
111             } else {
112                 addEdit(edit);
113             }
114         }
115     }
116 
117     public void discardCompound() {
118         if (compounds.size() > 0) {
119             compounds.remove(compounds.size()-1);
120         }
121     }
122 
123     public boolean isCompound() {
124         return compounds.size() > 0;
125     }
126 
127     @Override
128     public void redo() {
129         redoing = true;
130 
131         if (discardableUndoManager.canRedo()) {
132             discardableUndoManager.redo();
133         } else {
134             super.redo();
135         }
136 
137         fireStateChanged();
138         redoing = false;
139     }
140     
141     public void mark() {
142         mark = editToBeUndone();
143     }
144     
145     public boolean isMark() {
146         if (!discardableUndoManager.canUndo()) {
147             return mark == editToBeUndone();
148         }
149         
150         return false;
151     }
152     
153     public void addChangeListener(ChangeListener listener) {
154         listeners.add( ChangeListener.class, listener);
155     }
156 
157     public void removeChangeListener(ChangeListener listener) {
158         listeners.remove( ChangeListener.class, listener);
159     }
160 
161     public synchronized boolean canUndo() {
162         return discardableUndoManager.canUndo() || super.canUndo();
163     }
164 
165     public synchronized boolean canRedo() {
166         return discardableUndoManager.canRedo() || super.canRedo();
167     }
168     
169     public synchronized void discardDiscardableEdits() {
170         discardableUndoManager.discardAllEdits();
171 
172         fireStateChanged();
173     }
174     
175     public synchronized void discardAllEdits() {
176         discardableUndoManager.discardAllEdits();
177         super.discardAllEdits();
178         compounds.clear();
179         
180         fireStateChanged();
181     }
182 
183     protected void fireStateChanged() {
184         // Guaranteed to return a non-null array
185         Object[] list = listeners.getListenerList();
186         
187         // Process the listeners last to first, notifying
188         // those that are interested in this event
189         for ( int i = list.length-2; i >= 0; i -= 2) {
190             if ( list[i] == ChangeListener.class) {
191                 ((ChangeListener)list[i+1]).stateChanged( new ChangeEvent( this));
192             }
193         }
194     }
195 }