KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > emf > common > command > BasicCommandStack


1 /**
2  * <copyright>
3  *
4  * Copyright (c) 2002-2004 IBM Corporation and others.
5  * All rights reserved. This program and the accompanying materials
6  * are made available under the terms of the Eclipse Public License v1.0
7  * which accompanies this distribution, and is available at
8  * http://www.eclipse.org/legal/epl-v10.html
9  *
10  * Contributors:
11  * IBM - Initial API and implementation
12  *
13  * </copyright>
14  *
15  * $Id: BasicCommandStack.java,v 1.8 2005/06/08 05:44:08 nickb Exp $
16  */

17 package org.eclipse.emf.common.command;
18
19
20 import java.util.ArrayList JavaDoc;
21 import java.util.Collection JavaDoc;
22 import java.util.EventObject JavaDoc;
23 import java.util.Iterator JavaDoc;
24 import java.util.List JavaDoc;
25 import java.util.ListIterator JavaDoc;
26
27 import org.eclipse.emf.common.CommonPlugin;
28 import org.eclipse.emf.common.util.WrappedException;
29
30
31 /**
32  * A basic and obvious implementation of an undoable stack of commands.
33  * See {@link Command} for more details about the command methods that this implementation uses.
34  */

35 public class BasicCommandStack implements CommandStack
36 {
37   /**
38    * The list of commands.
39    */

40   protected List JavaDoc commandList;
41
42   /**
43    * The current position within the list from which the next execute, undo, or redo, will be performed.
44    */

45   protected int top;
46
47   /**
48    * The command most recently executed, undone, or redone.
49    */

50   protected Command mostRecentCommand;
51
52   /**
53    * The {@link CommandStackListener}s.
54    */

55   protected Collection JavaDoc listeners;
56
57   /**
58    * The value of {@link #top} when {@link #saveIsDone} is called.
59    */

60   protected int saveIndex = -1;
61
62   /**
63    * Creates a new empty instance.
64    */

65   public BasicCommandStack()
66   {
67     commandList = new ArrayList JavaDoc();
68     top = -1;
69     listeners = new ArrayList JavaDoc();
70   }
71
72   /*
73    * Javadoc copied from interface.
74    */

75   public void execute(Command command)
76   {
77     // If the command is executable, record and execute it.
78
//
79
if (command != null && command.canExecute())
80     {
81       // Clear the list past the top.
82
//
83
for (ListIterator JavaDoc commands = commandList.listIterator(top + 1); commands.hasNext(); commands.remove())
84       {
85         Command otherCommand = (Command)commands.next();
86         otherCommand.dispose();
87       }
88
89       try
90       {
91         command.execute();
92         mostRecentCommand = command;
93         commandList.add(command);
94         ++top;
95       }
96       catch (RuntimeException JavaDoc exception)
97       {
98         handleError(exception);
99
100         mostRecentCommand = null;
101         command.dispose();
102       }
103
104       // This is kind of tricky.
105
// If the saveIndex was in the redo part of the command list which has now been wiped out,
106
// then we can never reach a point where a save is not necessary, not even if we undo all the way back to the beginning.
107
//
108
if (saveIndex >= top)
109       {
110         // This forces isSaveNeded to always be true.
111
//
112
saveIndex = -2;
113       }
114
115       notifyListeners();
116     }
117     else
118     {
119       command.dispose();
120     }
121   }
122
123   /*
124    * Javadoc copied from interface.
125    */

126   public boolean canUndo()
127   {
128     return top != -1 && ((Command)commandList.get(top)).canUndo();
129   }
130
131   /*
132    * Javadoc copied from interface.
133    */

134   public void undo()
135   {
136     if (canUndo())
137     {
138       Command command = (Command)commandList.get(top--);
139       try
140       {
141         command.undo();
142         mostRecentCommand = command;
143       }
144       catch (RuntimeException JavaDoc exception)
145       {
146         handleError(exception);
147
148         mostRecentCommand = null;
149         flush();
150       }
151
152       notifyListeners();
153     }
154   }
155
156   /*
157    * Javadoc copied from interface.
158    */

159   public boolean canRedo()
160   {
161     return top < commandList.size() - 1;
162   }
163
164   /*
165    * Javadoc copied from interface.
166    */

167   public void redo()
168   {
169     if (canRedo())
170     {
171       Command command = (Command)commandList.get(++top);
172       try
173       {
174         command.redo();
175         mostRecentCommand = command;
176       }
177       catch (RuntimeException JavaDoc exception)
178       {
179         handleError(exception);
180
181         mostRecentCommand = null;
182
183         // Clear the list past the top.
184
//
185
for (ListIterator JavaDoc commands = commandList.listIterator(top--); commands.hasNext(); commands.remove())
186         {
187           Command otherCommand = (Command)commands.next();
188           otherCommand.dispose();
189         }
190       }
191
192       notifyListeners();
193     }
194   }
195
196   /*
197    * Javadoc copied from interface.
198    */

199   public void flush()
200   {
201     // Clear the list.
202
//
203
for (ListIterator JavaDoc commands = commandList.listIterator(); commands.hasNext(); commands.remove())
204     {
205       Command command = (Command)commands.next();
206       command.dispose();
207     }
208     commandList.clear();
209     top = -1;
210     saveIndex = -1;
211     notifyListeners();
212     mostRecentCommand = null;
213   }
214
215   /*
216    * Javadoc copied from interface.
217    */

218   public Command getUndoCommand()
219   {
220     return
221       top == -1 || top == commandList.size() ?
222         null :
223         (Command)commandList.get(top);
224   }
225
226   /*
227    * Javadoc copied from interface.
228    */

229   public Command getRedoCommand()
230   {
231     return
232       top + 1 >= commandList.size() ?
233         null :
234         (Command)commandList.get(top + 1);
235   }
236
237   /*
238    * Javadoc copied from interface.
239    */

240   public Command getMostRecentCommand()
241   {
242     return mostRecentCommand;
243   }
244   
245   /*
246    * Javadoc copied from interface.
247    */

248   public void addCommandStackListener(CommandStackListener listener)
249   {
250     listeners.add(listener);
251   }
252
253   /*
254    * Javadoc copied from interface.
255    */

256   public void removeCommandStackListener(CommandStackListener listener)
257   {
258     listeners.remove(listener);
259   }
260   
261   /**
262    * This is called to ensure that {@link CommandStackListener#commandStackChanged} is called for each listener.
263    */

264   protected void notifyListeners()
265   {
266     for (Iterator JavaDoc i = listeners.iterator(); i.hasNext(); )
267     {
268       ((CommandStackListener)i.next()).commandStackChanged(new EventObject JavaDoc(this));
269     }
270   }
271
272   /**
273    * Handles an exception thrown during command execution by loging it with the plugin.
274    */

275   protected void handleError(Exception JavaDoc exception)
276   {
277     CommonPlugin.INSTANCE.log
278       (new WrappedException
279          (CommonPlugin.INSTANCE.getString("_UI_IgnoreException_exception"), exception).fillInStackTrace());
280   }
281
282   /**
283    * Called after a save has been successfully performed.
284    */

285   public void saveIsDone()
286   {
287     // Remember where we are now.
288
//
289
saveIndex = top;
290   }
291
292   /**
293    * Returns whether the model has changes since {@link #saveIsDone} was call the last.
294    * @return whether the model has changes since <code>saveIsDone</code> was call the last.
295    */

296   public boolean isSaveNeeded()
297   {
298     // Only if we are at the remembered index do we NOT need to save.
299
//
300
//return top != saveIndex;
301

302     if (saveIndex < -1)
303     {
304       return true;
305     }
306
307     if (top > saveIndex)
308     {
309       for (int i = top; i > saveIndex; --i)
310       {
311         if (!(commandList.get(i) instanceof AbstractCommand.NonDirtying))
312         {
313           return true;
314         }
315       }
316     }
317     else
318     {
319       for (int i = saveIndex; i > top; --i)
320       {
321         if (!(commandList.get(i) instanceof AbstractCommand.NonDirtying))
322         {
323           return true;
324         }
325       }
326     }
327
328     return false;
329   }
330 }
331
Popular Tags