/******************************************************************************* * Copyright (c) 2000, 2003 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/cpl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package net.sourceforge.phpdt.internal.core; import net.sourceforge.phpdt.core.IBuffer; import net.sourceforge.phpdt.core.ICompilationUnit; import net.sourceforge.phpdt.core.IJavaElement; import net.sourceforge.phpdt.core.IJavaModelStatus; import net.sourceforge.phpdt.core.IJavaModelStatusConstants; import net.sourceforge.phpdt.core.JavaConventions; import net.sourceforge.phpdt.core.JavaModelException; import net.sourceforge.phpdt.core.jdom.DOMFactory; import net.sourceforge.phpdt.core.jdom.IDOMCompilationUnit; import net.sourceforge.phpdt.core.jdom.IDOMNode; import net.sourceforge.phpdt.internal.core.jdom.DOMNode; import net.sourceforge.phpdt.internal.core.util.Util; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IWorkspace; import org.eclipse.core.runtime.jobs.ISchedulingRule; /** *

* This abstract class implements behavior common to * CreateElementInCUOperations. To create a compilation unit, or * an element contained in a compilation unit, the source code for the entire * compilation unit is updated and saved. * *

* The element being created can be positioned relative to an existing element * in the compilation unit via the methods #createAfter and * #createBefore. By default, the new element is positioned as * the last child of its parent element. * */ public abstract class CreateElementInCUOperation extends JavaModelOperation { /** * The compilation unit DOM used for this operation */ protected IDOMCompilationUnit fCUDOM; /** * A constant meaning to position the new element as the last child of its * parent element. */ protected static final int INSERT_LAST = 1; /** * A constant meaning to position the new element after the element defined * by fAnchorElement. */ protected static final int INSERT_AFTER = 2; /** * A constant meaning to position the new element before the element defined * by fAnchorElement. */ protected static final int INSERT_BEFORE = 3; /** * One of the position constants, describing where to position the newly * created element. */ protected int fInsertionPolicy = INSERT_LAST; /** * The element that the newly created element is positioned relative to, as * described by fInsertPosition, or null if * the newly created element will be positioned last. */ protected IJavaElement fAnchorElement = null; /** * A flag indicating whether creation of a new element occurred. A request * for creating a duplicate element would request in this flag being set to * false. Ensures that no deltas are generated when creation * does not occur. */ protected boolean fCreationOccurred = true; /** * The element that is being created. */ protected DOMNode fCreatedElement; /** * The position of the element that is being created. */ protected int fInsertionPosition = -1; /** * The number of characters the new element replaces, or 0 if the new * element is inserted, or -1 if the new element is append to the end of the * CU. */ protected int fReplacementLength = -1; /** * Constructs an operation that creates a Java Language Element with the * specified parent, contained within a compilation unit. */ public CreateElementInCUOperation(IJavaElement parentElement) { super(null, new IJavaElement[] { parentElement }); initializeDefaultPosition(); } /** * Only allow cancelling if this operation is not nested. */ protected void checkCanceled() { if (!isNested) { super.checkCanceled(); } } /** * Instructs this operation to position the new element after the given * sibling, or to add the new element as the last child of its parent if * null. */ public void createAfter(IJavaElement sibling) { setRelativePosition(sibling, INSERT_AFTER); } /** * Instructs this operation to position the new element before the given * sibling, or to add the new element as the last child of its parent if * null. */ public void createBefore(IJavaElement sibling) { setRelativePosition(sibling, INSERT_BEFORE); } /** * Execute the operation - generate new source for the compilation unit and * save the results. * * @exception JavaModelException * if the operation is unable to complete */ protected void executeOperation() throws JavaModelException { try { beginTask(getMainTaskName(), getMainAmountOfWork()); JavaElementDelta delta = newJavaElementDelta(); ICompilationUnit unit = getCompilationUnit(); generateNewCompilationUnitDOM(unit); if (fCreationOccurred) { // a change has really occurred IBuffer buffer = unit.getBuffer(); if (buffer == null) return; char[] bufferContents = buffer.getCharacters(); if (bufferContents == null) return; char[] elementContents = net.sourceforge.phpdt.internal.core.util.Util .normalizeCRs(fCreatedElement.getCharacters(), bufferContents); switch (fReplacementLength) { case -1: // element is append at the end buffer.append(elementContents); break; case 0: // element is inserted buffer.replace(fInsertionPosition, 0, elementContents); break; default: // element is replacing the previous one buffer.replace(fInsertionPosition, fReplacementLength, elementContents); } unit.save(null, false); boolean isWorkingCopy = unit.isWorkingCopy(); if (!isWorkingCopy) this.setAttribute(HAS_MODIFIED_RESOURCE_ATTR, TRUE); worked(1); resultElements = generateResultHandles(); if (!isWorkingCopy // if unit is working copy, then save will // have already fired the delta && !Util.isExcluded(unit) && unit.getParent().exists()) { for (int i = 0; i < resultElements.length; i++) { delta.added(resultElements[i]); } addDelta(delta); } // else unit is created outside classpath // non-java resource delta will be notified by delta processor } } finally { done(); } } /** * Returns a JDOM document fragment for the element being created. */ protected abstract IDOMNode generateElementDOM() throws JavaModelException; /** * Returns the DOM with the new source to use for the given compilation * unit. */ protected void generateNewCompilationUnitDOM(ICompilationUnit cu) throws JavaModelException { IBuffer buffer = cu.getBuffer(); if (buffer == null) return; char[] prevSource = buffer.getCharacters(); if (prevSource == null) return; // create a JDOM for the compilation unit fCUDOM = (new DOMFactory()).createCompilationUnit(prevSource, cu .getElementName()); IDOMNode child = generateElementDOM(); if (child != null) { insertDOMNode(fCUDOM, child); } worked(1); } /** * Creates and returns the handle for the element this operation created. */ protected abstract IJavaElement generateResultHandle(); /** * Creates and returns the handles for the elements this operation created. */ protected IJavaElement[] generateResultHandles() throws JavaModelException { return new IJavaElement[] { generateResultHandle() }; } /** * Returns the compilation unit in which the new element is being created. */ protected ICompilationUnit getCompilationUnit() { return getCompilationUnitFor(getParentElement()); } /** * Returns the amount of work for the main task of this operation for * progress reporting. */ protected int getMainAmountOfWork() { return 2; } /** * Returns the name of the main task of this operation for progress * reporting. */ public abstract String getMainTaskName(); protected ISchedulingRule getSchedulingRule() { IResource resource = getCompilationUnit().getResource(); IWorkspace workspace = resource.getWorkspace(); return workspace.getRuleFactory().modifyRule(resource); } /** * Returns the elements created by this operation. */ public IJavaElement[] getResultElements() { return resultElements; } /** * Sets the default position in which to create the new type member. By * default, the new element is positioned as the last child of the parent * element in which it is created. Operations that require a different * default position must override this method. */ protected void initializeDefaultPosition() { } /** * Inserts the given child into the given JDOM, based on the position * settings of this operation. * * @see createAfter(IJavaElement) * @see createBefore(IJavaElement); */ protected void insertDOMNode(IDOMNode parent, IDOMNode child) { if (fInsertionPolicy != INSERT_LAST) { IDOMNode sibling = ((JavaElement) fAnchorElement).findNode(fCUDOM); if (sibling != null && fInsertionPolicy == INSERT_AFTER) { sibling = sibling.getNextNode(); } if (sibling != null) { sibling.insertSibling(child); fCreatedElement = (DOMNode) child; fInsertionPosition = ((DOMNode) sibling).getStartPosition(); fReplacementLength = 0; return; } } // add as the last element of the parent parent.addChild(child); fCreatedElement = (DOMNode) child; fInsertionPosition = ((DOMNode) parent).getInsertionPosition(); // fInsertionPosition = lastChild == null ? // ((DOMNode)parent).getInsertionPosition() : // lastChild.getInsertionPosition(); fReplacementLength = parent.getParent() == null ? -1 : 0; } /** * Sets the name of the DOMNode that will be used to create * this new element. Used by the CopyElementsOperation for * renaming. Only used for CreateTypeMemberOperation */ protected void setAlteredName(String newName) { } /** * Instructs this operation to position the new element relative to the * given sibling, or to add the new element as the last child of its parent * if null. The position must be one of the * position constants. */ protected void setRelativePosition(IJavaElement sibling, int policy) throws IllegalArgumentException { if (sibling == null) { fAnchorElement = null; fInsertionPolicy = INSERT_LAST; } else { fAnchorElement = sibling; fInsertionPolicy = policy; } } /** * Possible failures: *

* * @see IJavaModelStatus * @see JavaConventions */ public IJavaModelStatus verify() { if (getParentElement() == null) { return new JavaModelStatus( IJavaModelStatusConstants.NO_ELEMENTS_TO_PROCESS); } if (fAnchorElement != null) { IJavaElement domPresentParent = fAnchorElement.getParent(); if (domPresentParent.getElementType() == IJavaElement.IMPORT_CONTAINER) { domPresentParent = domPresentParent.getParent(); } if (!domPresentParent.equals(getParentElement())) { return new JavaModelStatus( IJavaModelStatusConstants.INVALID_SIBLING, fAnchorElement); } } return JavaModelStatus.VERIFIED_OK; } }