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    }