/******************************************************************************* * Copyright (c) 2000, 2008 QNX Software Systems and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * QNX Software Systems - Initial API and implementation *******************************************************************************/ package org.eclipse.cdt.internal.core.model; import org.eclipse.cdt.core.CConventions; import org.eclipse.cdt.core.model.CModelException; import org.eclipse.cdt.core.model.IBuffer; import org.eclipse.cdt.core.model.ICElement; import org.eclipse.cdt.core.model.ICModelStatus; import org.eclipse.cdt.core.model.ICModelStatusConstants; import org.eclipse.cdt.core.model.ISourceRange; import org.eclipse.cdt.core.model.ISourceReference; import org.eclipse.cdt.core.model.ITranslationUnit; /** * <p>This abstract class implements behavior common to <code>CreateElementInTUOperations</code>. * 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. * * <p>The element being created can be positioned relative to an existing * element in the compilation unit via the methods <code>#createAfter</code> * and <code>#createBefore</code>. By default, the new element is positioned * as the last child of its parent element. * */ public abstract class CreateElementInTUOperation extends CModelOperation { /** * 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 <code>fAnchorElement</code>. */ protected static final int INSERT_AFTER = 2; /** * A constant meaning to position the new element * before the element defined by <code>fAnchorElement</code>. */ 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 is being created. */ protected String fCreatedElement = null; /** * The element that the newly created element is * positioned relative to, as described by * <code>fInsertPosition</code>, or <code>null</code> * if the newly created element will be positioned * last. */ protected ICElement 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 <code>false</code>. Ensures that no deltas are generated * when creation does not occur. */ protected boolean fCreationOccurred = true; /** * 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 C Language Element with * the specified parent, contained within a translation unit. */ public CreateElementInTUOperation(ICElement parentElement) { super(null, new ICElement[]{parentElement}); initializeDefaultPosition(); } /** * Only allow cancelling if this operation is not nested. */ @Override protected void checkCanceled() { if (!fNested) { 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 <code>null</code>. */ public void createAfter(ICElement 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 <code>null</code>. */ public void createBefore(ICElement sibling) { setRelativePosition(sibling, INSERT_BEFORE); } protected abstract String generateElement(ITranslationUnit unit) throws CModelException; /** * Execute the operation - generate new source for the compilation unit * and save the results. * * @exception CModelException if the operation is unable to complete */ @Override protected void executeOperation() throws CModelException { beginTask(getMainTaskName(), getMainAmountOfWork()); CElementDelta delta = newCElementDelta(); ITranslationUnit unit = getTranslationUnit(); fCreatedElement = generateElement(unit); insertElement(); 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 = Util.normalizeCRs(getCreatedElementCharacters(), 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.setAttributes(...); //} worked(1); fResultElements = generateResultHandles(); if (!isWorkingCopy) { // if unit is working copy, then save will have already fired the delta if (unit.getParent().exists()) { for (ICElement resultElement : fResultElements) { delta.added(resultElement); } addDelta(delta); } // else unit is created outside classpath // non-java resource delta will be notified by delta processor } } done(); } private char[] getCreatedElementCharacters() { return fCreatedElement.toCharArray(); } /** * Creates and returns the handle for the element this operation created. */ protected abstract ICElement generateResultHandle(); /** * Creates and returns the handles for the elements this operation created. */ protected ICElement[] generateResultHandles() throws CModelException { return new ICElement[]{generateResultHandle()}; } /** * Returns the compilation unit in which the new element is being created. */ protected ITranslationUnit getTranslationUnit() { return ((ISourceReference)getParentElement()).getTranslationUnit(); } /** * Returns the amount of work for the main task of this operation for * progress reporting. * @see #executeOperation() */ protected int getMainAmountOfWork(){ return 2; } /** * Returns the name of the main task of this operation for * progress reporting. * @see #executeOperation() */ protected abstract String getMainTaskName(); /** * Returns the elements created by this operation. */ @Override public ICElement[] getResultElements() { return fResultElements; } /** * 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(ICElement) * @see #createBefore(ICElement) */ protected void insertElement() throws CModelException { if (fInsertionPolicy != INSERT_LAST) { ISourceRange range = ((ISourceReference)fAnchorElement).getSourceRange(); switch (fInsertionPolicy) { case INSERT_AFTER: fReplacementLength = 0; fInsertionPosition = range.getStartPos() + range.getLength(); break; case INSERT_BEFORE: fReplacementLength = 0; fInsertionPosition = range.getStartPos(); break; default: fReplacementLength = range.getStartPos() + range.getLength(); fInsertionPosition = range.getStartPos(); } return; } //add as the last element of the parent fReplacementLength = -1; } /** * Sets the name of the <code>DOMNode</code> that will be used to * create this new element. * Used by the <code>CopyElementsOperation</code> for renaming. * Only used for <code>CreateTypeMemberOperation</code> */ 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 <code>null</code>. The <code>position</code> * must be one of the position constants. */ protected void setRelativePosition(ICElement sibling, int policy) throws IllegalArgumentException { if (sibling == null) { fAnchorElement = null; fInsertionPolicy = INSERT_LAST; } else { fAnchorElement = sibling; fInsertionPolicy = policy; } } /** * Possible failures: <ul> * <li>NO_ELEMENTS_TO_PROCESS - the compilation unit supplied to the operation is * <code>null</code>. * <li>INVALID_NAME - no name, a name was null or not a valid * import declaration name. * <li>INVALID_SIBLING - the sibling provided for positioning is not valid. * </ul> * @see ICModelStatus * @see CConventions */ @Override public ICModelStatus verify() { if (getParentElement() == null) { return new CModelStatus(ICModelStatusConstants.NO_ELEMENTS_TO_PROCESS); } if (fAnchorElement != null) { ICElement domPresentParent = fAnchorElement.getParent(); if (!domPresentParent.equals(getParentElement())) { return new CModelStatus(ICModelStatusConstants.INVALID_SIBLING, fAnchorElement); } } return CModelStatus.VERIFIED_OK; } }