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
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 package net.sourceforge.phpdt.internal.core;
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;
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.
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.
35 public abstract class CreateElementInCUOperation extends JavaModelOperation {
37 * The compilation unit DOM used for this operation
39 protected IDOMCompilationUnit fCUDOM;
41 * A constant meaning to position the new element
42 * as the last child of its parent element.
44 protected static final int INSERT_LAST = 1;
46 * A constant meaning to position the new element
47 * after the element defined by <code>fAnchorElement</code>.
49 protected static final int INSERT_AFTER = 2;
52 * A constant meaning to position the new element
53 * before the element defined by <code>fAnchorElement</code>.
55 protected static final int INSERT_BEFORE = 3;
57 * One of the position constants, describing where
58 * to position the newly created element.
60 protected int fInsertionPolicy = INSERT_LAST;
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
68 protected IJavaElement fAnchorElement = null;
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.
75 protected boolean fCreationOccurred = true;
77 * The element that is being created.
79 protected DOMNode fCreatedElement;
81 * The position of the element that is being created.
83 protected int fInsertionPosition = -1;
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.
89 protected int fReplacementLength = -1;
91 * Constructs an operation that creates a Java Language Element with
92 * the specified parent, contained within a compilation unit.
94 public CreateElementInCUOperation(IJavaElement parentElement) {
95 super(null, new IJavaElement[]{parentElement});
96 initializeDefaultPosition();
99 * Only allow cancelling if this operation is not nested.
101 protected void checkCanceled() {
103 super.checkCanceled();
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>.
111 public void createAfter(IJavaElement sibling) {
112 setRelativePosition(sibling, INSERT_AFTER);
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>.
119 public void createBefore(IJavaElement sibling) {
120 setRelativePosition(sibling, INSERT_BEFORE);
123 * Execute the operation - generate new source for the compilation unit
124 * and save the results.
126 * @exception JavaModelException if the operation is unable to complete
128 protected void executeOperation() throws JavaModelException {
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) {
143 // element is append at the end
144 buffer.append(elementContents);
147 // element is inserted
148 buffer.replace(fInsertionPosition, 0, elementContents);
151 // element is replacing the previous one
152 buffer.replace(fInsertionPosition, fReplacementLength, elementContents);
154 unit.save(null, false);
155 boolean isWorkingCopy = unit.isWorkingCopy();
157 this.setAttribute(HAS_MODIFIED_RESOURCE_ATTR, TRUE);
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]);
167 } // else unit is created outside classpath
168 // non-java resource delta will be notified by delta processor
175 * Returns a JDOM document fragment for the element being created.
177 protected abstract IDOMNode generateElementDOM() throws JavaModelException;
179 * Returns the DOM with the new source to use for the given compilation unit.
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;
187 // create a JDOM for the compilation unit
188 fCUDOM = (new DOMFactory()).createCompilationUnit(prevSource, cu.getElementName());
189 IDOMNode child = generateElementDOM();
191 insertDOMNode(fCUDOM, child);
196 * Creates and returns the handle for the element this operation created.
198 protected abstract IJavaElement generateResultHandle();
200 * Creates and returns the handles for the elements this operation created.
202 protected IJavaElement[] generateResultHandles() throws JavaModelException {
203 return new IJavaElement[]{generateResultHandle()};
206 * Returns the compilation unit in which the new element is being created.
208 protected ICompilationUnit getCompilationUnit() {
209 return getCompilationUnitFor(getParentElement());
212 * Returns the amount of work for the main task of this operation for
213 * progress reporting.
215 protected int getMainAmountOfWork(){
219 * Returns the name of the main task of this operation for
220 * progress reporting.
222 public abstract String getMainTaskName();
224 * Returns the elements created by this operation.
226 public IJavaElement[] getResultElements() {
227 return fResultElements;
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.
236 protected void initializeDefaultPosition() {
240 * Inserts the given child into the given JDOM,
241 * based on the position settings of this operation.
243 * @see createAfter(IJavaElement)
244 * @see createBefore(IJavaElement);
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();
252 if (sibling != null) {
253 sibling.insertSibling(child);
254 fCreatedElement = (DOMNode)child;
255 fInsertionPosition = ((DOMNode)sibling).getStartPosition();
256 fReplacementLength = 0;
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;
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>
273 protected void setAlteredName(String newName) {
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.
281 protected void setRelativePosition(IJavaElement sibling, int policy) throws IllegalArgumentException {
282 if (sibling == null) {
283 fAnchorElement = null;
284 fInsertionPolicy = INSERT_LAST;
286 fAnchorElement = sibling;
287 fInsertionPolicy = policy;
291 * Possible failures: <ul>
292 * <li>NO_ELEMENTS_TO_PROCESS - the compilation unit supplied to the operation is
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.
298 * @see IJavaModelStatus
299 * @see JavaConventions
301 public IJavaModelStatus verify() {
302 if (getParentElement() == null) {
303 return new JavaModelStatus(IJavaModelStatusConstants.NO_ELEMENTS_TO_PROCESS);
305 if (fAnchorElement != null) {
306 IJavaElement domPresentParent = fAnchorElement.getParent();
307 if (domPresentParent.getElementType() == IJavaElement.IMPORT_CONTAINER) {
308 domPresentParent = domPresentParent.getParent();
310 if (!domPresentParent.equals(getParentElement())) {
311 return new JavaModelStatus(IJavaModelStatusConstants.INVALID_SIBLING, fAnchorElement);
314 return JavaModelStatus.VERIFIED_OK;