/******************************************************************************* * Copyright (c) 2000, 2016 IBM Corporation 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 * *******************************************************************************/ package org.eclipse.dltk.internal.core; import org.eclipse.dltk.core.DLTKCore; import org.eclipse.dltk.core.IModelElement; import org.eclipse.dltk.core.IModelStatus; import org.eclipse.dltk.core.IModelStatusConstants; import org.eclipse.dltk.core.ISourceModule; import org.eclipse.dltk.core.ModelException; import org.eclipse.dltk.internal.core.util.Messages; /** * This operation copies/moves a collection of elements from their current * container to a new container, optionally renaming the elements. * <p> * Notes: * <ul> * <li>If there is already an element with the same name in the new container, * the operation either overwrites or aborts, depending on the collision policy * setting. The default setting is abort. * * <li>When constructors are copied to a type, the constructors are * automatically renamed to the name of the destination type. * * <li>When main types are renamed (move within the same parent), the * compilation unit and constructors are automatically renamed * * <li>The collection of elements being copied must all share the same type of * container (for example, must all be type members). * * <li>The elements are inserted in the new container in the order given. * * <li>The elements can be positioned in the new container - see * #setInsertBefore. By default, the elements are inserted based on the default * positions as specified in the creation operation for that element type. * * <li>This operation can be used to copy and rename elements within the same * container. * * <li>This operation only copies elements contained within compilation units. * </ul> * */ public class CopyElementsOperation extends MultiOperation { /** * When executed, this operation will copy the given elements to the given * containers. The elements and destination containers must be in the * correct order. If there is > 1 destination, the number of destinations * must be the same as the number of elements being copied/moved/renamed. */ public CopyElementsOperation(IModelElement[] elementsToCopy, IModelElement[] destContainers, boolean force) { super(elementsToCopy, destContainers, force); } /** * When executed, this operation will copy the given elements to the given * container. */ public CopyElementsOperation(IModelElement[] elementsToCopy, IModelElement destContainer, boolean force) { this(elementsToCopy, new IModelElement[] { destContainer }, force); } /** * Returns the <code>String</code> to use as the main task name for * progress monitoring. */ @Override protected String getMainTaskName() { return Messages.operation_copyElementProgress; } /** * Returns the nested operation to use for processing this element */ protected ModelOperation getNestedOperation(IModelElement element) { return null; } /** * Returns <code>true</code> if this element is the main type of its * compilation unit. */ protected boolean isRenamingMainType(IModelElement element, IModelElement dest) throws ModelException { if ((isRename() || getNewNameFor(element) != null) && dest.getElementType() == IModelElement.SOURCE_MODULE) { String typeName = dest.getElementName(); if (DLTKCore.DEBUG) { System.err.println("TODO:Add extension remove code here..."); //$NON-NLS-1$ } // typeName = // /*org.eclipse.dltk.internal.core.util.Util.getNameWithoutScriptLikeExtension((*/typeName;//); return element.getElementName().equals(typeName) && element.getParent().equals(dest); } return false; } /** * Copy/move the element from the source to destination, renaming the * elements as specified, honoring the collision policy. * * @exception ScriptModelException * if the operation is unable to be completed */ @Override protected void processElement(IModelElement element) throws ModelException { ModelOperation op = getNestedOperation(element); // boolean createElementInCUOperation = op instanceof CreateElementInCUOperation; if (op == null) { return; } if (DLTKCore.DEBUG) { System.err.println("TODO: Add CreateElementInCUOperation"); //$NON-NLS-1$ } // if (createElementInCUOperation) { // IModelElement sibling = (IModelElement) this.insertBeforeElements.get(element); // if (sibling != null) { // ((CreateElementInCUOperation) op).setRelativePosition(sibling, CreateElementInCUOperation.INSERT_BEFORE); // } else if (isRename()) { // IModelElement anchor = resolveRenameAnchor(element); // if (anchor != null) { // ((CreateElementInCUOperation) op).setRelativePosition(anchor, CreateElementInCUOperation.INSERT_AFTER); // insert // // after // // so // // that // // the // // anchor // // is // // found // // before // // when // // deleted // // below // } // } // String newName = getNewNameFor(element); // if (newName != null) { // ((CreateElementInCUOperation) op).setAlteredName(newName); // } // } executeNestedOperation(op, 1); ModelElement destination = (ModelElement) getDestinationParent(element); ISourceModule unit = destination.getSourceModule(); if (!unit.isWorkingCopy()) { unit.close(); } // if (createElementInCUOperation && isMove() && !isRenamingMainType(element, destination)) { // DeleteElementsOperation deleteOp = new DeleteElementsOperation(new IModelElement[] { // element // }, this.force); // executeNestedOperation(deleteOp, 1); // } } /** * Returns the anchor used for positioning in the destination for the * element being renamed. For renaming, if no anchor has explicitly been * provided, the element is anchored in the same position. */ // private IModelElement resolveRenameAnchor(IModelElement element) throws ModelException { // IParent parent = (IParent) element.getParent(); // IModelElement[] children = parent.getChildren(); // for (int i = 0; i < children.length; i++) { // IModelElement child = children[i]; // if (child.equals(element)) { // return child; // } // } // return null; // } /** * Possible failures: * <ul> * <li>NO_ELEMENTS_TO_PROCESS - no elements supplied to the operation * <li>INDEX_OUT_OF_BOUNDS - the number of renamings supplied to the * operation does not match the number of elements that were supplied. * </ul> */ @Override protected IModelStatus verify() { IModelStatus status = super.verify(); if (!status.isOK()) { return status; } if (this.renamingsList != null && this.renamingsList.length != this.elementsToProcess.length) { return new ModelStatus(IModelStatusConstants.INDEX_OUT_OF_BOUNDS); } return ModelStatus.VERIFIED_OK; } /** * @see MultiOperation * * Possible failure codes: * <ul> * * <li>ELEMENT_DOES_NOT_EXIST - <code>element</code> or its specified * destination is is <code>null</code> or does not exist. If a * <code>null</code> element is supplied, no element is provided in the * status, otherwise, the non-existant element is supplied in the status. * <li>INVALID_ELEMENT_TYPES - <code>element</code> is not contained * within a compilation unit. This operation only operates on elements * contained within compilation units. * <li>READ_ONLY - <code>element</code> is read only. * <li>INVALID_DESTINATION - The destination parent specified for * <code>element</code> is of an incompatible type. The destination for a * package declaration or import declaration must be a compilation unit; the * destination for a type must be a type or compilation unit; the destinaion * for any type member (other than a type) must be a type. When this error * occurs, the element provided in the operation status is the * <code>element</code>. * <li>INVALID_NAME - the new name for <code>element</code> does not have * valid syntax. In this case the element and name are provided in the * status. * * </ul> */ @Override protected void verify(IModelElement element) throws ModelException { if (element == null || !element.exists()) error(IModelStatusConstants.ELEMENT_DOES_NOT_EXIST, element); if (element.getElementType() < IModelElement.TYPE) error(IModelStatusConstants.INVALID_ELEMENT_TYPES, element); if (element.isReadOnly()) error(IModelStatusConstants.READ_ONLY, element); IModelElement dest = getDestinationParent(element); verifyDestination(element, dest); verifySibling(element, dest); if (this.renamingsList != null) { verifyRenaming(element); } } }