| /******************************************************************************* |
| * Copyright (c) 2006, 2007 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 |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| |
| package org.eclipse.ui.internal.ide.undo; |
| |
| import java.net.URI; |
| |
| 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.IWorkspaceRoot; |
| import org.eclipse.core.resources.ResourcesPlugin; |
| import org.eclipse.core.runtime.Assert; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IPath; |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.Path; |
| import org.eclipse.core.runtime.SubProgressMonitor; |
| import org.eclipse.ui.ide.undo.ResourceDescription; |
| |
| /** |
| * ContainerDescription is a lightweight description that describes a container |
| * to be created. |
| * |
| * This class is not intended to be instantiated or used by clients. |
| * |
| * @since 3.3 |
| * |
| */ |
| public abstract class ContainerDescription extends AbstractResourceDescription { |
| |
| String name; |
| |
| URI location; |
| |
| String defaultCharSet; |
| |
| AbstractResourceDescription[] members; |
| |
| /** |
| * Create a container description from the specified container handle that |
| * can be used to create the container. The returned ContainerDescription |
| * should represent any non-existing parents in addition to the specified |
| * container. |
| * |
| * @param container |
| * the handle of the container to be described |
| * @return a container description describing the container and any |
| * non-existing parents. |
| */ |
| |
| public static ContainerDescription fromContainer(IContainer container) { |
| IPath fullPath = container.getFullPath(); |
| ContainerDescription firstCreatedParent = null; |
| ContainerDescription currentContainerDescription = null; |
| |
| // Does the container exist already? If so, then the parent exists and |
| // we use the normal creation constructor. |
| IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); |
| IContainer currentContainer = (IContainer) root.findMember(fullPath); |
| if (currentContainer != null) { |
| return (ContainerDescription) ResourceDescription |
| .fromResource(container); |
| } |
| |
| // Create container descriptions for any uncreated parents in the given |
| // path. |
| currentContainer = root; |
| for (int i = 0; i < fullPath.segmentCount(); i++) { |
| String currentSegment = fullPath.segment(i); |
| IResource resource = currentContainer.findMember(currentSegment); |
| if (resource != null) { |
| // parent already exists, no need to create a description for it |
| currentContainer = (IContainer) resource; |
| } else { |
| if (i == 0) { |
| // parent does not exist and it is a project |
| firstCreatedParent = new ProjectDescription(root |
| .getProject(currentSegment)); |
| currentContainerDescription = firstCreatedParent; |
| } else { |
| IFolder folderHandle = currentContainer.getFolder(new Path( |
| currentSegment)); |
| ContainerDescription currentFolder = new FolderDescription( |
| folderHandle); |
| currentContainer = folderHandle; |
| if (currentContainerDescription != null) { |
| currentContainerDescription.addMember(currentFolder); |
| } |
| currentContainerDescription = currentFolder; |
| if (firstCreatedParent == null) { |
| firstCreatedParent = currentFolder; |
| } |
| } |
| } |
| } |
| return firstCreatedParent; |
| } |
| |
| /** |
| * Create a ContainerDescription with no state. |
| */ |
| public ContainerDescription() { |
| |
| } |
| |
| /** |
| * Create a ContainerDescription from the specified container handle. |
| * Typically used when the container handle represents a resource that |
| * actually exists, although it will not fail if the resource is |
| * non-existent. |
| * |
| * @param container |
| * the container to be described |
| */ |
| public ContainerDescription(IContainer container) { |
| super(container); |
| this.name = container.getName(); |
| if (container.isLinked()) { |
| this.location = container.getLocationURI(); |
| } |
| try { |
| if (container.isAccessible()) { |
| defaultCharSet = container.getDefaultCharset(false); |
| IResource[] resourceMembers = container.members(); |
| members = new AbstractResourceDescription[resourceMembers.length]; |
| for (int i = 0; i < resourceMembers.length; i++) { |
| members[i] = (AbstractResourceDescription) ResourceDescription |
| .fromResource(resourceMembers[i]); |
| } |
| } |
| } catch (CoreException e) { |
| // Eat this exception because it only occurs when the resource |
| // does not exist and we have already checked this. |
| // We do not want to throw exceptions on the simple constructor, as |
| // no one has actually tried to do anything yet. |
| } |
| } |
| |
| /** |
| * Create any child resources known by this container description. |
| * |
| * @param parentHandle |
| * the handle of the created parent |
| * @param monitor |
| * the progress monitor to be used |
| * @param ticks |
| * the number of ticks allocated for creating children |
| * @throws CoreException |
| */ |
| protected void createChildResources(IContainer parentHandle, |
| IProgressMonitor monitor, int ticks) throws CoreException { |
| |
| // restore any children |
| if (members != null && members.length > 0) { |
| for (int i = 0; i < members.length; i++) { |
| members[i].parent = parentHandle; |
| members[i].createResource(new SubProgressMonitor(monitor, ticks |
| / members.length)); |
| } |
| } |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.ui.internal.ide.undo.ResourceDescription#recordStateFromHistory(org.eclipse.core.resources.IResource, |
| * org.eclipse.core.runtime.IProgressMonitor) |
| */ |
| public void recordStateFromHistory(IResource resource, |
| IProgressMonitor monitor) throws CoreException { |
| monitor.beginTask( |
| UndoMessages.FolderDescription_SavingUndoInfoProgress, 100); |
| if (members != null) { |
| for (int i = 0; i < members.length; i++) { |
| if (members[i] instanceof FileDescription) { |
| IPath path = resource.getFullPath().append( |
| ((FileDescription) members[i]).name); |
| IFile fileHandle = resource.getWorkspace().getRoot().getFile( |
| path); |
| members[i].recordStateFromHistory(fileHandle, |
| new SubProgressMonitor(monitor, 100 / members.length)); |
| } else if (members[i] instanceof FolderDescription) { |
| IPath path = resource.getFullPath().append( |
| ((FolderDescription) members[i]).name); |
| IFolder folderHandle = resource.getWorkspace().getRoot() |
| .getFolder(path); |
| members[i].recordStateFromHistory(folderHandle, |
| new SubProgressMonitor(monitor, 100 / members.length)); |
| } |
| } |
| } |
| monitor.done(); |
| } |
| |
| /** |
| * Return the name of the container described by this ContainerDescription. |
| * |
| * @return the name of the container. |
| */ |
| public String getName() { |
| return name; |
| } |
| |
| /** |
| * Return the first folder found that has no child folders. |
| * |
| * @return the container description for the first child in the receiver |
| * that is a leaf, or this container if there are no children. |
| */ |
| public ContainerDescription getFirstLeafFolder() { |
| // If there are no members, this is a leaf |
| if (members == null || members.length == 0) { |
| return this; |
| } |
| // Traverse the members and find the first potential leaf |
| for (int i = 0; i < members.length; i++) { |
| if (members[i] instanceof ContainerDescription) { |
| return ((ContainerDescription) members[i]).getFirstLeafFolder(); |
| } |
| } |
| // No child folders were found, this is a leaf |
| return this; |
| } |
| |
| /** |
| * Add the specified resource description as a member of this resource |
| * description |
| * |
| * @param member |
| * the resource description considered a member of this |
| * container. |
| */ |
| public void addMember(AbstractResourceDescription member) { |
| if (members == null) { |
| members = new AbstractResourceDescription[] { member }; |
| } else { |
| AbstractResourceDescription[] expandedMembers = new AbstractResourceDescription[members.length + 1]; |
| System.arraycopy(members, 0, expandedMembers, 0, members.length); |
| expandedMembers[members.length] = member; |
| members = expandedMembers; |
| } |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.ui.internal.ide.undo.ResourceDescription#restoreResourceAttributes(org.eclipse.core.resources.IResource) |
| */ |
| protected void restoreResourceAttributes(IResource resource) |
| throws CoreException { |
| super.restoreResourceAttributes(resource); |
| Assert.isLegal(resource instanceof IContainer); |
| IContainer container = (IContainer) resource; |
| if (defaultCharSet != null) { |
| container.setDefaultCharset(defaultCharSet, null); |
| } |
| } |
| |
| /** |
| * Set the location to which this container is linked. |
| * |
| * @param location |
| * the location URI, or <code>null</code> if there is no link |
| */ |
| public void setLocation(URI location) { |
| this.location = location; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.ui.internal.ide.undo.ResourceDescription#verifyExistence(boolean) |
| */ |
| public boolean verifyExistence(boolean checkMembers) { |
| boolean existence = super.verifyExistence(checkMembers); |
| if (existence) { |
| if (checkMembers) { |
| // restore any children |
| if (members != null && members.length > 0) { |
| for (int i = 0; i < members.length; i++) { |
| if (!members[i].verifyExistence(checkMembers)) { |
| return false; |
| } |
| } |
| } |
| } |
| return true; |
| } |
| return false; |
| } |
| } |