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;
32 * This abstract class implements behavior common to
33 * <code>CreateElementInCUOperations</code>. To create a compilation unit, or
34 * an element contained in a compilation unit, the source code for the entire
35 * compilation unit is updated and saved.
38 * The element being created can be positioned relative to an existing element
39 * in the compilation unit via the methods <code>#createAfter</code> and
40 * <code>#createBefore</code>. By default, the new element is positioned as
41 * the last child of its parent element.
44 public abstract class CreateElementInCUOperation extends JavaModelOperation {
46 * The compilation unit DOM used for this operation
48 protected IDOMCompilationUnit fCUDOM;
51 * A constant meaning to position the new element as the last child of its
54 protected static final int INSERT_LAST = 1;
57 * A constant meaning to position the new element after the element defined
58 * by <code>fAnchorElement</code>.
60 protected static final int INSERT_AFTER = 2;
63 * A constant meaning to position the new element before the element defined
64 * by <code>fAnchorElement</code>.
66 protected static final int INSERT_BEFORE = 3;
69 * One of the position constants, describing where to position the newly
72 protected int fInsertionPolicy = INSERT_LAST;
75 * The element that the newly created element is positioned relative to, as
76 * described by <code>fInsertPosition</code>, or <code>null</code> if
77 * the newly created element will be positioned last.
79 protected IJavaElement fAnchorElement = null;
82 * A flag indicating whether creation of a new element occurred. A request
83 * for creating a duplicate element would request in this flag being set to
84 * <code>false</code>. Ensures that no deltas are generated when creation
87 protected boolean fCreationOccurred = true;
90 * The element that is being created.
92 protected DOMNode fCreatedElement;
95 * The position of the element that is being created.
97 protected int fInsertionPosition = -1;
100 * The number of characters the new element replaces, or 0 if the new
101 * element is inserted, or -1 if the new element is append to the end of the
104 protected int fReplacementLength = -1;
107 * Constructs an operation that creates a Java Language Element with the
108 * specified parent, contained within a compilation unit.
110 public CreateElementInCUOperation(IJavaElement parentElement) {
111 super(null, new IJavaElement[] { parentElement });
112 initializeDefaultPosition();
116 * Only allow cancelling if this operation is not nested.
118 protected void checkCanceled() {
120 super.checkCanceled();
125 * Instructs this operation to position the new element after the given
126 * sibling, or to add the new element as the last child of its parent if
129 public void createAfter(IJavaElement sibling) {
130 setRelativePosition(sibling, INSERT_AFTER);
134 * Instructs this operation to position the new element before the given
135 * sibling, or to add the new element as the last child of its parent if
138 public void createBefore(IJavaElement sibling) {
139 setRelativePosition(sibling, INSERT_BEFORE);
143 * Execute the operation - generate new source for the compilation unit and
146 * @exception JavaModelException
147 * if the operation is unable to complete
149 protected void executeOperation() throws JavaModelException {
151 beginTask(getMainTaskName(), getMainAmountOfWork());
152 JavaElementDelta delta = newJavaElementDelta();
153 ICompilationUnit unit = getCompilationUnit();
154 generateNewCompilationUnitDOM(unit);
155 if (fCreationOccurred) {
156 // a change has really occurred
157 IBuffer buffer = unit.getBuffer();
160 char[] bufferContents = buffer.getCharacters();
161 if (bufferContents == null)
163 char[] elementContents = net.sourceforge.phpdt.internal.core.util.Util
164 .normalizeCRs(fCreatedElement.getCharacters(),
166 switch (fReplacementLength) {
168 // element is append at the end
169 buffer.append(elementContents);
172 // element is inserted
173 buffer.replace(fInsertionPosition, 0, elementContents);
176 // element is replacing the previous one
177 buffer.replace(fInsertionPosition, fReplacementLength,
180 unit.save(null, false);
181 boolean isWorkingCopy = unit.isWorkingCopy();
183 this.setAttribute(HAS_MODIFIED_RESOURCE_ATTR, TRUE);
185 resultElements = generateResultHandles();
186 if (!isWorkingCopy // if unit is working copy, then save will
187 // have already fired the delta
188 && !Util.isExcluded(unit) && unit.getParent().exists()) {
189 for (int i = 0; i < resultElements.length; i++) {
190 delta.added(resultElements[i]);
193 } // else unit is created outside classpath
194 // non-java resource delta will be notified by delta processor
202 * Returns a JDOM document fragment for the element being created.
204 protected abstract IDOMNode generateElementDOM() throws JavaModelException;
207 * Returns the DOM with the new source to use for the given compilation
210 protected void generateNewCompilationUnitDOM(ICompilationUnit cu)
211 throws JavaModelException {
212 IBuffer buffer = cu.getBuffer();
215 char[] prevSource = buffer.getCharacters();
216 if (prevSource == null)
219 // create a JDOM for the compilation unit
220 fCUDOM = (new DOMFactory()).createCompilationUnit(prevSource, cu
222 IDOMNode child = generateElementDOM();
224 insertDOMNode(fCUDOM, child);
230 * Creates and returns the handle for the element this operation created.
232 protected abstract IJavaElement generateResultHandle();
235 * Creates and returns the handles for the elements this operation created.
237 protected IJavaElement[] generateResultHandles() throws JavaModelException {
238 return new IJavaElement[] { generateResultHandle() };
242 * Returns the compilation unit in which the new element is being created.
244 protected ICompilationUnit getCompilationUnit() {
245 return getCompilationUnitFor(getParentElement());
249 * Returns the amount of work for the main task of this operation for
250 * progress reporting.
252 protected int getMainAmountOfWork() {
257 * Returns the name of the main task of this operation for progress
260 public abstract String getMainTaskName();
262 protected ISchedulingRule getSchedulingRule() {
263 IResource resource = getCompilationUnit().getResource();
264 IWorkspace workspace = resource.getWorkspace();
265 return workspace.getRuleFactory().modifyRule(resource);
269 * Returns the elements created by this operation.
271 public IJavaElement[] getResultElements() {
272 return resultElements;
276 * Sets the default position in which to create the new type member. By
277 * default, the new element is positioned as the last child of the parent
278 * element in which it is created. Operations that require a different
279 * default position must override this method.
281 protected void initializeDefaultPosition() {
286 * Inserts the given child into the given JDOM, based on the position
287 * settings of this operation.
289 * @see createAfter(IJavaElement)
290 * @see createBefore(IJavaElement);
292 protected void insertDOMNode(IDOMNode parent, IDOMNode child) {
293 if (fInsertionPolicy != INSERT_LAST) {
294 IDOMNode sibling = ((JavaElement) fAnchorElement).findNode(fCUDOM);
295 if (sibling != null && fInsertionPolicy == INSERT_AFTER) {
296 sibling = sibling.getNextNode();
298 if (sibling != null) {
299 sibling.insertSibling(child);
300 fCreatedElement = (DOMNode) child;
301 fInsertionPosition = ((DOMNode) sibling).getStartPosition();
302 fReplacementLength = 0;
306 // add as the last element of the parent
307 parent.addChild(child);
308 fCreatedElement = (DOMNode) child;
309 fInsertionPosition = ((DOMNode) parent).getInsertionPosition();
310 // fInsertionPosition = lastChild == null ?
311 // ((DOMNode)parent).getInsertionPosition() :
312 // lastChild.getInsertionPosition();
313 fReplacementLength = parent.getParent() == null ? -1 : 0;
317 * Sets the name of the <code>DOMNode</code> that will be used to create
318 * this new element. Used by the <code>CopyElementsOperation</code> for
319 * renaming. Only used for <code>CreateTypeMemberOperation</code>
321 protected void setAlteredName(String newName) {
325 * Instructs this operation to position the new element relative to the
326 * given sibling, or to add the new element as the last child of its parent
327 * if <code>null</code>. The <code>position</code> must be one of the
328 * position constants.
330 protected void setRelativePosition(IJavaElement sibling, int policy)
331 throws IllegalArgumentException {
332 if (sibling == null) {
333 fAnchorElement = null;
334 fInsertionPolicy = INSERT_LAST;
336 fAnchorElement = sibling;
337 fInsertionPolicy = policy;
344 * <li>NO_ELEMENTS_TO_PROCESS - the compilation unit supplied to the
345 * operation is <code>null</code>.
346 * <li>INVALID_NAME - no name, a name was null or not a valid import
348 * <li>INVALID_SIBLING - the sibling provided for positioning is not valid.
351 * @see IJavaModelStatus
352 * @see JavaConventions
354 public IJavaModelStatus verify() {
355 if (getParentElement() == null) {
356 return new JavaModelStatus(
357 IJavaModelStatusConstants.NO_ELEMENTS_TO_PROCESS);
359 if (fAnchorElement != null) {
360 IJavaElement domPresentParent = fAnchorElement.getParent();
361 if (domPresentParent.getElementType() == IJavaElement.IMPORT_CONTAINER) {
362 domPresentParent = domPresentParent.getParent();
364 if (!domPresentParent.equals(getParentElement())) {
365 return new JavaModelStatus(
366 IJavaModelStatusConstants.INVALID_SIBLING,
370 return JavaModelStatus.VERIFIED_OK;