/******************************************************************************* * 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:
*
null
.
*