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 java.util.HashMap;
16 import net.sourceforge.phpdt.core.ICompilationUnit;
17 import net.sourceforge.phpdt.core.IJavaElement;
18 import net.sourceforge.phpdt.core.IJavaModelStatus;
19 import net.sourceforge.phpdt.core.IJavaModelStatusConstants;
20 import net.sourceforge.phpdt.core.IMember;
21 import net.sourceforge.phpdt.core.IParent;
22 import net.sourceforge.phpdt.core.JavaModelException;
23 import net.sourceforge.phpdt.core.jdom.DOMFactory;
24 import net.sourceforge.phpdt.core.jdom.IDOMCompilationUnit;
25 import net.sourceforge.phpdt.core.jdom.IDOMNode;
28 * This operation copies/moves a collection of elements from their current
29 * container to a new container, optionally renaming the
32 * <li>If there is already an element with the same name in
33 * the new container, the operation either overwrites or aborts,
34 * depending on the collision policy setting. The default setting is
37 * <li>When constructors are copied to a type, the constructors
38 * are automatically renamed to the name of the destination
41 * <li>When main types are renamed (move within the same parent),
42 * the compilation unit and constructors are automatically renamed
44 * <li>The collection of elements being copied must all share the
45 * same type of container (for example, must all be type members).
47 * <li>The elements are inserted in the new container in the order given.
49 * <li>The elements can be positioned in the new container - see #setInsertBefore.
50 * By default, the elements are inserted based on the default positions as specified in
51 * the creation operation for that element type.
53 * <li>This operation can be used to copy and rename elements within
56 * <li>This operation only copies elements contained within compilation units.
60 public class CopyElementsOperation extends MultiOperation {
63 private Map fSources = new HashMap();
65 * When executed, this operation will copy the given elements to the
66 * given containers. The elements and destination containers must be in
67 * the correct order. If there is > 1 destination, the number of destinations
68 * must be the same as the number of elements being copied/moved/renamed.
70 public CopyElementsOperation(IJavaElement[] elementsToCopy, IJavaElement[] destContainers, boolean force) {
71 super(elementsToCopy, destContainers, force);
74 * When executed, this operation will copy the given elements to the
77 public CopyElementsOperation(IJavaElement[] elementsToCopy, IJavaElement destContainer, boolean force) {
78 this(elementsToCopy, new IJavaElement[]{destContainer}, force);
81 * Returns the <code>String</code> to use as the main task name
82 * for progress monitoring.
84 protected String getMainTaskName() {
85 return Util.bind("operation.copyElementProgress"); //$NON-NLS-1$
88 * Returns the nested operation to use for processing this element
90 protected JavaModelOperation getNestedOperation(IJavaElement element) {
93 // IJavaElement dest = getDestinationParent(element);
94 // switch (element.getElementType()) {
95 // case IJavaElement.PACKAGE_DECLARATION :
96 // return new CreatePackageDeclarationOperation(element.getElementName(), (ICompilationUnit) dest);
97 // case IJavaElement.IMPORT_DECLARATION :
98 // return new CreateImportOperation(element.getElementName(), (ICompilationUnit) dest);
99 // case IJavaElement.TYPE :
100 // if (isRenamingMainType(element, dest)) {
101 // return new RenameResourceElementsOperation(new IJavaElement[] {dest}, new IJavaElement[] {dest.getParent()}, new String[]{getNewNameFor(element) + ".php"}, fForce); //$NON-NLS-1$
103 // return new CreateTypeOperation(dest, getSourceFor(element) + Util.LINE_SEPARATOR, fForce);
105 // case IJavaElement.METHOD :
106 // return new CreateMethodOperation((IType) dest, getSourceFor(element) + Util.LINE_SEPARATOR, fForce);
107 // case IJavaElement.FIELD :
108 // return new CreateFieldOperation((IType) dest, getSourceFor(element) + Util.LINE_SEPARATOR, fForce);
109 // case IJavaElement.INITIALIZER :
110 // return new CreateInitializerOperation((IType) dest, getSourceFor(element) + Util.LINE_SEPARATOR);
114 // } catch (JavaModelException npe) {
119 * Returns the cached source for this element or compute it if not already cached.
121 private String getSourceFor(IJavaElement element) throws JavaModelException {
122 String source = (String) fSources.get(element);
123 if (source == null && element instanceof IMember) {
124 IMember member = (IMember)element;
125 ICompilationUnit cu = member.getCompilationUnit();
126 String cuSource = cu.getSource();
127 IDOMCompilationUnit domCU = new DOMFactory().createCompilationUnit(cuSource, cu.getElementName());
128 IDOMNode node = ((JavaElement)element).findNode(domCU);
129 source = new String(node.getCharacters());
130 fSources.put(element, source);
135 * Returns <code>true</code> if this element is the main type of its compilation unit.
137 protected boolean isRenamingMainType(IJavaElement element, IJavaElement dest) {
138 if ((isRename() || getNewNameFor(element) != null)
139 && dest.getElementType() == IJavaElement.COMPILATION_UNIT) {
140 String typeName = dest.getElementName();
141 typeName = typeName.substring(0, typeName.length() - 5);
142 return element.getElementName().equals(typeName) && element.getParent().equals(dest);
147 * Copy/move the element from the source to destination, renaming
148 * the elements as specified, honoring the collision policy.
150 * @exception JavaModelException if the operation is unable to
153 protected void processElement(IJavaElement element) throws JavaModelException {
154 JavaModelOperation op = getNestedOperation(element);
155 boolean createElementInCUOperation =op instanceof CreateElementInCUOperation;
159 if (createElementInCUOperation) {
160 IJavaElement sibling = (IJavaElement) fInsertBeforeElements.get(element);
161 if (sibling != null) {
162 ((CreateElementInCUOperation) op).setRelativePosition(sibling, CreateElementInCUOperation.INSERT_BEFORE);
165 IJavaElement anchor = resolveRenameAnchor(element);
166 if (anchor != null) {
167 ((CreateElementInCUOperation) op).setRelativePosition(anchor, CreateElementInCUOperation.INSERT_AFTER); // insert after so that the anchor is found before when deleted below
170 String newName = getNewNameFor(element);
171 if (newName != null) {
172 ((CreateElementInCUOperation) op).setAlteredName(newName);
175 executeNestedOperation(op, 1);
177 JavaElement destination = (JavaElement) getDestinationParent(element);
178 ICompilationUnit unit= destination.getCompilationUnit();
179 if (!unit.isWorkingCopy()) {
183 if (createElementInCUOperation && isMove() && !isRenamingMainType(element, destination)) {
184 DeleteElementsOperation deleteOp = new DeleteElementsOperation(new IJavaElement[] { element }, fForce);
185 executeNestedOperation(deleteOp, 1);
189 * Returns the anchor used for positioning in the destination for
190 * the element being renamed. For renaming, if no anchor has
191 * explicitly been provided, the element is anchored in the same position.
193 private IJavaElement resolveRenameAnchor(IJavaElement element) throws JavaModelException {
194 IParent parent = (IParent) element.getParent();
195 IJavaElement[] children = parent.getChildren();
196 for (int i = 0; i < children.length; i++) {
197 IJavaElement child = children[i];
198 if (child.equals(element)) {
207 * <li>NO_ELEMENTS_TO_PROCESS - no elements supplied to the operation
208 * <li>INDEX_OUT_OF_BOUNDS - the number of renamings supplied to the operation
209 * does not match the number of elements that were supplied.
212 protected IJavaModelStatus verify() {
213 IJavaModelStatus status = super.verify();
214 if (!status.isOK()) {
217 if (fRenamingsList != null && fRenamingsList.length != fElementsToProcess.length) {
218 return new JavaModelStatus(IJavaModelStatusConstants.INDEX_OUT_OF_BOUNDS);
220 return JavaModelStatus.VERIFIED_OK;
223 * @see MultiOperation
225 * Possible failure codes:
228 * <li>ELEMENT_DOES_NOT_EXIST - <code>element</code> or its specified destination is
229 * is <code>null</code> or does not exist. If a <code>null</code> element is
230 * supplied, no element is provided in the status, otherwise, the non-existant element
231 * is supplied in the status.
232 * <li>INVALID_ELEMENT_TYPES - <code>element</code> is not contained within a compilation unit.
233 * This operation only operates on elements contained within compilation units.
234 * <li>READ_ONLY - <code>element</code> is read only.
235 * <li>INVALID_DESTINATION - The destination parent specified for <code>element</code>
236 * is of an incompatible type. The destination for a package declaration or import declaration must
237 * be a compilation unit; the destination for a type must be a type or compilation
238 * unit; the destinaion for any type member (other than a type) must be a type. When
239 * this error occurs, the element provided in the operation status is the <code>element</code>.
240 * <li>INVALID_NAME - the new name for <code>element</code> does not have valid syntax.
241 * In this case the element and name are provided in the status.
245 protected void verify(IJavaElement element) throws JavaModelException {
246 if (element == null || !element.exists())
247 error(IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST, element);
249 if (element.getElementType() < IJavaElement.TYPE)
250 error(IJavaModelStatusConstants.INVALID_ELEMENT_TYPES, element);
252 if (element.isReadOnly())
253 error(IJavaModelStatusConstants.READ_ONLY, element);
255 IJavaElement dest = getDestinationParent(element);
256 verifyDestination(element, dest);
257 verifySibling(element, dest);
258 if (fRenamingsList != null) {
259 verifyRenaming(element);