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 org.eclipse.core.resources.IResource;
14 import org.eclipse.core.resources.IWorkspace;
15 import org.eclipse.core.runtime.jobs.ISchedulingRule;
17 import net.sourceforge.phpdt.core.IBuffer;
18 import net.sourceforge.phpdt.core.ICompilationUnit;
19 import net.sourceforge.phpdt.core.IJavaElement;
20 import net.sourceforge.phpdt.core.IJavaModelStatus;
21 import net.sourceforge.phpdt.core.IJavaModelStatusConstants;
22 import net.sourceforge.phpdt.core.JavaModelException;
23 import net.sourceforge.phpdt.core.jdom.DOMFactory;
24 import net.sourceforge.phpdt.core.jdom.IDOMCompilationUnit;
25 import net.sourceforge.phpdt.core.jdom.IDOMNode;
26 import net.sourceforge.phpdt.internal.core.jdom.DOMNode;
27 import net.sourceforge.phpdt.internal.core.util.Util;
30 * <p>This abstract class implements behavior common to <code>CreateElementInCUOperations</code>.
31 * To create a compilation unit, or an element contained in a compilation unit, the
32 * source code for the entire compilation unit is updated and saved.
34 * <p>The element being created can be positioned relative to an existing
35 * element in the compilation unit via the methods <code>#createAfter</code>
36 * and <code>#createBefore</code>. By default, the new element is positioned
37 * as the last child of its parent element.
40 public abstract class CreateElementInCUOperation extends JavaModelOperation {
42 * The compilation unit DOM used for this operation
44 protected IDOMCompilationUnit fCUDOM;
46 * A constant meaning to position the new element
47 * as the last child of its parent element.
49 protected static final int INSERT_LAST = 1;
51 * A constant meaning to position the new element
52 * after the element defined by <code>fAnchorElement</code>.
54 protected static final int INSERT_AFTER = 2;
57 * A constant meaning to position the new element
58 * before the element defined by <code>fAnchorElement</code>.
60 protected static final int INSERT_BEFORE = 3;
62 * One of the position constants, describing where
63 * to position the newly created element.
65 protected int fInsertionPolicy = INSERT_LAST;
67 * The element that the newly created element is
68 * positioned relative to, as described by
69 * <code>fInsertPosition</code>, or <code>null</code>
70 * if the newly created element will be positioned
73 protected IJavaElement fAnchorElement = null;
75 * A flag indicating whether creation of a new element occurred.
76 * A request for creating a duplicate element would request in this
77 * flag being set to <code>false</code>. Ensures that no deltas are generated
78 * when creation does not occur.
80 protected boolean fCreationOccurred = true;
82 * The element that is being created.
84 protected DOMNode fCreatedElement;
86 * The position of the element that is being created.
88 protected int fInsertionPosition = -1;
90 * The number of characters the new element replaces,
91 * or 0 if the new element is inserted,
92 * or -1 if the new element is append to the end of the CU.
94 protected int fReplacementLength = -1;
96 * Constructs an operation that creates a Java Language Element with
97 * the specified parent, contained within a compilation unit.
99 public CreateElementInCUOperation(IJavaElement parentElement) {
100 super(null, new IJavaElement[]{parentElement});
101 initializeDefaultPosition();
104 * Only allow cancelling if this operation is not nested.
106 protected void checkCanceled() {
108 super.checkCanceled();
112 * Instructs this operation to position the new element after
113 * the given sibling, or to add the new element as the last child
114 * of its parent if <code>null</code>.
116 public void createAfter(IJavaElement sibling) {
117 setRelativePosition(sibling, INSERT_AFTER);
120 * Instructs this operation to position the new element before
121 * the given sibling, or to add the new element as the last child
122 * of its parent if <code>null</code>.
124 public void createBefore(IJavaElement sibling) {
125 setRelativePosition(sibling, INSERT_BEFORE);
128 * Execute the operation - generate new source for the compilation unit
129 * and save the results.
131 * @exception JavaModelException if the operation is unable to complete
133 protected void executeOperation() throws JavaModelException {
135 beginTask(getMainTaskName(), getMainAmountOfWork());
136 JavaElementDelta delta = newJavaElementDelta();
137 ICompilationUnit unit = getCompilationUnit();
138 generateNewCompilationUnitDOM(unit);
139 if (fCreationOccurred) {
140 //a change has really occurred
141 IBuffer buffer = unit.getBuffer();
142 if (buffer == null) return;
143 char[] bufferContents = buffer.getCharacters();
144 if (bufferContents == null) return;
145 char[] elementContents = net.sourceforge.phpdt.internal.core.util.Util.normalizeCRs(fCreatedElement.getCharacters(), bufferContents);
146 switch (fReplacementLength) {
148 // element is append at the end
149 buffer.append(elementContents);
152 // element is inserted
153 buffer.replace(fInsertionPosition, 0, elementContents);
156 // element is replacing the previous one
157 buffer.replace(fInsertionPosition, fReplacementLength, elementContents);
159 unit.save(null, false);
160 boolean isWorkingCopy = unit.isWorkingCopy();
162 this.setAttribute(HAS_MODIFIED_RESOURCE_ATTR, TRUE);
164 resultElements = generateResultHandles();
165 if (!isWorkingCopy // if unit is working copy, then save will have already fired the delta
166 && !Util.isExcluded(unit)
167 && unit.getParent().exists()) {
168 for (int i = 0; i < resultElements.length; i++) {
169 delta.added(resultElements[i]);
172 } // else unit is created outside classpath
173 // non-java resource delta will be notified by delta processor
180 * Returns a JDOM document fragment for the element being created.
182 protected abstract IDOMNode generateElementDOM() throws JavaModelException;
184 * Returns the DOM with the new source to use for the given compilation unit.
186 protected void generateNewCompilationUnitDOM(ICompilationUnit cu) throws JavaModelException {
187 IBuffer buffer = cu.getBuffer();
188 if (buffer == null) return;
189 char[] prevSource = buffer.getCharacters();
190 if (prevSource == null) return;
192 // create a JDOM for the compilation unit
193 fCUDOM = (new DOMFactory()).createCompilationUnit(prevSource, cu.getElementName());
194 IDOMNode child = generateElementDOM();
196 insertDOMNode(fCUDOM, child);
201 * Creates and returns the handle for the element this operation created.
203 protected abstract IJavaElement generateResultHandle();
205 * Creates and returns the handles for the elements this operation created.
207 protected IJavaElement[] generateResultHandles() throws JavaModelException {
208 return new IJavaElement[]{generateResultHandle()};
211 * Returns the compilation unit in which the new element is being created.
213 protected ICompilationUnit getCompilationUnit() {
214 return getCompilationUnitFor(getParentElement());
217 * Returns the amount of work for the main task of this operation for
218 * progress reporting.
220 protected int getMainAmountOfWork(){
224 * Returns the name of the main task of this operation for
225 * progress reporting.
227 public abstract String getMainTaskName();
229 protected ISchedulingRule getSchedulingRule() {
230 IResource resource = getCompilationUnit().getResource();
231 IWorkspace workspace = resource.getWorkspace();
232 return workspace.getRuleFactory().modifyRule(resource);
235 * Returns the elements created by this operation.
237 public IJavaElement[] getResultElements() {
238 return resultElements;
241 * Sets the default position in which to create the new type
242 * member. By default, the new element is positioned as the
243 * last child of the parent element in which it is created.
244 * Operations that require a different default position must
245 * override this method.
247 protected void initializeDefaultPosition() {
251 * Inserts the given child into the given JDOM,
252 * based on the position settings of this operation.
254 * @see createAfter(IJavaElement)
255 * @see createBefore(IJavaElement);
257 protected void insertDOMNode(IDOMNode parent, IDOMNode child) {
258 if (fInsertionPolicy != INSERT_LAST) {
259 IDOMNode sibling = ((JavaElement)fAnchorElement).findNode(fCUDOM);
260 if (sibling != null && fInsertionPolicy == INSERT_AFTER) {
261 sibling = sibling.getNextNode();
263 if (sibling != null) {
264 sibling.insertSibling(child);
265 fCreatedElement = (DOMNode)child;
266 fInsertionPosition = ((DOMNode)sibling).getStartPosition();
267 fReplacementLength = 0;
271 //add as the last element of the parent
272 parent.addChild(child);
273 fCreatedElement = (DOMNode)child;
274 fInsertionPosition = ((DOMNode)parent).getInsertionPosition();
275 // fInsertionPosition = lastChild == null ? ((DOMNode)parent).getInsertionPosition() : lastChild.getInsertionPosition();
276 fReplacementLength = parent.getParent() == null ? -1 : 0;
279 * Sets the name of the <code>DOMNode</code> that will be used to
280 * create this new element.
281 * Used by the <code>CopyElementsOperation</code> for renaming.
282 * Only used for <code>CreateTypeMemberOperation</code>
284 protected void setAlteredName(String newName) {
287 * Instructs this operation to position the new element relative
288 * to the given sibling, or to add the new element as the last child
289 * of its parent if <code>null</code>. The <code>position</code>
290 * must be one of the position constants.
292 protected void setRelativePosition(IJavaElement sibling, int policy) throws IllegalArgumentException {
293 if (sibling == null) {
294 fAnchorElement = null;
295 fInsertionPolicy = INSERT_LAST;
297 fAnchorElement = sibling;
298 fInsertionPolicy = policy;
302 * Possible failures: <ul>
303 * <li>NO_ELEMENTS_TO_PROCESS - the compilation unit supplied to the operation is
305 * <li>INVALID_NAME - no name, a name was null or not a valid
306 * import declaration name.
307 * <li>INVALID_SIBLING - the sibling provided for positioning is not valid.
309 * @see IJavaModelStatus
310 * @see JavaConventions
312 public IJavaModelStatus verify() {
313 if (getParentElement() == null) {
314 return new JavaModelStatus(IJavaModelStatusConstants.NO_ELEMENTS_TO_PROCESS);
316 if (fAnchorElement != null) {
317 IJavaElement domPresentParent = fAnchorElement.getParent();
318 if (domPresentParent.getElementType() == IJavaElement.IMPORT_CONTAINER) {
319 domPresentParent = domPresentParent.getParent();
321 if (!domPresentParent.equals(getParentElement())) {
322 return new JavaModelStatus(IJavaModelStatusConstants.INVALID_SIBLING, fAnchorElement);
325 return JavaModelStatus.VERIFIED_OK;