Copyright (c) 2006, 2015 IBM Corporation and others. This program and the accompanying materials are made available under the terms of the Eclipse Public License 2.0 which accompanies this distribution, and is available at https://www.eclipse.org/legal/epl-2.0/ SPDX-License-Identifier: EPL-2.0 Contributors: IBM Corporation - initial API and implementation
/******************************************************************************* * Copyright (c) 2006, 2015 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 * which accompanies this distribution, and is available at * https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/
package org.eclipse.core.internal.resources.mapping; import org.eclipse.core.internal.utils.Policy; import org.eclipse.core.resources.*; import org.eclipse.core.resources.mapping.IResourceChangeDescriptionFactory; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath;
Factory for creating a resource delta that describes a proposed change.
/** * Factory for creating a resource delta that describes a proposed change. */
public class ResourceChangeDescriptionFactory implements IResourceChangeDescriptionFactory { private ProposedResourceDelta root = new ProposedResourceDelta(ResourcesPlugin.getWorkspace().getRoot());
Creates and a delta representing a deleted resource, and adds it to the provided parent delta.
Params:
  • parentDelta – The parent of the deletion delta to create
  • resource – The deleted resource to create a delta for
/** * Creates and a delta representing a deleted resource, and adds it to the provided * parent delta. * @param parentDelta The parent of the deletion delta to create * @param resource The deleted resource to create a delta for */
private ProposedResourceDelta buildDeleteDelta(ProposedResourceDelta parentDelta, IResource resource) { //start with the existing delta for this resource, if any, to preserve other flags ProposedResourceDelta delta = parentDelta.getChild(resource.getName()); if (delta == null) { delta = new ProposedResourceDelta(resource); parentDelta.add(delta); } delta.setKind(IResourceDelta.REMOVED); if (resource.getType() == IResource.FILE) return delta; //recurse to build deletion deltas for children try { IResource[] members = ((IContainer) resource).members(); int childCount = members.length; if (childCount > 0) { ProposedResourceDelta[] childDeltas = new ProposedResourceDelta[childCount]; for (int i = 0; i < childCount; i++) childDeltas[i] = buildDeleteDelta(delta, members[i]); } } catch (CoreException e) { //don't need to create deletion deltas for children of inaccessible resources } return delta; } @Override public void change(IFile file) { ProposedResourceDelta delta = getDelta(file); if (delta.getKind() == 0) delta.setKind(IResourceDelta.CHANGED); //the CONTENT flag only applies to the changed and moved from cases if (delta.getKind() == IResourceDelta.CHANGED || (delta.getFlags() & IResourceDelta.MOVED_FROM) != 0 || (delta.getFlags() & IResourceDelta.COPIED_FROM) != 0) delta.addFlags(IResourceDelta.CONTENT); } @Override public void close(IProject project) { delete(project); ProposedResourceDelta delta = getDelta(project); delta.addFlags(IResourceDelta.OPEN); } @Override public void copy(IResource resource, IPath destination) { moveOrCopyDeep(resource, destination, false /* copy */); } @Override public void create(IResource resource) { getDelta(resource).setKind(IResourceDelta.ADDED); } @Override public void delete(IResource resource) { if (resource.getType() == IResource.ROOT) { //the root itself cannot be deleted, so create deletions for each project IProject[] projects = ((IWorkspaceRoot) resource).getProjects(IContainer.INCLUDE_HIDDEN); for (IProject project : projects) buildDeleteDelta(root, project); } else { buildDeleteDelta(getDelta(resource.getParent()), resource); } } private void fail(CoreException e) { Policy.log(e.getStatus().getSeverity(), "An internal error occurred while accumulating a change description.", e); //$NON-NLS-1$ } @Override public IResourceDelta getDelta() { return root; } ProposedResourceDelta getDelta(IResource resource) { ProposedResourceDelta delta = (ProposedResourceDelta) root.findMember(resource.getFullPath()); if (delta != null) { return delta; } ProposedResourceDelta parent = getDelta(resource.getParent()); delta = new ProposedResourceDelta(resource); parent.add(delta); return delta; } /* * Return the resource at the destination path that corresponds to the source resource * @param source the source resource * @param sourcePrefix the path of the root of the move or copy * @param destinationPrefix the path of the destination the root was copied to * @return the destination resource */ protected IResource getDestinationResource(IResource source, IPath sourcePrefix, IPath destinationPrefix) { IPath relativePath = source.getFullPath().removeFirstSegments(sourcePrefix.segmentCount()); IPath destinationPath = destinationPrefix.append(relativePath); IResource destination; IWorkspaceRoot wsRoot = ResourcesPlugin.getWorkspace().getRoot(); switch (source.getType()) { case IResource.FILE : destination = wsRoot.getFile(destinationPath); break; case IResource.FOLDER : destination = wsRoot.getFolder(destinationPath); break; case IResource.PROJECT : destination = wsRoot.getProject(destinationPath.segment(0)); break; default : // Shouldn't happen destination = null; } return destination; } @Override public void move(IResource resource, IPath destination) { moveOrCopyDeep(resource, destination, true /* move */); }
Builds the delta representing a single resource being moved or copied.
Params:
  • resource – The resource being moved
  • sourcePrefix – The root of the sub-tree being moved
  • destinationPrefix – The root of the destination sub-tree
  • move – true for a move, false for a copy
Returns:Whether to move or copy the child
/** * Builds the delta representing a single resource being moved or copied. * * @param resource The resource being moved * @param sourcePrefix The root of the sub-tree being moved * @param destinationPrefix The root of the destination sub-tree * @param move <code>true</code> for a move, <code>false</code> for a copy * @return Whether to move or copy the child */
boolean moveOrCopy(IResource resource, final IPath sourcePrefix, final IPath destinationPrefix, final boolean move) { ProposedResourceDelta sourceDelta = getDelta(resource); if (sourceDelta.getKind() == IResourceDelta.REMOVED) { // There is already a removed delta here so there // is nothing to move/copy return false; } IResource destinationResource = getDestinationResource(resource, sourcePrefix, destinationPrefix); ProposedResourceDelta destinationDelta = getDelta(destinationResource); if ((destinationDelta.getKind() & (IResourceDelta.ADDED | IResourceDelta.CHANGED)) > 0) { // There is already a resource at the destination // TODO: What do we do return false; } // First, create the delta for the source IPath fromPath = resource.getFullPath(); boolean wasAdded = false; final int sourceFlags = sourceDelta.getFlags(); if (move) { // We transfer the source flags to the destination if (sourceDelta.getKind() == IResourceDelta.ADDED) { if ((sourceFlags & IResourceDelta.MOVED_FROM) != 0) { // The resource was moved from somewhere else so // we need to transfer the path to the new location fromPath = sourceDelta.getMovedFromPath(); sourceDelta.setMovedFromPath(null); } // The source was added and then moved so we'll // make it an add at the destination sourceDelta.setKind(0); wasAdded = true; } else { // We reset the status to be a remove/move_to sourceDelta.setKind(IResourceDelta.REMOVED); sourceDelta.setFlags(IResourceDelta.MOVED_TO); sourceDelta.setMovedToPath(destinationPrefix.append(fromPath.removeFirstSegments(sourcePrefix.segmentCount()))); } } // Next, create the delta for the destination if (destinationDelta.getKind() == IResourceDelta.REMOVED) { // The destination was removed and is being re-added destinationDelta.setKind(IResourceDelta.CHANGED); destinationDelta.addFlags(IResourceDelta.REPLACED); } else { destinationDelta.setKind(IResourceDelta.ADDED); } if (!wasAdded || !fromPath.equals(resource.getFullPath())) { // The source wasn't added so it is a move/copy destinationDelta.addFlags(move ? IResourceDelta.MOVED_FROM : IResourceDelta.COPIED_FROM); destinationDelta.setMovedFromPath(fromPath); // Apply the source flags if (move) destinationDelta.addFlags(sourceFlags); } return true; }
Helper method that generate a move or copy delta for a sub-tree of resources being moved or copied.
/** * Helper method that generate a move or copy delta for a sub-tree * of resources being moved or copied. */
private void moveOrCopyDeep(IResource resource, IPath destination, final boolean move) { final IPath sourcePrefix = resource.getFullPath(); final IPath destinationPrefix = destination; try { //build delta for the entire sub-tree if available if (resource.isAccessible()) { resource.accept(child -> moveOrCopy(child, sourcePrefix, destinationPrefix, move)); } else { //just build a delta for the single resource moveOrCopy(resource, sourcePrefix, destination, move); } } catch (CoreException e) { fail(e); } } }