Organized imports
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / core / CreateElementInCUOperation.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2003 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 net.sourceforge.phpdt.internal.core;
12
13 import net.sourceforge.phpdt.core.IBuffer;
14 import net.sourceforge.phpdt.core.ICompilationUnit;
15 import net.sourceforge.phpdt.core.IJavaElement;
16 import net.sourceforge.phpdt.core.IJavaModelStatus;
17 import net.sourceforge.phpdt.core.IJavaModelStatusConstants;
18 import net.sourceforge.phpdt.core.JavaConventions;
19 import net.sourceforge.phpdt.core.JavaModelException;
20 import net.sourceforge.phpdt.core.jdom.DOMFactory;
21 import net.sourceforge.phpdt.core.jdom.IDOMCompilationUnit;
22 import net.sourceforge.phpdt.core.jdom.IDOMNode;
23 import net.sourceforge.phpdt.internal.core.jdom.DOMNode;
24 import net.sourceforge.phpdt.internal.core.util.Util;
25
26 import org.eclipse.core.resources.IResource;
27 import org.eclipse.core.resources.IWorkspace;
28 import org.eclipse.core.runtime.jobs.ISchedulingRule;
29
30 /**
31  * <p>This abstract class implements behavior common to <code>CreateElementInCUOperations</code>.
32  * To create a compilation unit, or an element contained in a compilation unit, the
33  * source code for the entire compilation unit is updated and saved.
34  *
35  * <p>The element being created can be positioned relative to an existing
36  * element in the compilation unit via the methods <code>#createAfter</code>
37  * and <code>#createBefore</code>. By default, the new element is positioned
38  * as the last child of its parent element.
39  *
40  */
41 public abstract class CreateElementInCUOperation extends JavaModelOperation {
42         /**
43          * The compilation unit DOM used for this operation
44          */
45         protected IDOMCompilationUnit fCUDOM;
46         /**
47          * A constant meaning to position the new element
48          * as the last child of its parent element.
49          */
50         protected static final int INSERT_LAST = 1;
51         /**
52          * A constant meaning to position the new element
53          * after the element defined by <code>fAnchorElement</code>.
54          */
55         protected static final int INSERT_AFTER = 2;
56
57         /**
58          * A constant meaning to position the new element
59          * before the element defined by <code>fAnchorElement</code>.
60          */
61         protected static final int INSERT_BEFORE = 3;
62         /**
63          * One of the position constants, describing where
64          * to position the newly created element.
65          */
66         protected int fInsertionPolicy = INSERT_LAST;
67         /**
68          * The element that the newly created element is
69          * positioned relative to, as described by
70          * <code>fInsertPosition</code>, or <code>null</code>
71          * if the newly created element will be positioned
72          * last.
73          */
74         protected IJavaElement fAnchorElement = null;
75         /**
76          * A flag indicating whether creation of a new element occurred.
77          * A request for creating a duplicate element would request in this
78          * flag being set to <code>false</code>. Ensures that no deltas are generated
79          * when creation does not occur.
80          */
81         protected boolean fCreationOccurred = true;
82         /**
83          * The element that is being created.
84          */
85         protected DOMNode fCreatedElement;
86         /**
87          * The position of the element that is being created.
88          */
89         protected int fInsertionPosition = -1;
90         /**
91          * The number of characters the new element replaces,
92          * or 0 if the new element is inserted,
93          * or -1 if the new element is append to the end of the CU.
94          */
95         protected int fReplacementLength = -1;
96         /**
97          * Constructs an operation that creates a Java Language Element with
98          * the specified parent, contained within a compilation unit.
99          */
100         public CreateElementInCUOperation(IJavaElement parentElement) {
101                 super(null, new IJavaElement[]{parentElement});
102                 initializeDefaultPosition();
103         }
104         /**
105          * Only allow cancelling if this operation is not nested.
106          */
107         protected void checkCanceled() {
108                 if (!isNested) {
109                         super.checkCanceled();
110                 }
111         }
112         /**
113          * Instructs this operation to position the new element after
114          * the given sibling, or to add the new element as the last child
115          * of its parent if <code>null</code>.
116          */
117         public void createAfter(IJavaElement sibling) {
118                 setRelativePosition(sibling, INSERT_AFTER);
119         }
120         /**
121          * Instructs this operation to position the new element before
122          * the given sibling, or to add the new element as the last child
123          * of its parent if <code>null</code>.
124          */
125         public void createBefore(IJavaElement sibling) {
126                 setRelativePosition(sibling, INSERT_BEFORE);
127         }
128         /**
129          * Execute the operation - generate new source for the compilation unit
130          * and save the results.
131          *
132          * @exception JavaModelException if the operation is unable to complete
133          */
134         protected void executeOperation() throws JavaModelException {
135                 try {
136                         beginTask(getMainTaskName(), getMainAmountOfWork());
137                         JavaElementDelta delta = newJavaElementDelta();
138                         ICompilationUnit unit = getCompilationUnit();
139                         generateNewCompilationUnitDOM(unit);
140                         if (fCreationOccurred) {
141                                 //a change has really occurred
142                                 IBuffer buffer = unit.getBuffer();
143                                 if (buffer  == null) return;
144                                 char[] bufferContents = buffer.getCharacters();
145                                 if (bufferContents == null) return;
146                                 char[] elementContents = net.sourceforge.phpdt.internal.core.util.Util.normalizeCRs(fCreatedElement.getCharacters(), bufferContents);
147                                 switch (fReplacementLength) {
148                                         case -1 : 
149                                                 // element is append at the end
150                                                 buffer.append(elementContents);
151                                                 break;
152                                         case 0 :
153                                                 // element is inserted
154                                                 buffer.replace(fInsertionPosition, 0, elementContents);
155                                                 break;
156                                         default :
157                                                 // element is replacing the previous one
158                                                 buffer.replace(fInsertionPosition, fReplacementLength, elementContents);
159                                 }
160                                 unit.save(null, false);
161                                 boolean isWorkingCopy = unit.isWorkingCopy();
162                                 if (!isWorkingCopy)
163                                         this.setAttribute(HAS_MODIFIED_RESOURCE_ATTR, TRUE);
164                                 worked(1);
165                                 resultElements = generateResultHandles();
166                                 if (!isWorkingCopy // if unit is working copy, then save will have already fired the delta
167                                                 && !Util.isExcluded(unit)
168                                                 && unit.getParent().exists()) {
169                                         for (int i = 0; i < resultElements.length; i++) {
170                                                 delta.added(resultElements[i]);
171                                         }
172                                         addDelta(delta);
173                                 } // else unit is created outside classpath
174                                   // non-java resource delta will be notified by delta processor
175                         }
176                 } finally {
177                         done();
178                 }
179         }
180         /**
181          * Returns a JDOM document fragment for the element being created.
182          */
183         protected abstract IDOMNode generateElementDOM() throws JavaModelException;
184         /**
185          * Returns the DOM with the new source to use for the given compilation unit.
186          */
187         protected void generateNewCompilationUnitDOM(ICompilationUnit cu) throws JavaModelException {
188                 IBuffer buffer = cu.getBuffer();
189                 if (buffer == null) return;
190                 char[] prevSource = buffer.getCharacters();
191                 if (prevSource == null) return;
192         
193                 // create a JDOM for the compilation unit
194                 fCUDOM = (new DOMFactory()).createCompilationUnit(prevSource, cu.getElementName());
195                 IDOMNode child = generateElementDOM();
196                 if (child != null) {
197                         insertDOMNode(fCUDOM, child);
198                 }
199                 worked(1);
200         }
201         /**
202          * Creates and returns the handle for the element this operation created.
203          */
204         protected abstract IJavaElement generateResultHandle();
205         /**
206          * Creates and returns the handles for the elements this operation created.
207          */
208         protected IJavaElement[] generateResultHandles() throws JavaModelException {
209                 return new IJavaElement[]{generateResultHandle()};
210         }
211         /**
212          * Returns the compilation unit in which the new element is being created.
213          */
214         protected ICompilationUnit getCompilationUnit() {
215                 return getCompilationUnitFor(getParentElement());
216         }
217         /**
218          * Returns the amount of work for the main task of this operation for
219          * progress reporting.
220          */
221         protected int getMainAmountOfWork(){
222                 return 2;
223         }
224         /**
225          * Returns the name of the main task of this operation for
226          * progress reporting.
227          */
228         public abstract String getMainTaskName();
229         
230         protected ISchedulingRule getSchedulingRule() {
231                 IResource resource = getCompilationUnit().getResource();
232                 IWorkspace workspace = resource.getWorkspace();
233                 return workspace.getRuleFactory().modifyRule(resource);
234         }
235         /**
236          * Returns the elements created by this operation.
237          */
238         public IJavaElement[] getResultElements() {
239                 return resultElements;
240         }
241         /**
242          * Sets the default position in which to create the new type
243          * member. By default, the new element is positioned as the
244          * last child of the parent element in which it is created.
245          * Operations that require a different default position must
246          * override this method.
247          */
248         protected void initializeDefaultPosition() {
249         
250         }
251         /**
252          * Inserts the given child into the given JDOM, 
253          * based on the position settings of this operation.
254          *
255          * @see createAfter(IJavaElement)
256          * @see createBefore(IJavaElement);
257          */
258         protected void insertDOMNode(IDOMNode parent, IDOMNode child) {
259                 if (fInsertionPolicy != INSERT_LAST) {
260                         IDOMNode sibling = ((JavaElement)fAnchorElement).findNode(fCUDOM);
261                         if (sibling != null && fInsertionPolicy == INSERT_AFTER) {
262                                 sibling = sibling.getNextNode();
263                         }
264                         if (sibling != null) {
265                                 sibling.insertSibling(child);
266                                 fCreatedElement = (DOMNode)child;
267                                 fInsertionPosition = ((DOMNode)sibling).getStartPosition();
268                                 fReplacementLength = 0;
269                                 return;
270                         }
271                 }
272                 //add as the last element of the parent
273                 parent.addChild(child);
274                 fCreatedElement = (DOMNode)child;
275                 fInsertionPosition = ((DOMNode)parent).getInsertionPosition();
276         //      fInsertionPosition = lastChild == null ? ((DOMNode)parent).getInsertionPosition() : lastChild.getInsertionPosition();
277                 fReplacementLength = parent.getParent() == null ? -1 : 0;
278         }
279         /**
280          * Sets the name of the <code>DOMNode</code> that will be used to
281          * create this new element.
282          * Used by the <code>CopyElementsOperation</code> for renaming.
283          * Only used for <code>CreateTypeMemberOperation</code>
284          */
285         protected void setAlteredName(String newName) {
286         }
287         /**
288          * Instructs this operation to position the new element relative
289          * to the given sibling, or to add the new element as the last child
290          * of its parent if <code>null</code>. The <code>position</code>
291          * must be one of the position constants.
292          */
293         protected void setRelativePosition(IJavaElement sibling, int policy) throws IllegalArgumentException {
294                 if (sibling == null) {
295                         fAnchorElement = null;
296                         fInsertionPolicy = INSERT_LAST;
297                 } else {
298                         fAnchorElement = sibling;
299                         fInsertionPolicy = policy;
300                 }
301         }
302         /**
303          * Possible failures: <ul>
304          *  <li>NO_ELEMENTS_TO_PROCESS - the compilation unit supplied to the operation is
305          *              <code>null</code>.
306          *  <li>INVALID_NAME - no name, a name was null or not a valid
307          *              import declaration name.
308          *  <li>INVALID_SIBLING - the sibling provided for positioning is not valid.
309          * </ul>
310          * @see IJavaModelStatus
311          * @see JavaConventions
312          */
313         public IJavaModelStatus verify() {
314                 if (getParentElement() == null) {
315                         return new JavaModelStatus(IJavaModelStatusConstants.NO_ELEMENTS_TO_PROCESS);
316                 }
317                 if (fAnchorElement != null) {
318                         IJavaElement domPresentParent = fAnchorElement.getParent();
319                         if (domPresentParent.getElementType() == IJavaElement.IMPORT_CONTAINER) {
320                                 domPresentParent = domPresentParent.getParent();
321                         }
322                         if (!domPresentParent.equals(getParentElement())) {
323                                 return new JavaModelStatus(IJavaModelStatusConstants.INVALID_SIBLING, fAnchorElement);
324                         }
325                 }
326                 return JavaModelStatus.VERIFIED_OK;
327         }
328 }