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.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;
26 import org.eclipse.core.resources.IResource;
27 import org.eclipse.core.resources.IWorkspace;
28 import org.eclipse.core.runtime.jobs.ISchedulingRule;
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.
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.
41 public abstract class CreateElementInCUOperation extends JavaModelOperation {
43 * The compilation unit DOM used for this operation
45 protected IDOMCompilationUnit fCUDOM;
47 * A constant meaning to position the new element
48 * as the last child of its parent element.
50 protected static final int INSERT_LAST = 1;
52 * A constant meaning to position the new element
53 * after the element defined by <code>fAnchorElement</code>.
55 protected static final int INSERT_AFTER = 2;
58 * A constant meaning to position the new element
59 * before the element defined by <code>fAnchorElement</code>.
61 protected static final int INSERT_BEFORE = 3;
63 * One of the position constants, describing where
64 * to position the newly created element.
66 protected int fInsertionPolicy = INSERT_LAST;
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
74 protected IJavaElement fAnchorElement = null;
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.
81 protected boolean fCreationOccurred = true;
83 * The element that is being created.
85 protected DOMNode fCreatedElement;
87 * The position of the element that is being created.
89 protected int fInsertionPosition = -1;
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.
95 protected int fReplacementLength = -1;
97 * Constructs an operation that creates a Java Language Element with
98 * the specified parent, contained within a compilation unit.
100 public CreateElementInCUOperation(IJavaElement parentElement) {
101 super(null, new IJavaElement[]{parentElement});
102 initializeDefaultPosition();
105 * Only allow cancelling if this operation is not nested.
107 protected void checkCanceled() {
109 super.checkCanceled();
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>.
117 public void createAfter(IJavaElement sibling) {
118 setRelativePosition(sibling, INSERT_AFTER);
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>.
125 public void createBefore(IJavaElement sibling) {
126 setRelativePosition(sibling, INSERT_BEFORE);
129 * Execute the operation - generate new source for the compilation unit
130 * and save the results.
132 * @exception JavaModelException if the operation is unable to complete
134 protected void executeOperation() throws JavaModelException {
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) {
149 // element is append at the end
150 buffer.append(elementContents);
153 // element is inserted
154 buffer.replace(fInsertionPosition, 0, elementContents);
157 // element is replacing the previous one
158 buffer.replace(fInsertionPosition, fReplacementLength, elementContents);
160 unit.save(null, false);
161 boolean isWorkingCopy = unit.isWorkingCopy();
163 this.setAttribute(HAS_MODIFIED_RESOURCE_ATTR, TRUE);
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]);
173 } // else unit is created outside classpath
174 // non-java resource delta will be notified by delta processor
181 * Returns a JDOM document fragment for the element being created.
183 protected abstract IDOMNode generateElementDOM() throws JavaModelException;
185 * Returns the DOM with the new source to use for the given compilation unit.
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;
193 // create a JDOM for the compilation unit
194 fCUDOM = (new DOMFactory()).createCompilationUnit(prevSource, cu.getElementName());
195 IDOMNode child = generateElementDOM();
197 insertDOMNode(fCUDOM, child);
202 * Creates and returns the handle for the element this operation created.
204 protected abstract IJavaElement generateResultHandle();
206 * Creates and returns the handles for the elements this operation created.
208 protected IJavaElement[] generateResultHandles() throws JavaModelException {
209 return new IJavaElement[]{generateResultHandle()};
212 * Returns the compilation unit in which the new element is being created.
214 protected ICompilationUnit getCompilationUnit() {
215 return getCompilationUnitFor(getParentElement());
218 * Returns the amount of work for the main task of this operation for
219 * progress reporting.
221 protected int getMainAmountOfWork(){
225 * Returns the name of the main task of this operation for
226 * progress reporting.
228 public abstract String getMainTaskName();
230 protected ISchedulingRule getSchedulingRule() {
231 IResource resource = getCompilationUnit().getResource();
232 IWorkspace workspace = resource.getWorkspace();
233 return workspace.getRuleFactory().modifyRule(resource);
236 * Returns the elements created by this operation.
238 public IJavaElement[] getResultElements() {
239 return resultElements;
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.
248 protected void initializeDefaultPosition() {
252 * Inserts the given child into the given JDOM,
253 * based on the position settings of this operation.
255 * @see createAfter(IJavaElement)
256 * @see createBefore(IJavaElement);
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();
264 if (sibling != null) {
265 sibling.insertSibling(child);
266 fCreatedElement = (DOMNode)child;
267 fInsertionPosition = ((DOMNode)sibling).getStartPosition();
268 fReplacementLength = 0;
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;
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>
285 protected void setAlteredName(String newName) {
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.
293 protected void setRelativePosition(IJavaElement sibling, int policy) throws IllegalArgumentException {
294 if (sibling == null) {
295 fAnchorElement = null;
296 fInsertionPolicy = INSERT_LAST;
298 fAnchorElement = sibling;
299 fInsertionPolicy = policy;
303 * Possible failures: <ul>
304 * <li>NO_ELEMENTS_TO_PROCESS - the compilation unit supplied to the operation is
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.
310 * @see IJavaModelStatus
311 * @see JavaConventions
313 public IJavaModelStatus verify() {
314 if (getParentElement() == null) {
315 return new JavaModelStatus(IJavaModelStatusConstants.NO_ELEMENTS_TO_PROCESS);
317 if (fAnchorElement != null) {
318 IJavaElement domPresentParent = fAnchorElement.getParent();
319 if (domPresentParent.getElementType() == IJavaElement.IMPORT_CONTAINER) {
320 domPresentParent = domPresentParent.getParent();
322 if (!domPresentParent.equals(getParentElement())) {
323 return new JavaModelStatus(IJavaModelStatusConstants.INVALID_SIBLING, fAnchorElement);
326 return JavaModelStatus.VERIFIED_OK;