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