Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: org/eclipse/ltk/core/refactoring/Change.java


1   /*******************************************************************************
2    * Copyright (c) 2000, 2004 IBM Corporation and others.
3    * All rights reserved. This program and the accompanying materials 
4    * are made available under the terms of the Common Public License v1.0
5    * which accompanies this distribution, and is available at
6    * http://www.eclipse.org/legal/cpl-v10.html
7    * 
8    * Contributors:
9    *     IBM Corporation - initial API and implementation
10   *******************************************************************************/
11  package org.eclipse.ltk.core.refactoring;
12  
13  import org.eclipse.core.runtime.CoreException;
14  import org.eclipse.core.runtime.IAdaptable;
15  import org.eclipse.core.runtime.IProgressMonitor;
16  import org.eclipse.core.runtime.OperationCanceledException;
17  
18  import org.eclipse.ltk.internal.core.refactoring.Assert;
19  
20  /**
21   * An abstract base implementation for object representing a generic change 
22   * to the workbench. A <code>Change</code> object is typically created by 
23   * calling <code>Refactoring.createChange()</code>. This class should be
24   * subclassed by clients wishing to provide new changes.
25   * <p>
26   * Changes are best executed by using a {@link PerformChangeOperation}. If clients
27   * execute a change directly then the following life cycle has to be honored:
28   * <ul>
29   *   <li>after a single change or a tree of changes has been created, the
30   *       method <code>initializeValidationState</code> has to be called.</li>
31   *   <li>the method <code>isValid</code> can be used to determine if a change
32   *       can still be applied to the workspace. If the method returns a {@link 
33   *       RefactoringStatus} with a severity of FATAL then the change has to be 
34   *       treated as invalid. Performing an invalid change isn't allowed and 
35   *       results in an unspecified result. This method can be called multiple
36   *       times.
37   *   <li>then the method perform can be called. An disabled change must not
38   *       be executed. The perform method can only be called once. After a change
39   *       as been executed only the method <code>dispose</code> must be called.</li>
40   *   <li>the method dispose has to be called either after the perform method
41   *       has been called or if a change is no longer needed. The second case
42   *       for example occurs when the undo stack gets flushed and all change
43   *       objects managed by the undo stack are no longer needed. The method
44   *       dispose is typically implemented to unregister listeners register during the
45   *       method <code>initializeValidationState</code>. There is no guarantee 
46   *       that <code>initializeValidationState</code>, <code>isValid</code>
47   *       or <code>perform</code> has been called, before <code>dispose</code>
48   *       is called.
49   * </ul>
50   * Below a code snippet that can be used to execute a change:
51   * <pre>
52   *   Change change= createChange();
53   *   try {
54   *     change.initializeValidationState(pm);
55   * 
56   *     ....
57   * 
58   *     if (!change.isEnabled())
59   *         return;
60   *     RefactoringStatus valid= change.isValid(new SubProgressMonitor(pm, 1));
61   *     if (valid.hasFatalError())
62   *         return;
63   *     Change undo= change.perform(new SubProgressMonitor(pm, 1));
64   *     if (undo != null) {
65   *        undo.initializeValidationState(new SubProgressMonitor(pm, 1));
66   *        // do something with the undo object
67   *     }
68   *   } finally {
69   *     change.dispose();
70   *   }
71   * </pre>
72   * </p>
73   * <p>
74   * It is important that implementors of this abstract class provide an adequate 
75   * implementation of <code>isValid</code> and that they provide an undo change
76   * via the return value of the method <code>perform</code>. If no undo can be
77   * provided then the perform method is allowed to return <code>null</code>. But
78   * implementors should be aware that not providing an undo object for a change 
79   * object that is part of a larger change tree will result in the fact that for
80   * the whole change tree no undo object will be present.    
81   * </p>
82   * <p>
83   * Clients may subclass this class.
84   * </p>
85   * 
86   * @since 3.0
87   */
88  public abstract class Change implements IAdaptable {
89  
90    private Change fParent;
91    private boolean fIsEnabled= true;
92    
93    /**
94     * Constructs a new change object.
95     */
96    protected Change() {
97    }
98    
99    /**
100    * Returns the human readable name of this change. The
101    * name <em>MUST</em> not be <code>null</code>.
102    * 
103    * @return the human readable name of this change
104    */
105   public abstract String getName();
106   
107   /**
108    * Returns whether this change is enabled or not. Disabled changes
109    * must not be executed.
110    *
111    * @return <code>true</code> if the change is enabled; <code>false</code>
112    *  otherwise.
113    */
114   public boolean isEnabled() {
115     return fIsEnabled;
116   }
117   
118   /**
119    * Sets whether this change is enabled or not.
120    *
121    * @param enabled <code>true</code> to enable this change; <code>
122    *  false</code> otherwise
123    */
124   public void setEnabled(boolean enabled) {
125     fIsEnabled= enabled;
126   }
127   
128   /**
129    * Returns the parent change. Returns <code>null</code> if no
130    * parent exists.
131    * 
132    * @return the parent change
133    */
134   public Change getParent() {
135     return fParent;
136   }
137   
138   /**
139    * Sets the parent of this change. Requires that this change isn't already
140    * connected to a parent. The parent can be <code>null</code> to disconnect
141    * this change from a parent.
142    * 
143    * @param parent the parent of this change or <code>null</code>
144    */
145   /* package */ void setParent(Change parent) {
146     if (parent != null)
147       Assert.isTrue(fParent == null);
148     fParent= parent;
149   }
150   
151   /**
152    * Hook method to initialize some internal state to provide an adequate answer
153    * for the <code>isValid</code> method. This method gets called after a change
154    * or a whole change tree has been created. 
155    * <p>
156    * Typically this method is implemented in one of the following ways: 
157    * <ul>
158    *   <li>the change hooks up a listener on some delta notification mechanism
159    *       and marks itself as invalid if it receives a certain delta. Is this 
160    *       the case the implementor must take care of unhooking the listener
161    *       in <code>dispose</code>.</li>
162    *   <li>the change remembers some information allowing to decide if a change
163    *       object is still valid when <code>isValid</code> is called.</li>
164    * </ul>
165    * <p>
166    * For example, a change object that manipulates the content of an <code>IFile</code>
167    * could either listen to resource changes and detect that the file got changed or
168    * it could remember some content stamp and compare it with the actual content stamp 
169    * when <code>isValid</code> is called.
170    * </p>
171    * 
172    * @param pm a progress monitor
173    */
174   public abstract void initializeValidationData(IProgressMonitor pm);
175   
176   /**
177    * Verifies that this change object is still valid and can be executed by calling 
178    * <code>perform</code>. If a refactoring status  with a severity of {@link 
179    * RefactoringStatus#FATAL} is returned then the change has to be treated as invalid 
180    * and can no longer be executed. Performing such a change produces an unspecified 
181    * result and will very likely throw an exception.
182    * <p>
183    * This method is also called by the {@link IUndoManager UndoManager} to decide if
184    * an undo or redo change is still valid and therefore can be executed.
185    * </p>
186    * 
187    * @param pm a progress monitor.
188    * 
189    * @return a refactoring status describing the outcome of the validation check
190    * 
191    * @throws CoreException if an error occurred during validation check. The change
192    *  is to be treated as invalid if an exception occurs
193    * 
194    * @throws OperationCanceledException if the validation check got cancelled
195    */
196   public abstract RefactoringStatus isValid(IProgressMonitor pm) throws CoreException, OperationCanceledException;
197   
198   /**
199    * Performs this change. If this method is call on an invalid or disabled change 
200    * object the result is unspecified. Changes should in general not respond to
201    * {@link IProgressMonitor#isCanceled()} since canceling a change tree in the
202    * middle of its execution leaves the workspace in a half changed state.   
203    * 
204    * @param pm a progress monitor
205    * 
206    * @return the undo change for this change object or <code>null</code> if no
207    *  undo is provided
208    * 
209    * @throws CoreException if an error occurred during change execution
210    */
211   public abstract Change perform(IProgressMonitor pm) throws CoreException;
212   
213   /**
214    * Disposes this change. Subclasses that override this method typically 
215    * unregister listeners which got registered during the call to <code>
216    * initializeValidationState</code>. 
217    * <p>
218    * Subclasses may override this method.
219    * </p>
220    */
221   public void dispose() {
222     // empty default implementation
223   }
224    
225   /**
226    * Returns the element modified by this <code>Change</code>. The method may return 
227    * <code>null</code> if the change isn't related to an element.
228    * 
229    * @return the element modified by this change
230    */
231   public abstract Object getModifiedElement();
232   
233   /**
234    * {@inheritDoc}
235    */
236   public Object getAdapter(Class adapter) {
237     if (fParent == null)
238       return null;
239     return fParent.getAdapter(adapter);
240   }
241 }