| /******************************************************************************* |
| * Copyright (c) 2000, 2016 IBM Corporation and others. |
| * This program and the accompanying materials are made available under the |
| * terms of the Eclipse Public License v. 2.0 which is available at |
| * http://www.eclipse.org/legal/epl-2.0. |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| *******************************************************************************/ |
| package org.eclipse.dltk.internal.core; |
| |
| import java.io.ByteArrayInputStream; |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.Map; |
| |
| import org.eclipse.core.resources.IContainer; |
| import org.eclipse.core.resources.IFile; |
| import org.eclipse.core.resources.IFolder; |
| import org.eclipse.core.resources.IResource; |
| import org.eclipse.core.resources.ResourcesPlugin; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IPath; |
| import org.eclipse.core.runtime.Path; |
| import org.eclipse.dltk.core.DLTKContentTypeManager; |
| import org.eclipse.dltk.core.DLTKCore; |
| import org.eclipse.dltk.core.DLTKLanguageManager; |
| import org.eclipse.dltk.core.IDLTKLanguageToolkit; |
| import org.eclipse.dltk.core.IModelElement; |
| import org.eclipse.dltk.core.IModelElementDelta; |
| import org.eclipse.dltk.core.IModelStatus; |
| import org.eclipse.dltk.core.IModelStatusConstants; |
| import org.eclipse.dltk.core.IProjectFragment; |
| import org.eclipse.dltk.core.IScriptFolder; |
| import org.eclipse.dltk.core.IScriptProject; |
| import org.eclipse.dltk.core.ISourceModule; |
| import org.eclipse.dltk.core.ModelException; |
| import org.eclipse.dltk.internal.core.util.Messages; |
| import org.eclipse.dltk.internal.core.util.Util; |
| |
| /** |
| * This operation copies/moves/renames a collection of resources from their |
| * current container to a new container, optionally renaming the elements. |
| * <p> |
| * Notes: |
| * <ul> |
| * <li>If there is already an resource 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 a compilation unit is copied to a new package, the package |
| * declaration in the compilation unit is automatically updated. |
| * |
| * <li>The collection of elements being copied must all share the same type of |
| * container. |
| * |
| * <li>This operation can be used to copy and rename elements within the same |
| * container. |
| * |
| * <li>This operation only copies compilation units and package fragments. It |
| * does not copy package fragment roots - a platform operation must be used for |
| * that. |
| * </ul> |
| * |
| */ |
| public class CopyResourceElementsOperation extends MultiOperation { |
| /** |
| * The list of new resources created during this operation. |
| */ |
| protected ArrayList createdElements; |
| /** |
| * Table specifying deltas for elements being copied/moved/renamed. Keyed by |
| * elements' project(s), and values are the corresponding deltas. |
| */ |
| protected Map deltasPerProject = new HashMap(1); |
| |
| // /** |
| // * The <code>ASTParser</code> used to manipulate the source code of |
| // * <code>ISourceModule</code>. |
| // */ |
| // protected ASTParser parser; |
| /** |
| * When executed, this operation will copy the given resources to the given |
| * container. |
| */ |
| public CopyResourceElementsOperation(IModelElement[] resourcesToCopy, |
| IModelElement destContainer, boolean force) { |
| this(resourcesToCopy, new IModelElement[] { destContainer }, force); |
| } |
| |
| /** |
| * When executed, this operation will copy the given resources to the given |
| * containers. The resources 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 resources being copied/moved. |
| */ |
| public CopyResourceElementsOperation(IModelElement[] resourcesToCopy, |
| IModelElement[] destContainers, boolean force) { |
| super(resourcesToCopy, destContainers, force); |
| // initializeASTParser(); |
| } |
| |
| // private void initializeASTParser() { |
| // this.parser = ASTParser.newParser(AST.JLS3); |
| // } |
| /** |
| * Returns the children of <code>source</code> which are affected by this |
| * operation. If <code>source</code> is a <code>K_SOURCE</code>, these are |
| * the <code>.java</code> files, if it is a <code>K_BINARY</code>, they are |
| * the <code>.class</code> files. |
| */ |
| private IResource[] collectResourcesOfInterest(IScriptFolder source) |
| throws ModelException { |
| IModelElement[] children = source.getChildren(); |
| int childOfInterest = IModelElement.SOURCE_MODULE; |
| // if (source.getKind() == IProjectFragment.K_BINARY) { |
| // childOfInterest = IModelElement.CLASS_FILE; |
| // } |
| ArrayList correctKindChildren = new ArrayList(children.length); |
| for (int i = 0; i < children.length; i++) { |
| IModelElement child = children[i]; |
| if (child.getElementType() == childOfInterest) { |
| correctKindChildren.add(child.getResource()); |
| } |
| } |
| // Gather non-java resources |
| Object[] nonScriptResources = source.getForeignResources(); |
| int actualNonScriptResourceCount = 0; |
| for (int i = 0, max = nonScriptResources.length; i < max; i++) { |
| if (nonScriptResources[i] instanceof IResource) |
| actualNonScriptResourceCount++; |
| } |
| IResource[] actualNonScriptResources = new IResource[actualNonScriptResourceCount]; |
| for (int i = 0, max = nonScriptResources.length, index = 0; i < max; i++) { |
| if (nonScriptResources[i] instanceof IResource) |
| actualNonScriptResources[index++] = (IResource) nonScriptResources[i]; |
| } |
| if (actualNonScriptResourceCount != 0) { |
| int correctKindChildrenSize = correctKindChildren.size(); |
| IResource[] result = new IResource[correctKindChildrenSize |
| + actualNonScriptResourceCount]; |
| correctKindChildren.toArray(result); |
| System.arraycopy(actualNonScriptResources, 0, result, |
| correctKindChildrenSize, actualNonScriptResourceCount); |
| return result; |
| } else { |
| IResource[] result = new IResource[correctKindChildren.size()]; |
| correctKindChildren.toArray(result); |
| return result; |
| } |
| } |
| |
| /** |
| * Creates any destination package fragment(s) which do not exists yet. |
| * Return true if a read-only package fragment has been found among package |
| * fragments, false otherwise |
| */ |
| private boolean createNeededScriptFolders(IContainer sourceFolder, |
| IProjectFragment root, IPath newFragName, boolean moveFolder) |
| throws ModelException { |
| boolean containsReadOnlyScriptFolder = false; |
| IContainer parentFolder = (IContainer) root.getResource(); |
| ModelElementDelta projectDelta = null; |
| IPath sideEffectPackageName = Path.EMPTY; |
| for (int i = 0; i < newFragName.segmentCount(); i++) { |
| String subFolderName = newFragName.segment(i); |
| sideEffectPackageName = sideEffectPackageName.append(subFolderName); |
| IResource subFolder = parentFolder.findMember(subFolderName); |
| if (subFolder == null) { |
| // create deepest folder only if not a move (folder will be |
| // moved in processScriptFolderResource) |
| if (!(moveFolder && i == newFragName.segmentCount() - 1)) { |
| createFolder(parentFolder, subFolderName, force); |
| } |
| parentFolder = parentFolder.getFolder(new Path(subFolderName)); |
| sourceFolder = sourceFolder.getFolder(new Path(subFolderName)); |
| if (Util.isReadOnly(sourceFolder)) { |
| containsReadOnlyScriptFolder = true; |
| } |
| IScriptFolder sideEffectPackage = root |
| .getScriptFolder(sideEffectPackageName); |
| if (i < newFragName.segmentCount() - 1 // all but the last one |
| // are side effect |
| // packages |
| && !Util.isExcluded(parentFolder, root)) { |
| if (projectDelta == null) { |
| projectDelta = getDeltaFor(root.getScriptProject()); |
| } |
| projectDelta.added(sideEffectPackage); |
| } |
| createdElements.add(sideEffectPackage); |
| } else { |
| parentFolder = (IContainer) subFolder; |
| } |
| } |
| return containsReadOnlyScriptFolder; |
| } |
| |
| /** |
| * Returns the <code>ScriptElementDelta</code> for |
| * <code>scriptProject</code>, creating it and putting it in |
| * <code>fDeltasPerProject</code> if it does not exist yet. |
| */ |
| private ModelElementDelta getDeltaFor(IScriptProject scriptProject) { |
| ModelElementDelta delta = (ModelElementDelta) deltasPerProject |
| .get(scriptProject); |
| if (delta == null) { |
| delta = new ModelElementDelta(scriptProject); |
| deltasPerProject.put(scriptProject, delta); |
| } |
| return delta; |
| } |
| |
| /** |
| * @see MultiOperation |
| */ |
| @Override |
| protected String getMainTaskName() { |
| return Messages.operation_copyResourceProgress; |
| } |
| |
| /** |
| * Sets the deltas to register the changes resulting from this operation for |
| * this source element and its destination. If the operation is a cross |
| * project operation |
| * <ul> |
| * <li>On a copy, the delta should be rooted in the dest project |
| * <li>On a move, two deltas are generated |
| * <ul> |
| * <li>one rooted in the source project |
| * <li>one rooted in the destination project |
| * </ul> |
| * </ul> |
| * If the operation is rooted in a single project, the delta is rooted in |
| * that project |
| * |
| */ |
| protected void prepareDeltas(IModelElement sourceElement, |
| IModelElement destinationElement, boolean isMove) { |
| if (Util.isExcluded(sourceElement) |
| || Util.isExcluded(destinationElement)) |
| return; |
| IScriptProject destProject = destinationElement.getScriptProject(); |
| if (isMove) { |
| IScriptProject sourceProject = sourceElement.getScriptProject(); |
| getDeltaFor(sourceProject).movedFrom(sourceElement, |
| destinationElement); |
| getDeltaFor(destProject).movedTo(destinationElement, sourceElement); |
| } else { |
| getDeltaFor(destProject).added(destinationElement); |
| } |
| } |
| |
| /** |
| * Copies/moves a compilation unit with the name <code>newCUName</code> to |
| * the destination package.<br> |
| * The package statement in the compilation unit is updated if necessary. |
| * The main type of the compilation unit is renamed if necessary. |
| * |
| * @exception ScriptModelException |
| * if the operation is unable to complete |
| */ |
| private void processSourceModuleResource(ISourceModule source, |
| IScriptFolder dest) throws ModelException { |
| String newCUName = getNewNameFor(source); |
| String destName = (newCUName != null) ? newCUName : source |
| .getElementName(); |
| // ASTRewrite rewrite = updateContent(source, dest, newCUName); // null |
| // if unchanged |
| // TODO (frederic) remove when bug 67606 will be fixed (bug 67823) |
| // store encoding (fix bug 66898) |
| IFile sourceResource = (IFile) source.getResource(); |
| // String sourceEncoding = null; |
| // try { |
| // if( sourceResource != null ) { |
| // sourceEncoding = sourceResource.getCharset(false); |
| // } |
| // } catch (CoreException ce) { |
| // // no problem, use default encoding |
| // } |
| // end todo |
| // copy resource |
| IContainer destFolder = (IContainer) dest.getResource(); // can be an |
| // IFolder |
| // or an |
| // IProject |
| IFile destFile = destFolder.getFile(new Path(destName)); |
| SourceModule destCU = new SourceModule((ModelElement) dest, destName, |
| DefaultWorkingCopyOwner.PRIMARY); |
| if (sourceResource == null || !destFile.equals(sourceResource)) { |
| try { |
| if (!destCU.isWorkingCopy()) { |
| if (destFile.exists()) { |
| if (this.force) { |
| // we can remove it |
| deleteResource(destFile, IResource.KEEP_HISTORY); |
| destCU.close(); // ensure the in-memory buffer for |
| // the dest CU is closed |
| } else { |
| // abort |
| throw new ModelException(new ModelStatus( |
| IModelStatusConstants.NAME_COLLISION, |
| Messages.bind( |
| Messages.status_nameCollision, |
| destFile.getFullPath().toString()))); |
| } |
| } |
| int flags = this.force ? IResource.FORCE : IResource.NONE; |
| if (this.isMove()) { |
| flags |= IResource.KEEP_HISTORY; |
| if (sourceResource != null) { |
| sourceResource.move(destFile.getFullPath(), flags, |
| getSubProgressMonitor(1)); |
| } else { |
| if (DLTKCore.DEBUG) { |
| System.err |
| .println("TODO: Add correct status message here..."); //$NON-NLS-1$ |
| } |
| throw new ModelException(new ModelStatus( |
| IModelStatusConstants.NAME_COLLISION, |
| Messages.bind( |
| Messages.status_invalidResource, |
| destFile.getFullPath().toString()))); |
| } |
| } else { |
| // if (rewrite != null) flags |= IResource.KEEP_HISTORY; |
| if (sourceResource == null) { |
| ByteArrayInputStream bais = new ByteArrayInputStream( |
| new byte[0]); |
| destFile.create(bais, IResource.FORCE, |
| getSubProgressMonitor(1)); |
| destCU.getBuffer().setContents( |
| source.getSourceAsCharArray()); |
| destCU.save(getSubProgressMonitor(1), true); |
| } else { |
| sourceResource.copy(destFile.getFullPath(), flags, |
| getSubProgressMonitor(1)); |
| } |
| } |
| this.setAttribute(HAS_MODIFIED_RESOURCE_ATTR, TRUE); |
| } else { |
| destCU.getBuffer().setContents( |
| source.getBuffer().getContents()); |
| } |
| } catch (ModelException e) { |
| throw e; |
| } catch (CoreException e) { |
| throw new ModelException(e); |
| } |
| // update new resource content |
| // if (rewrite != null){ |
| // boolean wasReadOnly = destFile.isReadOnly(); |
| // try { |
| // saveContent(dest, destName, rewrite, sourceEncoding, destFile); |
| // } catch (CoreException e) { |
| // if (e instanceof ModelException) throw (ModelException) e; |
| // throw new ModelException(e); |
| // } finally { |
| // Util.setReadOnly(destFile, wasReadOnly); |
| // } |
| // } |
| // register the correct change deltas |
| prepareDeltas(source, destCU, isMove()); |
| if (newCUName != null) { |
| // the main type has been renamed |
| if (DLTKCore.DEBUG) { |
| System.err.println("TODO: Add remove extensions here..."); //$NON-NLS-1$ |
| } |
| String oldName = /* Util.getNameWithoutScriptLikeExtension( */source |
| .getElementName();// ); |
| String newName = /* Util.getNameWithoutScriptLikeExtension( */newCUName;// ) |
| // ; |
| prepareDeltas(source.getType(oldName), destCU.getType(newName), |
| isMove()); |
| } |
| } else { |
| if (!this.force) { |
| throw new ModelException(new ModelStatus( |
| IModelStatusConstants.NAME_COLLISION, Messages.bind( |
| Messages.status_nameCollision, destFile |
| .getFullPath().toString()))); |
| } |
| // update new resource content |
| // in case we do a saveas on the same resource we have to simply |
| // update the contents |
| // see http://dev.eclipse.org/bugs/show_bug.cgi?id=9351 |
| // try { |
| // if (rewrite != null){ |
| // saveContent(dest, destName, rewrite, sourceEncoding, destFile); |
| // } |
| // } catch (CoreException e) { |
| // if (e instanceof ModelException) throw (ModelException) e; |
| // throw new ModelException(e); |
| // } |
| } |
| } |
| |
| /** |
| * Process all of the changed deltas generated by this operation. |
| */ |
| protected void processDeltas() { |
| for (Iterator deltas = this.deltasPerProject.values().iterator(); deltas |
| .hasNext();) { |
| addDelta((IModelElementDelta) deltas.next()); |
| } |
| } |
| |
| /** |
| * @see MultiOperation This method delegates to |
| * <code>processSourceModuleResource</code> or |
| * <code>processScriptFolderResource</code>, depending on the type of |
| * <code>element</code>. |
| */ |
| @Override |
| protected void processElement(IModelElement element) throws ModelException { |
| IModelElement dest = getDestinationParent(element); |
| switch (element.getElementType()) { |
| case IModelElement.SOURCE_MODULE: |
| processSourceModuleResource((ISourceModule) element, |
| (IScriptFolder) dest); |
| createdElements.add(((IScriptFolder) dest).getSourceModule(element |
| .getElementName())); |
| break; |
| case IModelElement.SCRIPT_FOLDER: |
| processScriptFolderResource((IScriptFolder) element, |
| (IProjectFragment) dest, getNewNameFor(element)); |
| break; |
| default: |
| throw new ModelException(new ModelStatus( |
| IModelStatusConstants.INVALID_ELEMENT_TYPES, element)); |
| } |
| } |
| |
| /** |
| * @see MultiOperation Overridden to allow special processing of |
| * <code>ScriptElementDelta</code>s and <code>fResultElements</code>. |
| */ |
| @Override |
| protected void processElements() throws ModelException { |
| createdElements = new ArrayList(elementsToProcess.length); |
| try { |
| super.processElements(); |
| } catch (ModelException jme) { |
| throw jme; |
| } finally { |
| resultElements = new IModelElement[createdElements.size()]; |
| createdElements.toArray(resultElements); |
| processDeltas(); |
| } |
| } |
| |
| /** |
| * Copies/moves a package fragment with the name <code>newName</code> to the |
| * destination package.<br> |
| * |
| * @exception ScriptModelException |
| * if the operation is unable to complete |
| */ |
| private void processScriptFolderResource(IScriptFolder source, |
| IProjectFragment root, String newName) throws ModelException { |
| try { |
| // String[] newFragName = (newName == null) ? source.path.segments() |
| // : Util.getTrimmedSimpleNames(newName); |
| IPath source_path = source.getPath().removeFirstSegments( |
| source.getParent().getPath().segmentCount()); |
| IPath newFragName = (newName == null) ? source_path : new Path( |
| newName); |
| IScriptFolder newFrag = root.getScriptFolder(newFragName); |
| IResource[] resources = collectResourcesOfInterest(source); |
| // if isMove() can we move the folder itself ? (see |
| // http://bugs.eclipse.org/bugs/show_bug.cgi?id=22458) |
| boolean shouldMoveFolder = isMove() |
| && newFrag.getResource() != null |
| && !newFrag.getResource().exists(); // if |
| // new |
| // pkg |
| // fragment |
| // exists, |
| // it |
| // is |
| // an |
| // override |
| IFolder srcFolder = (IFolder) source.getResource(); |
| IPath destPath = newFrag.getPath(); |
| if (shouldMoveFolder) { |
| // check if destination is not included in source |
| if (srcFolder.getFullPath().isPrefixOf(destPath)) { |
| shouldMoveFolder = false; |
| } else { |
| // check if there are no sub-packages |
| IResource[] members = srcFolder.members(); |
| for (int i = 0; i < members.length; i++) { |
| if (members[i] instanceof IFolder) { |
| shouldMoveFolder = false; |
| break; |
| } |
| } |
| } |
| } |
| boolean containsReadOnlySubScriptFolders = createNeededScriptFolders( |
| (IContainer) source.getParent().getResource(), root, |
| newFragName, shouldMoveFolder); |
| boolean sourceIsReadOnly = Util.isReadOnly(srcFolder); |
| // Process resources |
| if (shouldMoveFolder) { |
| // move underlying resource |
| // TODO Revisit once bug 43044 is fixed |
| if (sourceIsReadOnly) { |
| Util.setReadOnly(srcFolder, false); |
| } |
| srcFolder.move(destPath, force, true /* keep history */, |
| getSubProgressMonitor(1)); |
| if (sourceIsReadOnly) { |
| Util.setReadOnly(srcFolder, true); |
| } |
| this.setAttribute(HAS_MODIFIED_RESOURCE_ATTR, TRUE); |
| } else { |
| // process the leaf resources |
| if (resources.length > 0) { |
| if (isRename()) { |
| if (!destPath.equals(source.getPath())) { |
| moveResources(resources, destPath); |
| } |
| } else if (isMove()) { |
| // we need to delete this resource if this operation |
| // wants to override existing resources |
| for (int i = 0, max = resources.length; i < max; i++) { |
| IResource destinationResource = ResourcesPlugin |
| .getWorkspace().getRoot().findMember( |
| destPath.append(resources[i] |
| .getName())); |
| if (destinationResource != null) { |
| if (force) { |
| deleteResource(destinationResource, |
| IResource.KEEP_HISTORY); |
| } else { |
| throw new ModelException( |
| new ModelStatus( |
| IModelStatusConstants.NAME_COLLISION, |
| Messages |
| .bind( |
| Messages.status_nameCollision, |
| destinationResource |
| .getFullPath() |
| .toString()))); |
| } |
| } |
| } |
| moveResources(resources, destPath); |
| } else { |
| // we need to delete this resource if this operation |
| // wants to override existing resources |
| for (int i = 0, max = resources.length; i < max; i++) { |
| IResource destinationResource = ResourcesPlugin |
| .getWorkspace().getRoot().findMember( |
| destPath.append(resources[i] |
| .getName())); |
| if (destinationResource != null) { |
| if (force) { |
| // we need to delete this resource if this |
| // operation wants to override existing |
| // resources |
| deleteResource(destinationResource, |
| IResource.KEEP_HISTORY); |
| } else { |
| throw new ModelException( |
| new ModelStatus( |
| IModelStatusConstants.NAME_COLLISION, |
| Messages |
| .bind( |
| Messages.status_nameCollision, |
| destinationResource |
| .getFullPath() |
| .toString()))); |
| } |
| } |
| } |
| copyResources(resources, destPath); |
| } |
| } |
| } |
| // Update package statement in compilation unit if needed |
| if (!Util.equalArraysOrNull(new Object[] { newFragName }, |
| new Object[] { source_path })) { // if package has been |
| // renamed, update the |
| // compilation units |
| |
| for (int i = 0; i < resources.length; i++) { |
| String resourceName = resources[i].getName(); |
| IDLTKLanguageToolkit toolkit = DLTKLanguageManager |
| .getLanguageToolkit(newFrag); |
| if (toolkit != null |
| && DLTKContentTypeManager |
| .isValidResourceForContentType(toolkit, |
| resources[i])) { |
| // we only consider potential compilation units |
| ISourceModule cu = newFrag |
| .getSourceModule(resourceName); |
| if (Util.isExcluded(cu.getPath(), root, false/* |
| * not a |
| * folder |
| */)) |
| continue; |
| if (DLTKCore.DEBUG) { |
| System.err |
| .println("TODO:Add source module modification code here..."); //$NON-NLS-1$ |
| } |
| // this.parser.setSource(cu); |
| // SourceModule astCU = (SourceModule) |
| // this.parser.createAST(this.progressMonitor); |
| // AST ast = astCU.getAST(); |
| // ASTRewrite rewrite = ASTRewrite.create(ast); |
| // updatePackageStatement(astCU, newFragName, rewrite); |
| // IDocument document = getDocument(cu); |
| // TextEdit edits = rewrite.rewriteAST(document, null); |
| // try { |
| // edits.apply(document); |
| // } catch (BadLocationException e) { |
| // throw new ModelException(e, |
| // IModelStatusConstants.INVALID_CONTENTS); |
| // } |
| cu.save(null, false); |
| } |
| } |
| } |
| // Discard empty old package (if still empty after the rename) |
| boolean isEmpty = true; |
| if (isMove() && srcFolder != null) { |
| // delete remaining files in this package (.class file in the |
| // case where Proj=src=bin) |
| // in case of a copy |
| updateReadOnlyScriptFoldersForMove((IContainer) source |
| .getParent().getResource(), root, newFragName, |
| sourceIsReadOnly); |
| if (srcFolder.exists()) { |
| IResource[] remaining = srcFolder.members(); |
| for (int i = 0, length = remaining.length; i < length; i++) { |
| IResource file = remaining[i]; |
| if (file instanceof IFile) { |
| if (Util.isReadOnly(file)) { |
| Util.setReadOnly(file, false); |
| } |
| this.deleteResource(file, IResource.FORCE |
| | IResource.KEEP_HISTORY); |
| } else { |
| isEmpty = false; |
| } |
| } |
| } |
| if (isEmpty) { |
| IResource rootResource; |
| // check if source is included in destination |
| if (destPath.isPrefixOf(srcFolder.getFullPath())) { |
| rootResource = newFrag.getResource(); |
| } else { |
| rootResource = source.getParent().getResource(); |
| } |
| // delete recursively empty folders |
| deleteEmptyScriptFolder(source, false, rootResource); |
| } |
| } else if (containsReadOnlySubScriptFolders) { |
| // in case of a copy |
| updateReadOnlyScriptFoldersForCopy((IContainer) source |
| .getParent().getResource(), root, newFragName); |
| } |
| // workaround for bug |
| // https://bugs.eclipse.org/bugs/show_bug.cgi?id=24505 |
| if (isEmpty && isMove() |
| && !(Util.isExcluded(source) || Util.isExcluded(newFrag))) { |
| IScriptProject sourceProject = source.getScriptProject(); |
| getDeltaFor(sourceProject).movedFrom(source, newFrag); |
| IScriptProject destProject = newFrag.getScriptProject(); |
| getDeltaFor(destProject).movedTo(newFrag, source); |
| } |
| } catch (ModelException e) { |
| throw e; |
| } catch (CoreException ce) { |
| throw new ModelException(ce); |
| } |
| } |
| |
| private void updateReadOnlyScriptFoldersForCopy(IContainer sourceFolder, |
| IProjectFragment root, IPath newFragName) { |
| IContainer parentFolder = (IContainer) root.getResource(); |
| for (int i = 0, length = newFragName.segmentCount(); i < length; i++) { |
| String subFolderName = newFragName.segment(i); |
| parentFolder = parentFolder.getFolder(new Path(subFolderName)); |
| sourceFolder = sourceFolder.getFolder(new Path(subFolderName)); |
| if (sourceFolder.exists() && Util.isReadOnly(sourceFolder)) { |
| Util.setReadOnly(parentFolder, true); |
| } |
| } |
| } |
| |
| private void updateReadOnlyScriptFoldersForMove(IContainer sourceFolder, |
| IProjectFragment root, IPath newFragName, |
| boolean sourceFolderIsReadOnly) { |
| IContainer parentFolder = (IContainer) root.getResource(); |
| for (int i = 0, length = newFragName.segmentCount(); i < length; i++) { |
| String subFolderName = newFragName.segment(i); |
| parentFolder = parentFolder.getFolder(new Path(subFolderName)); |
| sourceFolder = sourceFolder.getFolder(new Path(subFolderName)); |
| if ((sourceFolder.exists() && Util.isReadOnly(sourceFolder)) |
| || (i == length - 1 && sourceFolderIsReadOnly)) { |
| Util.setReadOnly(parentFolder, true); |
| // the source folder will be deleted anyway (move operation) |
| Util.setReadOnly(sourceFolder, false); |
| } |
| } |
| } |
| |
| /** |
| * 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 != elementsToProcess.length) { |
| return new ModelStatus(IModelStatusConstants.INDEX_OUT_OF_BOUNDS); |
| } |
| return ModelStatus.VERIFIED_OK; |
| } |
| |
| /** |
| * @see MultiOperation |
| */ |
| @Override |
| protected void verify(IModelElement element) throws ModelException { |
| if (element == null || !element.exists()) |
| error(IModelStatusConstants.ELEMENT_DOES_NOT_EXIST, element); |
| if (element.isReadOnly() && (isRename() || isMove())) |
| error(IModelStatusConstants.READ_ONLY, element); |
| IResource resource = element.getResource(); |
| if (resource instanceof IFolder) { |
| if (resource.isLinked()) { |
| error(IModelStatusConstants.INVALID_RESOURCE, element); |
| } |
| } |
| int elementType = element.getElementType(); |
| if (elementType == IModelElement.SOURCE_MODULE |
| && element instanceof SourceModule) { |
| SourceModule compilationUnit = (SourceModule) element; |
| if (isMove() && compilationUnit.isWorkingCopy() |
| && !compilationUnit.isPrimary()) |
| error(IModelStatusConstants.INVALID_ELEMENT_TYPES, element); |
| } else if (elementType == IModelElement.SOURCE_MODULE |
| && element instanceof ExternalSourceModule) { |
| if (isMove()) |
| error(IModelStatusConstants.INVALID_ELEMENT_TYPES, element); |
| } else if (elementType == IModelElement.SOURCE_MODULE |
| && element instanceof BuiltinSourceModule) { |
| if (isMove()) |
| error(IModelStatusConstants.INVALID_ELEMENT_TYPES, element); |
| } else if (elementType != IModelElement.SCRIPT_FOLDER) { |
| error(IModelStatusConstants.INVALID_ELEMENT_TYPES, element); |
| } |
| ModelElement dest = (ModelElement) getDestinationParent(element); |
| verifyDestination(element, dest); |
| if (this.renamings != null) { |
| verifyRenaming(element); |
| } |
| } |
| } |