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;
26 import net.sourceforge.phpdt.internal.core.util.Util;
29 * This operation copies/moves a collection of elements from their current
30 * container to a new container, optionally renaming the elements.
34 * <li>If there is already an element with the same name in the new container,
35 * the operation either overwrites or aborts, depending on the collision policy
36 * setting. The default setting is abort.
38 * <li>When constructors are copied to a type, the constructors are
39 * automatically renamed to the name of the destination type.
41 * <li>When main types are renamed (move within the same parent), the
42 * compilation unit and constructors are automatically renamed
44 * <li>The collection of elements being copied must all share the same type of
45 * 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
50 * #setInsertBefore. By default, the elements are inserted based on the default
51 * positions as specified in the creation operation for that element type.
53 * <li>This operation can be used to copy and rename elements within the same
56 * <li>This operation only copies elements contained within compilation units.
60 public class CopyElementsOperation extends MultiOperation {
62 private Map fSources = new HashMap();
65 * When executed, this operation will copy the given elements to the given
66 * containers. The elements and destination containers must be in the
67 * 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,
71 IJavaElement[] destContainers, boolean force) {
72 super(elementsToCopy, destContainers, force);
76 * When executed, this operation will copy the given elements to the given
79 public CopyElementsOperation(IJavaElement[] elementsToCopy,
80 IJavaElement destContainer, boolean force) {
81 this(elementsToCopy, new IJavaElement[] { destContainer }, force);
85 * Returns the <code>String</code> to use as the main task name for
86 * progress monitoring.
88 protected String getMainTaskName() {
89 return Util.bind("operation.copyElementProgress"); //$NON-NLS-1$
93 * Returns the nested operation to use for processing this element
95 protected JavaModelOperation getNestedOperation(IJavaElement element) {
98 // IJavaElement dest = getDestinationParent(element);
99 // switch (element.getElementType()) {
100 // case IJavaElement.PACKAGE_DECLARATION :
102 // CreatePackageDeclarationOperation(element.getElementName(),
103 // (ICompilationUnit) dest);
104 // case IJavaElement.IMPORT_DECLARATION :
105 // return new CreateImportOperation(element.getElementName(),
106 // (ICompilationUnit) dest);
107 // case IJavaElement.TYPE :
108 // if (isRenamingMainType(element, dest)) {
109 // return new RenameResourceElementsOperation(new IJavaElement[] {dest},
110 // new IJavaElement[] {dest.getParent()}, new
111 // String[]{getNewNameFor(element) + ".php"}, fForce); //$NON-NLS-1$
113 // return new CreateTypeOperation(dest, getSourceFor(element) +
114 // ProjectPrefUtil.LINE_SEPARATOR, fForce);
116 // case IJavaElement.METHOD :
117 // return new CreateMethodOperation((IType) dest, getSourceFor(element)
118 // + ProjectPrefUtil.LINE_SEPARATOR, fForce);
119 // case IJavaElement.FIELD :
120 // return new CreateFieldOperation((IType) dest, getSourceFor(element) +
121 // ProjectPrefUtil.LINE_SEPARATOR, fForce);
122 // case IJavaElement.INITIALIZER :
123 // return new CreateInitializerOperation((IType) dest,
124 // getSourceFor(element) + ProjectPrefUtil.LINE_SEPARATOR);
128 // } catch (JavaModelException npe) {
134 * Returns the cached source for this element or compute it if not already
137 private String getSourceFor(IJavaElement element) throws JavaModelException {
138 String source = (String) fSources.get(element);
139 if (source == null && element instanceof IMember) {
140 IMember member = (IMember) element;
141 ICompilationUnit cu = member.getCompilationUnit();
142 String cuSource = cu.getSource();
143 IDOMCompilationUnit domCU = new DOMFactory().createCompilationUnit(
144 cuSource, cu.getElementName());
145 IDOMNode node = ((JavaElement) element).findNode(domCU);
146 source = new String(node.getCharacters());
147 fSources.put(element, source);
153 * Returns <code>true</code> if this element is the main type of its
156 protected boolean isRenamingMainType(IJavaElement element, IJavaElement dest) {
157 if ((isRename() || getNewNameFor(element) != null)
158 && dest.getElementType() == IJavaElement.COMPILATION_UNIT) {
159 String typeName = dest.getElementName();
160 typeName = typeName.substring(0, typeName.length() - 5);
161 return element.getElementName().equals(typeName)
162 && element.getParent().equals(dest);
168 * Copy/move the element from the source to destination, renaming the
169 * elements as specified, honoring the collision policy.
171 * @exception JavaModelException
172 * if the operation is unable to be completed
174 protected void processElement(IJavaElement element)
175 throws JavaModelException {
176 JavaModelOperation op = getNestedOperation(element);
177 boolean createElementInCUOperation = op instanceof CreateElementInCUOperation;
181 if (createElementInCUOperation) {
182 IJavaElement sibling = (IJavaElement) fInsertBeforeElements
184 if (sibling != null) {
185 ((CreateElementInCUOperation) op).setRelativePosition(sibling,
186 CreateElementInCUOperation.INSERT_BEFORE);
187 } else if (isRename()) {
188 IJavaElement anchor = resolveRenameAnchor(element);
189 if (anchor != null) {
190 ((CreateElementInCUOperation) op).setRelativePosition(
191 anchor, CreateElementInCUOperation.INSERT_AFTER); // insert
205 String newName = getNewNameFor(element);
206 if (newName != null) {
207 ((CreateElementInCUOperation) op).setAlteredName(newName);
210 executeNestedOperation(op, 1);
212 JavaElement destination = (JavaElement) getDestinationParent(element);
213 ICompilationUnit unit = destination.getCompilationUnit();
214 if (!unit.isWorkingCopy()) {
218 if (createElementInCUOperation && isMove()
219 && !isRenamingMainType(element, destination)) {
220 DeleteElementsOperation deleteOp = new DeleteElementsOperation(
221 new IJavaElement[] { element }, force);
222 executeNestedOperation(deleteOp, 1);
227 * Returns the anchor used for positioning in the destination for the
228 * element being renamed. For renaming, if no anchor has explicitly been
229 * provided, the element is anchored in the same position.
231 private IJavaElement resolveRenameAnchor(IJavaElement element)
232 throws JavaModelException {
233 IParent parent = (IParent) element.getParent();
234 IJavaElement[] children = parent.getChildren();
235 for (int i = 0; i < children.length; i++) {
236 IJavaElement child = children[i];
237 if (child.equals(element)) {
247 * <li>NO_ELEMENTS_TO_PROCESS - no elements supplied to the operation
248 * <li>INDEX_OUT_OF_BOUNDS - the number of renamings supplied to the
249 * operation does not match the number of elements that were supplied.
252 protected IJavaModelStatus verify() {
253 IJavaModelStatus status = super.verify();
254 if (!status.isOK()) {
257 if (fRenamingsList != null
258 && fRenamingsList.length != fElementsToProcess.length) {
259 return new JavaModelStatus(
260 IJavaModelStatusConstants.INDEX_OUT_OF_BOUNDS);
262 return JavaModelStatus.VERIFIED_OK;
266 * @see MultiOperation
268 * Possible failure codes:
271 * <li>ELEMENT_DOES_NOT_EXIST - <code>element</code> or its specified
272 * destination is is <code>null</code> or does not exist. If a
273 * <code>null</code> element is supplied, no element is provided in the
274 * status, otherwise, the non-existant element is supplied in the status.
275 * <li>INVALID_ELEMENT_TYPES - <code>element</code> is not contained
276 * within a compilation unit. This operation only operates on elements
277 * contained within compilation units.
278 * <li>READ_ONLY - <code>element</code> is read only.
279 * <li>INVALID_DESTINATION - The destination parent specified for
280 * <code>element</code> is of an incompatible type. The destination for a
281 * package declaration or import declaration must be a compilation unit; the
282 * destination for a type must be a type or compilation unit; the destinaion
283 * for any type member (other than a type) must be a type. When this error
284 * occurs, the element provided in the operation status is the
285 * <code>element</code>.
286 * <li>INVALID_NAME - the new name for <code>element</code> does not have
287 * valid syntax. In this case the element and name are provided in the
292 protected void verify(IJavaElement element) throws JavaModelException {
293 if (element == null || !element.exists())
294 error(IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST, element);
296 if (element.getElementType() < IJavaElement.TYPE)
297 error(IJavaModelStatusConstants.INVALID_ELEMENT_TYPES, element);
299 if (element.isReadOnly())
300 error(IJavaModelStatusConstants.READ_ONLY, element);
302 IJavaElement dest = getDestinationParent(element);
303 verifyDestination(element, dest);
304 verifySibling(element, dest);
305 if (fRenamingsList != null) {
306 verifyRenaming(element);