001 /**
002 * <copyright>
003 *
004 * Copyright (c) 2002-2006 IBM Corporation and others.
005 * All rights reserved. This program and the accompanying materials
006 * are made available under the terms of the Eclipse Public License v1.0
007 * which accompanies this distribution, and is available at
008 * http://www.eclipse.org/legal/epl-v10.html
009 *
010 * Contributors:
011 * IBM - Initial API and implementation
012 *
013 * </copyright>
014 *
015 * $Id: AbstractCommand.java,v 1.5 2006/12/05 20:19:54 emerks Exp $
016 */
017 package org.eclipse.emf.common.command;
018
019
020 import java.util.Collection;
021 import java.util.Collections;
022
023 import org.eclipse.emf.common.CommonPlugin;
024
025
026 /**
027 * An abstract implementation of a basic command.
028 * Each derived class <bold>must</bold> implement {@link Command#execute} and {@link Command#redo},
029 * <bold>must</bold> either implement {@link #undo} or implement {@link #canUndo} to return false,
030 * and <bold>must</bold> either override {@link #prepare} (this is the preferred approach) or can override {@link #canExecute} directly.
031 *
032 * <p>
033 * It is very convenient to use prepare, as it is guaranteed to be called only once just before canExecute is to be tested.
034 * It can be implemented to create any additional commands that need to be executed,
035 * and the result it yields becomes the permanent cached return value for canExecute.
036 *
037 */
038 public abstract class AbstractCommand implements Command
039 {
040 /**
041 * Keeps track of whether prepare needs to be called.
042 * It is tested in {@link #canExecute} so that {@link #prepare} is called exactly once to ready the command for execution.
043 */
044 protected boolean isPrepared;
045
046 /**
047 * Keeps track of whether the command is executable.
048 * It is set in {@link #canExecute} to the result of calling {@link #prepare}.
049 */
050 protected boolean isExecutable;
051
052 /**
053 * Holds a short textual description of the command
054 * as returned by {@link #getDescription} and set by {@link #setDescription}.
055 */
056 protected String description;
057
058 /**
059 * Holds the label of the command as returned by {@link #getLabel} and set by {@link #setLabel}.
060 */
061 protected String label;
062
063 /**
064 * Creates an empty instance.
065 */
066 protected AbstractCommand()
067 {
068 super();
069 }
070
071 /**
072 * Creates an instance with the given label.
073 * @param label the label.
074 */
075 protected AbstractCommand(String label)
076 {
077 this.label = label;
078 }
079
080 /**
081 * Creates and instance with the given label and description.
082 * @param label the label.
083 * @param description the description.
084 */
085 protected AbstractCommand(String label, String description)
086 {
087 this.label = label;
088 this.description = description;
089 }
090
091 /**
092 * Called at most once in {@link #canExecute} to give the command an opportunity to ready itself for execution.
093 * The returned value is stored in {@link #canExecute}.
094 * In other words, you can override this method to initialize
095 * and to yield a cached value for the all subsequent calls to canExecute.
096 * @return whether the command is executable.
097 */
098 protected boolean prepare()
099 {
100 return false;
101 }
102
103 /**
104 * Calls {@link #prepare},
105 * caches the result in {@link #isExecutable},
106 * and sets {@link #isPrepared} to <code>true</code>;
107 * from then on, it will yield the value of isExecutable.
108 * @return whether the command can execute.
109 */
110 public boolean canExecute()
111 {
112 if (!isPrepared)
113 {
114 isExecutable = prepare();
115 isPrepared = true;
116 }
117
118 return isExecutable;
119 }
120
121 /**
122 * Returns <code>true</code> because most command should be undoable.
123 * @return <code>true</code>.
124 */
125 public boolean canUndo()
126 {
127 return true;
128 }
129
130 /**
131 * Throws a runtime exception.
132 * @exception UnsupportedOperationException always.
133 */
134 public void undo()
135 {
136 throw
137 new UnsupportedOperationException
138 (CommonPlugin.INSTANCE.getString
139 ("_EXC_Method_not_implemented", new String [] { this.getClass().getName() + ".undo()" }));
140 }
141
142 /**
143 * Returns an empty list.
144 * @return an empty list.
145 */
146 public Collection<?> getResult()
147 {
148 return Collections.EMPTY_LIST;
149 }
150
151 /**
152 * Returns an empty list.
153 * @return an empty list.
154 */
155 public Collection<?> getAffectedObjects()
156 {
157 return Collections.EMPTY_LIST;
158 }
159
160 /*
161 * Javadoc copied from interface.
162 */
163 public String getLabel()
164 {
165 return label == null ? CommonPlugin.INSTANCE.getString("_UI_AbstractCommand_label") : label;
166 }
167
168 /**
169 * Sets the label after construction.
170 * @param label the new label.
171 */
172 public void setLabel(String label)
173 {
174 this.label = label;
175 }
176
177 /*
178 * Javadoc copied from interface.
179 */
180 public String getDescription()
181 {
182 return description == null ? CommonPlugin.INSTANCE.getString("_UI_AbstractCommand_description") : description;
183 }
184
185 /**
186 * Sets the description after construction.
187 * @param description the new description.
188 */
189 public void setDescription(String description)
190 {
191 this.description = description;
192 }
193
194 /**
195 * Creates a new compound command, containing this command and the given command,
196 * that delegates chain to {@link CompoundCommand#append}.
197 * @param command the command to chain with this one.
198 * @return a new chained compound command.
199 */
200 public Command chain(Command command)
201 {
202 class ChainedCompoundCommand extends CompoundCommand
203 {
204 public ChainedCompoundCommand()
205 {
206 super();
207 }
208
209 @Override
210 public Command chain(Command c)
211 {
212 append(c);
213 return this;
214 }
215 }
216
217 CompoundCommand result = new ChainedCompoundCommand();
218 result.append(this);
219 result.append(command);
220 return result;
221 }
222
223 /*
224 * Javadoc copied from interface.
225 */
226 public void dispose()
227 {
228 // Do nothing.
229 }
230
231 /**
232 * Returns an abbreviated name using this object's own class' name, without package qualification,
233 * followed by a space separated list of <tt>field:value</tt> pairs.
234 * @return string representation.
235 */
236 @Override
237 public String toString()
238 {
239 String className = getClass().getName();
240 int lastDotIndex = className.lastIndexOf('.');
241 StringBuffer result = new StringBuffer(lastDotIndex == -1 ? className : className.substring(lastDotIndex + 1));
242 result.append(" (label: " + label + ")");
243 result.append(" (description: " + description + ")");
244 result.append(" (isPrepared: " + isPrepared + ")");
245 result.append(" (isExecutable: " + isExecutable + ")");
246
247 return result.toString();
248 }
249
250 /**
251 * A marker interface implemented by commands that don't dirty the model.
252 */
253 public static interface NonDirtying
254 {
255 // This is just a marker interface.
256 }
257 }