| /******************************************************************************* |
| * Copyright (c) 2000, 2015 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 |
| * Dan Rubel <dan_rubel@instantiations.com> - Implementation of getLocalTimeStamp |
| * Red Hat Incorporated - get/setResourceAttribute code |
| * Oakland Software Incorporated - added getSessionProperties and getPersistentProperties |
| * Holger Oehm <holger.oehm@sap.com> - [226264] race condition in Workspace.isTreeLocked()/setTreeLocked() |
| * Martin Oberhuber (Wind River) - [245937] ProjectDescription#setLinkLocation() detects non-change |
| * Serge Beauchamp (Freescale Semiconductor) - [252996] add resource filtering |
| * Serge Beauchamp (Freescale Semiconductor) - [229633] Project Path Variable Support |
| * James Blackburn (Broadcom Corp.) - ongoing development |
| * Sergey Prigogin (Google) - [338010] Resource.createLink() does not preserve symbolic links |
| * Lars Vogel <Lars.Vogel@vogella.com> - Bug 473427 |
| *******************************************************************************/ |
| package org.eclipse.core.internal.resources; |
| |
| import java.net.URI; |
| import java.net.URISyntaxException; |
| import java.util.*; |
| import org.eclipse.core.filesystem.*; |
| import org.eclipse.core.filesystem.URIUtil; |
| import org.eclipse.core.filesystem.provider.FileInfo; |
| import org.eclipse.core.internal.events.LifecycleEvent; |
| import org.eclipse.core.internal.localstore.FileSystemResourceManager; |
| import org.eclipse.core.internal.properties.IPropertyManager; |
| import org.eclipse.core.internal.utils.*; |
| import org.eclipse.core.internal.watson.*; |
| import org.eclipse.core.resources.*; |
| import org.eclipse.core.resources.team.IMoveDeleteHook; |
| import org.eclipse.core.runtime.*; |
| import org.eclipse.core.runtime.jobs.ISchedulingRule; |
| import org.eclipse.core.runtime.jobs.MultiRule; |
| import org.eclipse.osgi.util.NLS; |
| |
| public abstract class Resource extends PlatformObject implements IResource, ICoreConstants, Cloneable, IPathRequestor { |
| /* package */IPath path; |
| /* package */Workspace workspace; |
| |
| protected Resource(IPath path, Workspace workspace) { |
| this.path = path.removeTrailingSeparator(); |
| this.workspace = workspace; |
| } |
| |
| @Override |
| public void accept(IResourceProxyVisitor visitor, int memberFlags) throws CoreException { |
| accept(visitor, IResource.DEPTH_INFINITE, memberFlags); |
| } |
| |
| @Override |
| public void accept(final IResourceProxyVisitor visitor, final int depth, final int memberFlags) throws CoreException { |
| // It is invalid to call accept on a phantom when INCLUDE_PHANTOMS is not specified. |
| final boolean includePhantoms = (memberFlags & IContainer.INCLUDE_PHANTOMS) != 0; |
| if ((memberFlags & IContainer.DO_NOT_CHECK_EXISTENCE) == 0) |
| checkAccessible(getFlags(getResourceInfo(includePhantoms, false))); |
| |
| final ResourceProxy proxy = new ResourceProxy(); |
| IElementContentVisitor elementVisitor = new IElementContentVisitor() { |
| @Override |
| public boolean visitElement(ElementTree tree, IPathRequestor requestor, Object contents) { |
| ResourceInfo info = (ResourceInfo) contents; |
| if (!isMember(getFlags(info), memberFlags)) |
| return false; |
| proxy.requestor = requestor; |
| proxy.info = info; |
| try { |
| boolean shouldContinue = true; |
| switch (depth) { |
| case DEPTH_ZERO : |
| shouldContinue = false; |
| break; |
| case DEPTH_ONE : |
| shouldContinue = !path.equals(requestor.requestPath().removeLastSegments(1)); |
| break; |
| case DEPTH_INFINITE : |
| shouldContinue = true; |
| break; |
| } |
| return visitor.visit(proxy) && shouldContinue; |
| } catch (CoreException e) { |
| // Throw an exception to bail out of the traversal. |
| throw new WrappedRuntimeException(e); |
| } finally { |
| proxy.reset(); |
| } |
| } |
| }; |
| try { |
| new ElementTreeIterator(workspace.getElementTree(), getFullPath()).iterate(elementVisitor); |
| } catch (WrappedRuntimeException e) { |
| throw (CoreException) e.getTargetException(); |
| } finally { |
| proxy.requestor = null; |
| proxy.info = null; |
| } |
| } |
| |
| @Override |
| public void accept(IResourceVisitor visitor) throws CoreException { |
| accept(visitor, IResource.DEPTH_INFINITE, 0); |
| } |
| |
| @Override |
| public void accept(IResourceVisitor visitor, int depth, boolean includePhantoms) throws CoreException { |
| accept(visitor, depth, includePhantoms ? IContainer.INCLUDE_PHANTOMS : 0); |
| } |
| |
| @Override |
| public void accept(final IResourceVisitor visitor, int depth, int memberFlags) throws CoreException { |
| // Use the fast visitor if visiting to infinite depth. |
| if (depth == IResource.DEPTH_INFINITE) { |
| accept(new IResourceProxyVisitor() { |
| @Override |
| public boolean visit(IResourceProxy proxy) throws CoreException { |
| return visitor.visit(proxy.requestResource()); |
| } |
| }, memberFlags); |
| return; |
| } |
| // It is invalid to call accept on a phantom when INCLUDE_PHANTOMS is not specified. |
| final boolean includePhantoms = (memberFlags & IContainer.INCLUDE_PHANTOMS) != 0; |
| ResourceInfo info = getResourceInfo(includePhantoms, false); |
| int flags = getFlags(info); |
| if ((memberFlags & IContainer.DO_NOT_CHECK_EXISTENCE) == 0) |
| checkAccessible(flags); |
| |
| // Check that this resource matches the member flags |
| if (!isMember(flags, memberFlags)) |
| return; |
| // Visit this resource. |
| if (!visitor.visit(this) || depth == DEPTH_ZERO) |
| return; |
| // Get the info again because it might have been changed by the visitor. |
| info = getResourceInfo(includePhantoms, false); |
| if (info == null) |
| return; |
| // Thread safety: (cache the type to avoid changes -- we might not be inside an operation). |
| int type = info.getType(); |
| if (type == FILE) |
| return; |
| // If we had a gender change we need to fix up the resource before asking for its members. |
| IContainer resource = getType() != type ? (IContainer) workspace.newResource(getFullPath(), type) : (IContainer) this; |
| IResource[] members = resource.members(memberFlags); |
| for (int i = 0; i < members.length; i++) |
| members[i].accept(visitor, DEPTH_ZERO, memberFlags | IContainer.DO_NOT_CHECK_EXISTENCE); |
| } |
| |
| protected void assertCopyRequirements(IPath destination, int destinationType, int updateFlags) throws CoreException { |
| IStatus status = checkCopyRequirements(destination, destinationType, updateFlags); |
| if (!status.isOK()) { |
| // This assert is ok because the error cases generated by the check method above |
| // indicate assertion conditions. |
| Assert.isTrue(false, status.getChildren()[0].getMessage()); |
| } |
| } |
| |
| /** |
| * Throws an exception if the link preconditions are not met. Returns the file info |
| * for the file being linked to, or <code>null</code> if not available. |
| * @throws CoreException |
| */ |
| protected IFileInfo assertLinkRequirements(URI localLocation, int updateFlags) throws CoreException { |
| boolean allowMissingLocal = (updateFlags & IResource.ALLOW_MISSING_LOCAL) != 0; |
| if ((updateFlags & IResource.REPLACE) == 0) |
| checkDoesNotExist(getFlags(getResourceInfo(false, false)), true); |
| IStatus locationStatus = workspace.validateLinkLocationURI(this, localLocation); |
| // We only tolerate an undefined path variable in the allow missing local case. |
| final boolean variableUndefined = locationStatus.getCode() == IResourceStatus.VARIABLE_NOT_DEFINED_WARNING; |
| if (locationStatus.getSeverity() == IStatus.ERROR || (variableUndefined && !allowMissingLocal)) |
| throw new ResourceException(locationStatus); |
| // Check that the parent exists and is open. |
| Container parent = (Container) getParent(); |
| parent.checkAccessible(getFlags(parent.getResourceInfo(false, false))); |
| // If the variable is undefined we can't do any further checks. |
| if (variableUndefined) |
| return null; |
| // Check if the file exists. |
| URI resolved = getPathVariableManager().resolveURI(localLocation); |
| IFileStore store = EFS.getStore(resolved); |
| IFileInfo fileInfo = store.fetchInfo(); |
| boolean localExists = fileInfo.exists(); |
| if (!allowMissingLocal && !localExists) { |
| String msg = NLS.bind(Messages.links_localDoesNotExist, store.toString()); |
| throw new ResourceException(IResourceStatus.NOT_FOUND_LOCAL, getFullPath(), msg, null); |
| } |
| // Resource type and file system type must match. |
| if (localExists && ((getType() == IResource.FOLDER) != fileInfo.isDirectory())) { |
| String msg = NLS.bind(Messages.links_wrongLocalType, getFullPath()); |
| throw new ResourceException(IResourceStatus.WRONG_TYPE_LOCAL, getFullPath(), msg, null); |
| } |
| return fileInfo; |
| } |
| |
| protected void assertMoveRequirements(IPath destination, int destinationType, int updateFlags) throws CoreException { |
| IStatus status = checkMoveRequirements(destination, destinationType, updateFlags); |
| if (!status.isOK()) { |
| // This assert is ok because the error cases generated by the check method |
| // above indicate assertion conditions. |
| Assert.isTrue(false, status.getChildren()[0].getMessage()); |
| } |
| } |
| |
| public void checkAccessible(int flags) throws CoreException { |
| checkExists(flags, true); |
| } |
| |
| private ResourceInfo checkAccessibleAndLocal(int depth) throws CoreException { |
| ResourceInfo info = getResourceInfo(false, false); |
| int flags = getFlags(info); |
| checkAccessible(flags); |
| checkLocal(flags, depth); |
| return info; |
| } |
| |
| /** |
| * This method reports errors in two different ways. It can throw a |
| * CoreException or return a status. CoreExceptions are used according to the |
| * specification of the copy method. Programming errors, that would usually be |
| * prevented by using an "Assert" code, are reported as an IStatus. We're doing |
| * this way because we have two different methods to copy resources: |
| * IResource#copy and IWorkspace#copy. The first one gets the error and throws |
| * its message in an AssertionFailureException. The second one just throws a |
| * CoreException using the status returned by this method. |
| * |
| * @see IResource#copy(IPath, int, IProgressMonitor) |
| */ |
| public IStatus checkCopyRequirements(IPath destination, int destinationType, int updateFlags) throws CoreException { |
| String message = Messages.resources_copyNotMet; |
| MultiStatus status = new MultiStatus(ResourcesPlugin.PI_RESOURCES, IResourceStatus.INVALID_VALUE, message, null); |
| if (destination == null) { |
| message = Messages.resources_destNotNull; |
| return new ResourceStatus(IResourceStatus.INVALID_VALUE, getFullPath(), message); |
| } |
| destination = makePathAbsolute(destination); |
| if (getFullPath().isPrefixOf(destination)) { |
| message = NLS.bind(Messages.resources_copyDestNotSub, getFullPath()); |
| status.add(new ResourceStatus(IResourceStatus.INVALID_VALUE, getFullPath(), message)); |
| } |
| checkValidPath(destination, destinationType, false); |
| |
| ResourceInfo info; |
| checkAccessibleAndLocal(DEPTH_INFINITE); |
| |
| IPath destinationParent = destination.removeLastSegments(1); |
| checkValidGroupContainer(destinationParent, isLinked(), isVirtual()); |
| |
| Resource dest = workspace.newResource(destination, destinationType); |
| dest.checkDoesNotExist(); |
| |
| // Ensure we aren't trying to copy a file to a project. |
| if (getType() == IResource.FILE && destinationType == IResource.PROJECT) { |
| message = Messages.resources_fileToProj; |
| throw new ResourceException(IResourceStatus.INVALID_VALUE, getFullPath(), message, null); |
| } |
| |
| // We can't copy into a closed project. |
| if (destinationType != IResource.PROJECT) { |
| Project project = (Project) dest.getProject(); |
| info = project.getResourceInfo(false, false); |
| project.checkAccessible(getFlags(info)); |
| Container parent = (Container) dest.getParent(); |
| if (!parent.equals(project)) { |
| info = parent.getResourceInfo(false, false); |
| parent.checkExists(getFlags(info), true); |
| } |
| } |
| if (isUnderLink() || dest.isUnderLink()) { |
| // Make sure location is not null. This can occur with linked resources relative to |
| // undefined path variables |
| URI sourceLocation = getLocationURI(); |
| if (sourceLocation == null) { |
| message = NLS.bind(Messages.localstore_locationUndefined, getFullPath()); |
| throw new ResourceException(IResourceStatus.FAILED_READ_LOCAL, getFullPath(), message, null); |
| } |
| URI destLocation = dest.getLocationURI(); |
| if (destLocation == null && (dest.isUnderVirtual() == false)) { |
| message = NLS.bind(Messages.localstore_locationUndefined, dest.getFullPath()); |
| throw new ResourceException(IResourceStatus.FAILED_READ_LOCAL, dest.getFullPath(), message, null); |
| } |
| // Make sure location of source is not a prefix of the location of the destination |
| // this can occur if the source and/or destination is a linked resource |
| if (getStore().isParentOf(dest.getStore())) { |
| message = NLS.bind(Messages.resources_copyDestNotSub, getFullPath()); |
| throw new ResourceException(IResourceStatus.INVALID_VALUE, getFullPath(), message, null); |
| } |
| } |
| |
| return status.isOK() ? Status.OK_STATUS : (IStatus) status; |
| } |
| |
| /** |
| * Checks that this resource does not exist. If the file system is not case |
| * sensitive, this method also checks for a case variant. |
| */ |
| protected void checkDoesNotExist() throws CoreException { |
| checkDoesNotExist(getFlags(getResourceInfo(false, false)), false); |
| } |
| |
| /** |
| * Checks that this resource does not exist. If the file system is not case |
| * sensitive, this method also checks for a case variant. |
| * |
| * @exception CoreException if this resource exists |
| */ |
| public void checkDoesNotExist(int flags, boolean checkType) throws CoreException { |
| // If this exact resource exists we are done. |
| if (exists(flags, checkType)) { |
| String message = NLS.bind(Messages.resources_mustNotExist, getFullPath()); |
| throw new ResourceException(checkType ? IResourceStatus.RESOURCE_EXISTS : IResourceStatus.PATH_OCCUPIED, getFullPath(), message, null); |
| } |
| if (Workspace.caseSensitive) |
| return; |
| // Now look for a matching case variant in the tree. |
| IResource variant = findExistingResourceVariant(getFullPath()); |
| if (variant == null) |
| return; |
| String msg = NLS.bind(Messages.resources_existsDifferentCase, variant.getFullPath()); |
| throw new ResourceException(IResourceStatus.CASE_VARIANT_EXISTS, variant.getFullPath(), msg, null); |
| } |
| |
| /** |
| * Checks that this resource exists. |
| * If checkType is true, the type of this resource and the one in the tree must match. |
| * |
| * @exception CoreException if this resource does not exist |
| */ |
| public void checkExists(int flags, boolean checkType) throws CoreException { |
| if (!exists(flags, checkType)) { |
| String message = NLS.bind(Messages.resources_mustExist, getFullPath()); |
| throw new ResourceException(IResourceStatus.RESOURCE_NOT_FOUND, getFullPath(), message, null); |
| } |
| } |
| |
| /** |
| * Checks that this resource is local to the given depth. |
| * |
| * @exception CoreException if this resource is not local |
| */ |
| public void checkLocal(int flags, int depth) throws CoreException { |
| if (!isLocal(flags, depth)) { |
| String message = NLS.bind(Messages.resources_mustBeLocal, getFullPath()); |
| throw new ResourceException(IResourceStatus.RESOURCE_NOT_LOCAL, getFullPath(), message, null); |
| } |
| } |
| |
| /** |
| * This method reports errors in two different ways. It can throw a |
| * CoreException or log a status. CoreExceptions are used according |
| * to the specification of the move method. Programming errors, that |
| * would usually be prevented by using an "Assert" code, are reported as |
| * an IStatus. |
| * We're doing this way because we have two different methods to move |
| * resources: IResource#move and IWorkspace#move. The first one gets |
| * the error and throws its message in an AssertionFailureException. The |
| * second one just throws a CoreException using the status returned |
| * by this method. |
| * |
| * @see IResource#move(IPath, int, IProgressMonitor) |
| */ |
| protected IStatus checkMoveRequirements(IPath destination, int destinationType, int updateFlags) throws CoreException { |
| String message = Messages.resources_moveNotMet; |
| MultiStatus status = new MultiStatus(ResourcesPlugin.PI_RESOURCES, IResourceStatus.INVALID_VALUE, message, null); |
| if (destination == null) { |
| message = Messages.resources_destNotNull; |
| return new ResourceStatus(IResourceStatus.INVALID_VALUE, getFullPath(), message); |
| } |
| destination = makePathAbsolute(destination); |
| if (getFullPath().isPrefixOf(destination)) { |
| message = NLS.bind(Messages.resources_moveDestNotSub, getFullPath()); |
| status.add(new ResourceStatus(IResourceStatus.INVALID_VALUE, getFullPath(), message)); |
| } |
| checkValidPath(destination, destinationType, false); |
| |
| ResourceInfo info; |
| checkAccessibleAndLocal(DEPTH_INFINITE); |
| |
| IPath destinationParent = destination.removeLastSegments(1); |
| checkValidGroupContainer(destinationParent, isLinked(), isVirtual()); |
| |
| Resource dest = workspace.newResource(destination, destinationType); |
| |
| // Check if we are only changing case. |
| IResource variant = Workspace.caseSensitive ? null : findExistingResourceVariant(destination); |
| if (variant == null || !this.equals(variant)) |
| dest.checkDoesNotExist(); |
| |
| // Ensure we aren't trying to move a file to a project. |
| if (getType() == IResource.FILE && dest.getType() == IResource.PROJECT) { |
| message = Messages.resources_fileToProj; |
| throw new ResourceException(new ResourceStatus(IResourceStatus.INVALID_VALUE, getFullPath(), message)); |
| } |
| |
| // We can't move into a closed project. |
| if (destinationType != IResource.PROJECT) { |
| Project project = (Project) dest.getProject(); |
| info = project.getResourceInfo(false, false); |
| project.checkAccessible(getFlags(info)); |
| Container parent = (Container) dest.getParent(); |
| if (!parent.equals(project)) { |
| info = parent.getResourceInfo(false, false); |
| parent.checkExists(getFlags(info), true); |
| } |
| } |
| if (isUnderLink() || dest.isUnderLink()) { |
| // Make sure location is not null. This can occur with linked resources relative to |
| // undefined path variables. |
| URI sourceLocation = getLocationURI(); |
| if (sourceLocation == null) { |
| message = NLS.bind(Messages.localstore_locationUndefined, getFullPath()); |
| throw new ResourceException(IResourceStatus.FAILED_READ_LOCAL, getFullPath(), message, null); |
| } |
| URI destLocation = dest.getLocationURI(); |
| if (destLocation == null && (dest.isUnderVirtual() == false)) { |
| message = NLS.bind(Messages.localstore_locationUndefined, dest.getFullPath()); |
| throw new ResourceException(IResourceStatus.FAILED_READ_LOCAL, dest.getFullPath(), message, null); |
| } |
| // Make sure location of source is not a prefix of the location of the destination |
| // this can occur if the source and/or destination is a linked resource. |
| if (getStore().isParentOf(dest.getStore())) { |
| message = NLS.bind(Messages.resources_moveDestNotSub, getFullPath()); |
| throw new ResourceException(IResourceStatus.INVALID_VALUE, getFullPath(), message, null); |
| } |
| } |
| |
| return status.isOK() ? Status.OK_STATUS : (IStatus) status; |
| } |
| |
| /** |
| * Checks that the supplied path is valid according to Workspace.validatePath(). |
| * |
| * @exception CoreException if the path is not valid |
| */ |
| public void checkValidPath(IPath toValidate, int type, boolean lastSegmentOnly) throws CoreException { |
| IStatus result = workspace.locationValidator.validatePath(toValidate, type, lastSegmentOnly); |
| if (!result.isOK()) |
| throw new ResourceException(result); |
| } |
| |
| /** |
| * Checks that the destination is a suitable one given that it could be a group. |
| * |
| * @exception CoreException if the path points to a group |
| */ |
| public void checkValidGroupContainer(IPath destination, boolean isLink, boolean isGroup) throws CoreException { |
| if (!isLink && !isGroup) { |
| String message = Messages.group_invalidParent; |
| ResourceInfo info = workspace.getResourceInfo(destination, false, false); |
| if (info != null && info.isSet(M_VIRTUAL)) |
| throw new ResourceException(new ResourceStatus(IResourceStatus.INVALID_VALUE, null, message)); |
| } |
| } |
| |
| /** |
| * Checks that the destination is a suitable one given that it could be a group. |
| * |
| * @exception CoreException if the path points to a group |
| */ |
| public void checkValidGroupContainer(Container destination, boolean isLink, boolean isGroup) throws CoreException { |
| if (!isLink && !isGroup) { |
| String message = Messages.group_invalidParent; |
| if (destination.isVirtual()) |
| throw new ResourceException(new ResourceStatus(IResourceStatus.INVALID_VALUE, null, message)); |
| } |
| } |
| |
| public IStatus getValidGroupContainer(IPath destination, boolean isLink, boolean isGroup) { |
| if (!isLink && !isGroup) { |
| String message = Messages.group_invalidParent; |
| ResourceInfo info = workspace.getResourceInfo(destination, false, false); |
| if (info.isSet(M_VIRTUAL)) |
| return new ResourceStatus(IResourceStatus.INVALID_VALUE, null, message); |
| } |
| return Status.OK_STATUS; |
| } |
| |
| @Override |
| public void clearHistory(IProgressMonitor monitor) { |
| getLocalManager().getHistoryStore().remove(getFullPath(), monitor); |
| } |
| |
| @Override |
| public boolean contains(ISchedulingRule rule) { |
| if (this == rule) |
| return true; |
| // Must allow notifications to nest in all resource rules. |
| if (rule.getClass().equals(WorkManager.NotifyRule.class)) |
| return true; |
| if (rule instanceof MultiRule) { |
| MultiRule multi = (MultiRule) rule; |
| ISchedulingRule[] children = multi.getChildren(); |
| for (int i = 0; i < children.length; i++) |
| if (!contains(children[i])) |
| return false; |
| return true; |
| } |
| if (!(rule instanceof IResource)) |
| return false; |
| IResource resource = (IResource) rule; |
| if (!workspace.equals(resource.getWorkspace())) |
| return false; |
| return path.isPrefixOf(resource.getFullPath()); |
| } |
| |
| /** |
| * @throws CoreException |
| */ |
| public void convertToPhantom() throws CoreException { |
| ResourceInfo info = getResourceInfo(false, true); |
| if (info == null || isPhantom(getFlags(info))) |
| return; |
| info.clearSessionProperties(); |
| info.set(M_PHANTOM); |
| getLocalManager().updateLocalSync(info, I_NULL_SYNC_INFO); |
| info.clearModificationStamp(); |
| // Should already be done by the #deleteResource call but left in |
| // just to be safe and for code clarity. |
| info.setMarkers(null); |
| } |
| |
| @Override |
| public void copy(IPath destination, boolean force, IProgressMonitor monitor) throws CoreException { |
| int updateFlags = force ? IResource.FORCE : IResource.NONE; |
| copy(destination, updateFlags, monitor); |
| } |
| |
| @Override |
| public void copy(IPath destination, int updateFlags, IProgressMonitor monitor) throws CoreException { |
| String message = NLS.bind(Messages.resources_copying, getFullPath()); |
| SubMonitor progress = SubMonitor.convert(monitor, message, 100).checkCanceled(); |
| destination = makePathAbsolute(destination); |
| checkValidPath(destination, getType(), false); |
| Resource destResource = workspace.newResource(destination, getType()); |
| final ISchedulingRule rule = workspace.getRuleFactory().copyRule(this, destResource); |
| try { |
| workspace.prepareOperation(rule, progress.split(1)); |
| // The following assert method throws CoreExceptions as stated in the IResource.copy API |
| // and assert for programming errors. See checkCopyRequirements for more information. |
| assertCopyRequirements(destination, getType(), updateFlags); |
| workspace.beginOperation(true); |
| getLocalManager().copy(this, destResource, updateFlags, progress.split(98)); |
| } catch (OperationCanceledException e) { |
| workspace.getWorkManager().operationCanceled(); |
| throw e; |
| } finally { |
| workspace.endOperation(rule, true); |
| } |
| } |
| |
| @Override |
| public void copy(IProjectDescription destDesc, boolean force, IProgressMonitor monitor) throws CoreException { |
| int updateFlags = force ? IResource.FORCE : IResource.NONE; |
| copy(destDesc, updateFlags, monitor); |
| } |
| |
| /** |
| * Used when a folder is to be copied to a project. |
| * @see IResource#copy(IProjectDescription, int, IProgressMonitor) |
| */ |
| @Override |
| public void copy(IProjectDescription destDesc, int updateFlags, IProgressMonitor monitor) throws CoreException { |
| Assert.isNotNull(destDesc); |
| String message = NLS.bind(Messages.resources_copying, getFullPath()); |
| SubMonitor progress = SubMonitor.convert(monitor, message, 100).checkCanceled(); |
| try { |
| workspace.prepareOperation(workspace.getRoot(), progress.split(1)); |
| // The following assert method throws CoreExceptions as stated in the IResource.copy API |
| // and assert for programming errors. See checkCopyRequirements for more information. |
| IPath destPath = new Path(destDesc.getName()).makeAbsolute(); |
| assertCopyRequirements(destPath, getType(), updateFlags); |
| Project destProject = (Project) workspace.getRoot().getProject(destPath.lastSegment()); |
| workspace.beginOperation(true); |
| |
| // Create and open the new project. |
| destProject.create(destDesc, progress.split(5)); |
| destProject.open(progress.split(5)); |
| |
| // Copy the children. |
| IResource[] children = ((IContainer) this).members(IContainer.INCLUDE_TEAM_PRIVATE_MEMBERS | IContainer.INCLUDE_HIDDEN); |
| SubMonitor loopProgress = SubMonitor.convert(progress.split(70), children.length); |
| for (int i = 0; i < children.length; i++) { |
| Resource child = (Resource) children[i]; |
| child.copy(destPath.append(child.getName()), updateFlags, loopProgress.split(1)); |
| } |
| |
| // Copy over the properties. |
| getPropertyManager().copy(this, destProject, DEPTH_ZERO); |
| progress.split(18); |
| } catch (OperationCanceledException e) { |
| workspace.getWorkManager().operationCanceled(); |
| throw e; |
| } finally { |
| workspace.endOperation(workspace.getRoot(), true); |
| } |
| } |
| |
| /** |
| * Count the number of resources in the tree from this container to the |
| * specified depth. Include this resource. Include phantoms if |
| * the phantom boolean is true. |
| */ |
| public int countResources(int depth, boolean phantom) { |
| return workspace.countResources(path, depth, phantom); |
| } |
| |
| /** |
| * @see IFolder#createLink(IPath, int, IProgressMonitor) |
| * @see IFile#createLink(IPath, int, IProgressMonitor) |
| */ |
| public void createLink(IPath localLocation, int updateFlags, IProgressMonitor monitor) throws CoreException { |
| Assert.isNotNull(localLocation); |
| createLink(URIUtil.toURI(localLocation), updateFlags, monitor); |
| } |
| |
| /** |
| * @see IFolder#createLink(URI, int, IProgressMonitor) |
| * @see IFile#createLink(URI, int, IProgressMonitor) |
| */ |
| public void createLink(URI localLocation, int updateFlags, IProgressMonitor monitor) throws CoreException { |
| Assert.isNotNull(localLocation); |
| IResource existing = null; |
| if ((updateFlags & REPLACE) != 0) { |
| existing = workspace.getRoot().findMember(getFullPath()); |
| if (existing != null && existing.isLinked()) { |
| setLinkLocation(localLocation, updateFlags, monitor); |
| return; |
| } |
| } |
| |
| String message = NLS.bind(Messages.links_creating, getFullPath()); |
| SubMonitor progress = SubMonitor.convert(monitor, message, 100).checkCanceled(); |
| checkValidPath(path, FOLDER, true); |
| final ISchedulingRule rule = workspace.getRuleFactory().createRule(this); |
| try { |
| workspace.prepareOperation(rule, progress.split(1)); |
| IFileInfo fileInfo = assertLinkRequirements(localLocation, updateFlags); |
| workspace.broadcastEvent(LifecycleEvent.newEvent(LifecycleEvent.PRE_LINK_CREATE, this)); |
| workspace.beginOperation(true); |
| // Replace existing resource, if applicable. |
| if ((updateFlags & REPLACE) != 0 && existing != null) { |
| workspace.deleteResource(existing); |
| } |
| ResourceInfo info = workspace.createResource(this, false); |
| if ((updateFlags & IResource.HIDDEN) != 0) |
| info.set(M_HIDDEN); |
| info.set(M_LINK); |
| LinkDescription linkDescription = new LinkDescription(this, localLocation); |
| if (linkDescription.isGroup()) |
| info.set(M_VIRTUAL); |
| getLocalManager().link(this, localLocation, fileInfo); |
| progress.split(5); |
| // Save the location in the project description. |
| Project project = (Project) getProject(); |
| boolean changed = project.internalGetDescription().setLinkLocation(getProjectRelativePath(), linkDescription); |
| if (changed) { |
| try { |
| project.writeDescription(IResource.NONE); |
| } catch (CoreException e) { |
| // A problem happened updating the description, so delete the resource from the workspace. |
| workspace.deleteResource(this); |
| throw e; // Rethrow. |
| } |
| } |
| progress.split(4); |
| |
| // Refresh to discover any new resources below this linked location. |
| if (getType() != IResource.FILE) { |
| // Refresh either in background or foreground. |
| if ((updateFlags & IResource.BACKGROUND_REFRESH) != 0) { |
| workspace.refreshManager.refresh(this); |
| progress.split(90); |
| } else { |
| refreshLocal(DEPTH_INFINITE, progress.split(90)); |
| } |
| } else { |
| progress.split(90); |
| } |
| } catch (OperationCanceledException e) { |
| workspace.getWorkManager().operationCanceled(); |
| throw e; |
| } finally { |
| workspace.endOperation(rule, true); |
| } |
| } |
| |
| @Override |
| public IMarker createMarker(String type) throws CoreException { |
| Assert.isNotNull(type); |
| final ISchedulingRule rule = workspace.getRuleFactory().markerRule(this); |
| try { |
| workspace.prepareOperation(rule, null); |
| checkAccessible(getFlags(getResourceInfo(false, false))); |
| workspace.beginOperation(true); |
| MarkerInfo info = new MarkerInfo(); |
| info.setType(type); |
| info.setCreationTime(System.currentTimeMillis()); |
| workspace.getMarkerManager().add(this, info); |
| return new Marker(this, info.getId()); |
| } finally { |
| workspace.endOperation(rule, false); |
| } |
| } |
| |
| @Override |
| public IResourceProxy createProxy() { |
| ResourceProxy result = new ResourceProxy(); |
| result.info = getResourceInfo(false, false); |
| result.requestor = this; |
| result.resource = this; |
| return result; |
| } |
| |
| /** |
| * @see IProject#delete(boolean, boolean, IProgressMonitor) |
| * @see IWorkspaceRoot#delete(boolean, boolean, IProgressMonitor) |
| * N.B. This is not an IResource method! |
| */ |
| public void delete(boolean force, boolean keepHistory, IProgressMonitor monitor) throws CoreException { |
| int updateFlags = force ? IResource.FORCE : IResource.NONE; |
| updateFlags |= keepHistory ? IResource.KEEP_HISTORY : IResource.NONE; |
| delete(updateFlags, monitor); |
| } |
| |
| @Override |
| public void delete(boolean force, IProgressMonitor monitor) throws CoreException { |
| delete(force ? IResource.FORCE : IResource.NONE, monitor); |
| } |
| |
| @Override |
| public void delete(int updateFlags, IProgressMonitor monitor) throws CoreException { |
| String message = NLS.bind(Messages.resources_deleting, getFullPath()); |
| SubMonitor progress = SubMonitor.convert(monitor, 100).checkCanceled(); |
| progress.subTask(message); |
| final ISchedulingRule rule = workspace.getRuleFactory().deleteRule(this); |
| try { |
| workspace.prepareOperation(rule, progress.split(1)); |
| // If there is no resource then there is nothing to delete so just return. |
| if (!exists()) |
| return; |
| workspace.beginOperation(true); |
| broadcastPreDeleteEvent(); |
| |
| // When a project is being deleted, flush the build order in case there is a problem. |
| if (this.getType() == IResource.PROJECT) |
| workspace.flushBuildOrder(); |
| |
| final IFileStore originalStore = getStore(); |
| boolean wasLinked = isLinked(); |
| message = Messages.resources_deleteProblem; |
| MultiStatus status = new MultiStatus(ResourcesPlugin.PI_RESOURCES, IResourceStatus.FAILED_DELETE_LOCAL, message, null); |
| WorkManager workManager = workspace.getWorkManager(); |
| ResourceTree tree = new ResourceTree(workspace.getFileSystemManager(), workManager.getLock(), status, updateFlags); |
| int depth = 0; |
| try { |
| depth = workManager.beginUnprotected(); |
| unprotectedDelete(tree, updateFlags, progress.split(50)); |
| } finally { |
| workManager.endUnprotected(depth); |
| } |
| if (getType() == ROOT) { |
| // Need to clear out the root info. |
| workspace.getMarkerManager().removeMarkers(this, IResource.DEPTH_ZERO); |
| getPropertyManager().deleteProperties(this, IResource.DEPTH_ZERO); |
| getResourceInfo(false, false).clearSessionProperties(); |
| } |
| // Invalidate the tree for further use by clients. |
| tree.makeInvalid(); |
| if (!tree.getStatus().isOK()) |
| throw new ResourceException(tree.getStatus()); |
| // Update any aliases of this resource. |
| // Note that deletion of a linked resource cannot affect other resources. |
| if (!wasLinked) |
| workspace.getAliasManager().updateAliases(this, originalStore, IResource.DEPTH_INFINITE, progress.split(48)); |
| if (getType() == PROJECT) { |
| // Make sure the rule factory is cleared on project deletion. |
| ((Rules) workspace.getRuleFactory()).setRuleFactory((IProject) this, null); |
| // Make sure project deletion is remembered. |
| workspace.getSaveManager().requestSnapshot(); |
| } |
| } catch (OperationCanceledException e) { |
| workspace.getWorkManager().operationCanceled(); |
| throw e; |
| } finally { |
| workspace.endOperation(rule, true); |
| } |
| } |
| |
| @Override |
| public void deleteMarkers(String type, boolean includeSubtypes, int depth) throws CoreException { |
| final ISchedulingRule rule = workspace.getRuleFactory().markerRule(this); |
| try { |
| workspace.prepareOperation(rule, null); |
| ResourceInfo info = getResourceInfo(false, false); |
| checkAccessible(getFlags(info)); |
| |
| workspace.beginOperation(true); |
| workspace.getMarkerManager().removeMarkers(this, type, includeSubtypes, depth); |
| } finally { |
| workspace.endOperation(rule, false); |
| } |
| } |
| |
| /** |
| * This method should be called to delete a resource from the tree because it will also |
| * delete its properties and markers. If a status object is provided, minor exceptions are |
| * added, otherwise they are thrown. If major exceptions occur, they are always thrown. |
| */ |
| public void deleteResource(boolean convertToPhantom, MultiStatus status) throws CoreException { |
| // Remove markers on this resource and its descendants. |
| if (exists()) |
| getMarkerManager().removeMarkers(this, IResource.DEPTH_INFINITE); |
| // If this is a linked resource or contains linked resources, |
| // remove their entries from the project description. |
| List<Resource> links = findLinks(); |
| // Pre-delete notification to internal infrastructure |
| if (links != null) |
| for (Iterator<Resource> it = links.iterator(); it.hasNext();) |
| workspace.broadcastEvent(LifecycleEvent.newEvent(LifecycleEvent.PRE_LINK_DELETE, it.next())); |
| |
| // Check if we deleted a preferences file. |
| ProjectPreferences.deleted(this); |
| |
| // Remove all deleted linked resources from the project description. |
| if (getType() != IResource.PROJECT && links != null) { |
| Project project = (Project) getProject(); |
| ProjectDescription description = project.internalGetDescription(); |
| if (description != null) { |
| boolean wasChanged = false; |
| for (Iterator<Resource> it = links.iterator(); it.hasNext();) |
| wasChanged |= description.setLinkLocation(it.next().getProjectRelativePath(), null); |
| if (wasChanged) { |
| project.internalSetDescription(description, true); |
| try { |
| project.writeDescription(IResource.FORCE); |
| } catch (CoreException e) { |
| // A problem happened updating the description, update the description in memory. |
| project.updateDescription(); |
| throw e; // Rethrow. |
| } |
| } |
| } |
| } |
| |
| // If we are synchronizing, do not delete the resource. Convert it |
| // into a phantom. Actual deletion will happen when we refresh or push. |
| if (convertToPhantom && getType() != PROJECT && synchronizing(getResourceInfo(true, false))) { |
| convertToPhantom(); |
| } else { |
| workspace.deleteResource(this); |
| } |
| |
| List<Resource> filters = findFilters(); |
| if ((filters != null) && (filters.size() > 0)) { |
| // Delete resource filters. |
| Project project = (Project) getProject(); |
| ProjectDescription description = project.internalGetDescription(); |
| if (description != null) { |
| for (Iterator<Resource> it = filters.iterator(); it.hasNext();) |
| description.setFilters(it.next().getProjectRelativePath(), null); |
| project.internalSetDescription(description, true); |
| project.writeDescription(IResource.FORCE); |
| } |
| } |
| |
| // Delete properties after the resource is deleted from the tree. See bug 84584. |
| CoreException err = null; |
| try { |
| getPropertyManager().deleteResource(this); |
| } catch (CoreException e) { |
| if (status != null) { |
| status.add(e.getStatus()); |
| } else { |
| err = e; |
| } |
| } |
| if (err != null) |
| throw err; |
| } |
| |
| /** |
| * Returns a list of all linked resources at or below this resource, or null if there are no links. |
| */ |
| private List<Resource> findLinks() { |
| Project project = (Project) getProject(); |
| ProjectDescription description = project.internalGetDescription(); |
| HashMap<IPath, LinkDescription> linkMap = description.getLinks(); |
| if (linkMap == null) |
| return null; |
| List<Resource> links = null; |
| IPath myPath = getProjectRelativePath(); |
| for (Iterator<LinkDescription> it = linkMap.values().iterator(); it.hasNext();) { |
| LinkDescription link = it.next(); |
| IPath linkPath = link.getProjectRelativePath(); |
| if (myPath.isPrefixOf(linkPath)) { |
| if (links == null) |
| links = new ArrayList<>(); |
| links.add(workspace.newResource(project.getFullPath().append(linkPath), link.getType())); |
| } |
| } |
| return links; |
| } |
| |
| /** |
| * Returns a list of all filtered resources at or below this resource, or null if there are no links. |
| */ |
| private List<Resource> findFilters() { |
| Project project = (Project) getProject(); |
| ProjectDescription description = project.internalGetDescription(); |
| List<Resource> filters = null; |
| if (description != null) { |
| HashMap<IPath, LinkedList<FilterDescription>> filterMap = description.getFilters(); |
| if (filterMap != null) { |
| IPath myPath = getProjectRelativePath(); |
| for (Iterator<IPath> it = filterMap.keySet().iterator(); it.hasNext();) { |
| IPath filterPath = it.next(); |
| if (myPath.isPrefixOf(filterPath)) { |
| if (filters == null) |
| filters = new ArrayList<>(); |
| filters.add(workspace.newResource(project.getFullPath().append(filterPath), IResource.FOLDER)); |
| } |
| } |
| } |
| } |
| return filters; |
| } |
| |
| @Override |
| public boolean equals(Object target) { |
| if (this == target) |
| return true; |
| if (!(target instanceof Resource)) |
| return false; |
| Resource resource = (Resource) target; |
| return getType() == resource.getType() && path.equals(resource.path) && workspace.equals(resource.workspace); |
| } |
| |
| @Override |
| public boolean exists() { |
| ResourceInfo info = getResourceInfo(false, false); |
| return exists(getFlags(info), true); |
| } |
| |
| public boolean exists(int flags, boolean checkType) { |
| return flags != NULL_FLAG && !(checkType && ResourceInfo.getType(flags) != getType()); |
| } |
| |
| /** |
| * Helper method for case insensitive file systems. Returns |
| * an existing resource whose path differs only in case from |
| * the given path, or null if no such resource exists. |
| */ |
| public IResource findExistingResourceVariant(IPath target) { |
| if (!workspace.tree.includesIgnoreCase(target)) |
| return null; |
| // Ignore phantoms. |
| ResourceInfo info = (ResourceInfo) workspace.tree.getElementDataIgnoreCase(target); |
| if (info != null && info.isSet(M_PHANTOM)) |
| return null; |
| // Resort to slow lookup to find exact case variant. |
| IPath result = Path.ROOT; |
| int segmentCount = target.segmentCount(); |
| for (int i = 0; i < segmentCount; i++) { |
| String[] childNames = workspace.tree.getNamesOfChildren(result); |
| String name = findVariant(target.segment(i), childNames); |
| if (name == null) |
| return null; |
| result = result.append(name); |
| } |
| return workspace.getRoot().findMember(result); |
| } |
| |
| @Override |
| public IMarker findMarker(long id) { |
| return workspace.getMarkerManager().findMarker(this, id); |
| } |
| |
| @Override |
| public IMarker[] findMarkers(String type, boolean includeSubtypes, int depth) throws CoreException { |
| ResourceInfo info = getResourceInfo(false, false); |
| checkAccessible(getFlags(info)); |
| // It might happen that from this point the resource is not accessible anymore. |
| // But markers have the #exists method that callers can use to check if it is still valid. |
| return workspace.getMarkerManager().findMarkers(this, type, includeSubtypes, depth); |
| } |
| |
| @Override |
| public int findMaxProblemSeverity(String type, boolean includeSubtypes, int depth) throws CoreException { |
| ResourceInfo info = getResourceInfo(false, false); |
| checkAccessible(getFlags(info)); |
| // It might happen that from this point the resource is not accessible anymore. |
| // But markers have the #exists method that callers can use to check if it is still valid. |
| return workspace.getMarkerManager().findMaxProblemSeverity(this, type, includeSubtypes, depth); |
| } |
| |
| /** |
| * Searches for a variant of the given target in the list, |
| * that differs only in case. Returns the variant from |
| * the list if one is found, otherwise returns null. |
| */ |
| private String findVariant(String target, String[] list) { |
| for (int i = 0; i < list.length; i++) { |
| if (target.toUpperCase().equals(list[i].toUpperCase())) |
| return list[i]; |
| } |
| return null; |
| } |
| |
| protected void fixupAfterMoveSource() throws CoreException { |
| ResourceInfo info = getResourceInfo(true, true); |
| // If a linked resource is moved, we need to remove the location info from the ".project" file. |
| if (isLinked() || isVirtual()) { |
| Project project = (Project) getProject(); |
| if (project.internalGetDescription().setLinkLocation(getProjectRelativePath(), null)) |
| project.writeDescription(IResource.NONE); |
| } |
| |
| List<Resource> filters = findFilters(); |
| if ((filters != null) && (filters.size() > 0)) { |
| // Delete resource filters. |
| Project project = (Project) getProject(); |
| ProjectDescription description = project.internalGetDescription(); |
| for (Iterator<Resource> it = filters.iterator(); it.hasNext();) |
| description.setFilters(it.next().getProjectRelativePath(), null); |
| project.writeDescription(IResource.NONE); |
| } |
| |
| // Check if we deleted a preferences file. |
| ProjectPreferences.deleted(this); |
| |
| if (!synchronizing(info)) { |
| workspace.deleteResource(this); |
| return; |
| } |
| info.clearSessionProperties(); |
| info.clear(M_LOCAL_EXISTS); |
| info.setLocalSyncInfo(I_NULL_SYNC_INFO); |
| info.set(M_PHANTOM); |
| info.clearModificationStamp(); |
| info.setMarkers(null); |
| } |
| |
| @Override |
| public String getFileExtension() { |
| String name = getName(); |
| int index = name.lastIndexOf('.'); |
| if (index == -1) |
| return null; |
| if (index == (name.length() - 1)) |
| return ""; //$NON-NLS-1$ |
| return name.substring(index + 1); |
| } |
| |
| public int getFlags(ResourceInfo info) { |
| return (info == null) ? NULL_FLAG : info.getFlags(); |
| } |
| |
| @Override |
| public IPath getFullPath() { |
| return path; |
| } |
| |
| public FileSystemResourceManager getLocalManager() { |
| return workspace.getFileSystemManager(); |
| } |
| |
| @Override |
| public long getLocalTimeStamp() { |
| ResourceInfo info = getResourceInfo(false, false); |
| return (info == null || isVirtual()) ? IResource.NULL_STAMP : info.getLocalSyncInfo(); |
| } |
| |
| @Override |
| public IPath getLocation() { |
| IProject project = getProject(); |
| if (project != null && !project.exists()) |
| return null; |
| return getLocalManager().locationFor(this, false); |
| } |
| |
| @Override |
| public URI getLocationURI() { |
| IProject project = getProject(); |
| if (project != null && !project.exists()) |
| return null; |
| return getLocalManager().locationURIFor(this, false); |
| } |
| |
| @Override |
| public IMarker getMarker(long id) { |
| return new Marker(this, id); |
| } |
| |
| protected MarkerManager getMarkerManager() { |
| return workspace.getMarkerManager(); |
| } |
| |
| @Override |
| public long getModificationStamp() { |
| ResourceInfo info = getResourceInfo(false, false); |
| return info == null ? IResource.NULL_STAMP : info.getModificationStamp(); |
| } |
| |
| @Override |
| public String getName() { |
| return path.lastSegment(); |
| } |
| |
| @Override |
| public IContainer getParent() { |
| int segments = path.segmentCount(); |
| // Zero and one segments handled by subclasses. |
| if (segments < 2) |
| Assert.isLegal(false, path.toString()); |
| if (segments == 2) |
| return workspace.getRoot().getProject(path.segment(0)); |
| return (IFolder) workspace.newResource(path.removeLastSegments(1), IResource.FOLDER); |
| } |
| |
| @Override |
| public String getPersistentProperty(QualifiedName key) throws CoreException { |
| checkAccessibleAndLocal(DEPTH_ZERO); |
| return getPropertyManager().getProperty(this, key); |
| } |
| |
| @Override |
| public Map<QualifiedName, String> getPersistentProperties() throws CoreException { |
| checkAccessibleAndLocal(DEPTH_ZERO); |
| return getPropertyManager().getProperties(this); |
| } |
| |
| @Override |
| public IProject getProject() { |
| return workspace.getRoot().getProject(path.segment(0)); |
| } |
| |
| @Override |
| public IPath getProjectRelativePath() { |
| return getFullPath().removeFirstSegments(ICoreConstants.PROJECT_SEGMENT_LENGTH); |
| } |
| |
| public IPropertyManager getPropertyManager() { |
| return workspace.getPropertyManager(); |
| } |
| |
| @Override |
| public IPath getRawLocation() { |
| if (isLinked()) |
| return FileUtil.toPath(((Project) getProject()).internalGetDescription().getLinkLocationURI(getProjectRelativePath())); |
| return getLocation(); |
| } |
| |
| @Override |
| public URI getRawLocationURI() { |
| if (isLinked()) |
| return ((Project) getProject()).internalGetDescription().getLinkLocationURI(getProjectRelativePath()); |
| return getLocationURI(); |
| } |
| |
| @Override |
| public ResourceAttributes getResourceAttributes() { |
| if (!isAccessible() || isVirtual()) |
| return null; |
| return getLocalManager().attributes(this); |
| } |
| |
| /** |
| * Returns the resource info. Returns null if the resource doesn't exist. |
| * If the phantom flag is true, phantom resources are considered. |
| * If the mutable flag is true, a mutable info is returned. |
| */ |
| public ResourceInfo getResourceInfo(boolean phantom, boolean mutable) { |
| return workspace.getResourceInfo(getFullPath(), phantom, mutable); |
| } |
| |
| @Override |
| public Object getSessionProperty(QualifiedName key) throws CoreException { |
| ResourceInfo info = checkAccessibleAndLocal(DEPTH_ZERO); |
| return info.getSessionProperty(key); |
| } |
| |
| @Override |
| public Map<QualifiedName, Object> getSessionProperties() throws CoreException { |
| ResourceInfo info = checkAccessibleAndLocal(DEPTH_ZERO); |
| return info.getSessionProperties(); |
| } |
| |
| public IFileStore getStore() { |
| return getLocalManager().getStore(this); |
| } |
| |
| @Override |
| public abstract int getType(); |
| |
| public String getTypeString() { |
| switch (getType()) { |
| case FILE : |
| return "L"; //$NON-NLS-1$ |
| case FOLDER : |
| return "F"; //$NON-NLS-1$ |
| case PROJECT : |
| return "P"; //$NON-NLS-1$ |
| case ROOT : |
| return "R"; //$NON-NLS-1$ |
| } |
| return ""; //$NON-NLS-1$ |
| } |
| |
| @Override |
| public IWorkspace getWorkspace() { |
| return workspace; |
| } |
| |
| @Override |
| public int hashCode() { |
| // The container may be null if the identified resource |
| // does not exist so don't bother with it in the hash |
| return getFullPath().hashCode(); |
| } |
| |
| /** |
| * Sets the M_LOCAL_EXISTS flag. Is internal so we don't have |
| * to begin an operation. |
| */ |
| protected void internalSetLocal(boolean flag, int depth) throws CoreException { |
| ResourceInfo info = getResourceInfo(true, true); |
| // Only make the change if it's not already in desired state. |
| if (info.isSet(M_LOCAL_EXISTS) != flag) { |
| if (flag && !isPhantom(getFlags(info))) { |
| info.set(M_LOCAL_EXISTS); |
| workspace.updateModificationStamp(info); |
| } else { |
| info.clear(M_LOCAL_EXISTS); |
| info.clearModificationStamp(); |
| } |
| } |
| if (getType() == IResource.FILE || depth == IResource.DEPTH_ZERO) |
| return; |
| if (depth == IResource.DEPTH_ONE) |
| depth = IResource.DEPTH_ZERO; |
| IResource[] children = ((IContainer) this).members(); |
| for (int i = 0; i < children.length; i++) |
| ((Resource) children[i]).internalSetLocal(flag, depth); |
| } |
| |
| @Override |
| public boolean isAccessible() { |
| return exists(); |
| } |
| |
| @Override |
| public boolean isConflicting(ISchedulingRule rule) { |
| if (this == rule) |
| return true; |
| // Must not schedule at same time as notification. |
| if (rule.getClass().equals(WorkManager.NotifyRule.class)) |
| return true; |
| if (rule instanceof MultiRule) { |
| MultiRule multi = (MultiRule) rule; |
| ISchedulingRule[] children = multi.getChildren(); |
| for (int i = 0; i < children.length; i++) |
| if (isConflicting(children[i])) |
| return true; |
| return false; |
| } |
| if (!(rule instanceof IResource)) |
| return false; |
| IResource resource = (IResource) rule; |
| if (!workspace.equals(resource.getWorkspace())) |
| return false; |
| IPath otherPath = resource.getFullPath(); |
| return path.isPrefixOf(otherPath) || otherPath.isPrefixOf(path); |
| } |
| |
| @Override |
| public boolean isDerived() { |
| return isDerived(IResource.NONE); |
| } |
| |
| @Override |
| public boolean isDerived(int options) { |
| ResourceInfo info = getResourceInfo(false, false); |
| int flags = getFlags(info); |
| if (flags != NULL_FLAG && ResourceInfo.isSet(flags, ICoreConstants.M_DERIVED)) |
| return true; |
| // Check ancestors if the appropriate option is set. |
| if ((options & CHECK_ANCESTORS) != 0) |
| return getParent().isDerived(options); |
| return false; |
| } |
| |
| @Override |
| public boolean isHidden() { |
| ResourceInfo info = getResourceInfo(false, false); |
| int flags = getFlags(info); |
| return flags != NULL_FLAG && ResourceInfo.isSet(flags, ICoreConstants.M_HIDDEN); |
| } |
| |
| @Override |
| public boolean isHidden(int options) { |
| ResourceInfo info = getResourceInfo(false, false); |
| int flags = getFlags(info); |
| if (flags != NULL_FLAG && ResourceInfo.isSet(flags, ICoreConstants.M_HIDDEN)) |
| return true; |
| // Check ancestors if the appropriate option is set. |
| if ((options & CHECK_ANCESTORS) != 0) |
| return getParent().isHidden(options); |
| return false; |
| } |
| |
| @Override |
| public boolean isLinked() { |
| return isLinked(NONE); |
| } |
| |
| @Override |
| public boolean isLinked(int options) { |
| if ((options & CHECK_ANCESTORS) != 0) { |
| IProject project = getProject(); |
| if (project == null) |
| return false; |
| ProjectDescription desc = ((Project) project).internalGetDescription(); |
| if (desc == null) |
| return false; |
| HashMap<IPath, LinkDescription> links = desc.getLinks(); |
| if (links == null) |
| return false; |
| IPath myPath = getProjectRelativePath(); |
| for (Iterator<LinkDescription> it = links.values().iterator(); it.hasNext();) { |
| if (it.next().getProjectRelativePath().isPrefixOf(myPath)) |
| return true; |
| } |
| return false; |
| } |
| // The no ancestor checking case. |
| ResourceInfo info = getResourceInfo(false, false); |
| return info != null && info.isSet(M_LINK); |
| } |
| |
| @Override |
| public boolean isVirtual() { |
| ResourceInfo info = getResourceInfo(false, false); |
| return info != null && info.isSet(M_VIRTUAL); |
| } |
| |
| /** |
| * Checks whether the current resource has a parent that is virtual. |
| */ |
| public boolean isUnderVirtual() { |
| IContainer parent = getParent(); |
| while (parent != null) { |
| if (parent.isVirtual()) |
| return true; |
| parent = parent.getParent(); |
| } |
| return false; |
| } |
| |
| @Override |
| @Deprecated |
| public boolean isLocal(int depth) { |
| ResourceInfo info = getResourceInfo(false, false); |
| return isLocal(getFlags(info), depth); |
| } |
| |
| /** |
| * Note the depth parameter is intentionally ignored because |
| * this method is over-ridden by {@link Container#isLocal(int)}. |
| * @deprecated |
| */ |
| @Deprecated |
| public boolean isLocal(int flags, int depth) { |
| return flags != NULL_FLAG && ResourceInfo.isSet(flags, M_LOCAL_EXISTS); |
| } |
| |
| /** |
| * Returns whether a resource should be included in a traversal |
| * based on the provided member flags. |
| * |
| * @param flags The resource info flags |
| * @param memberFlags The member flag mask |
| * @return Whether the resource is included |
| */ |
| protected boolean isMember(int flags, int memberFlags) { |
| int excludeMask = 0; |
| if ((memberFlags & IContainer.INCLUDE_PHANTOMS) == 0) |
| excludeMask |= M_PHANTOM; |
| if ((memberFlags & IContainer.INCLUDE_HIDDEN) == 0) |
| excludeMask |= M_HIDDEN; |
| if ((memberFlags & IContainer.INCLUDE_TEAM_PRIVATE_MEMBERS) == 0) |
| excludeMask |= M_TEAM_PRIVATE_MEMBER; |
| if ((memberFlags & IContainer.EXCLUDE_DERIVED) != 0) |
| excludeMask |= M_DERIVED; |
| // The resource is a matching member if it matches none of the exclude flags. |
| return flags != NULL_FLAG && (flags & excludeMask) == 0; |
| } |
| |
| @Override |
| public boolean isPhantom() { |
| ResourceInfo info = getResourceInfo(true, false); |
| return isPhantom(getFlags(info)); |
| } |
| |
| public boolean isPhantom(int flags) { |
| return flags != NULL_FLAG && ResourceInfo.isSet(flags, M_PHANTOM); |
| } |
| |
| @Deprecated |
| @Override |
| public boolean isReadOnly() { |
| final ResourceAttributes attributes = getResourceAttributes(); |
| return attributes != null && attributes.isReadOnly(); |
| } |
| |
| @Override |
| public boolean isSynchronized(int depth) { |
| return getLocalManager().isSynchronized(this, depth); |
| } |
| |
| @Override |
| public boolean isTeamPrivateMember() { |
| ResourceInfo info = getResourceInfo(false, false); |
| int flags = getFlags(info); |
| return flags != NULL_FLAG && ResourceInfo.isSet(flags, ICoreConstants.M_TEAM_PRIVATE_MEMBER); |
| } |
| |
| @Override |
| public boolean isTeamPrivateMember(int options) { |
| ResourceInfo info = getResourceInfo(false, false); |
| int flags = getFlags(info); |
| if (flags != NULL_FLAG && ResourceInfo.isSet(flags, ICoreConstants.M_TEAM_PRIVATE_MEMBER)) |
| return true; |
| // Check ancestors if the appropriate option is set. |
| if ((options & CHECK_ANCESTORS) != 0) |
| return getParent().isTeamPrivateMember(options); |
| return false; |
| } |
| |
| /** |
| * Returns true if this resource is a linked resource, or a child of a linked |
| * resource, and false otherwise. |
| */ |
| public boolean isUnderLink() { |
| int depth = path.segmentCount(); |
| if (depth < 2) |
| return false; |
| if (depth == 2) |
| return isLinked(); |
| // Check if parent at depth two is a link. |
| IPath linkParent = path.removeLastSegments(depth - 2); |
| return workspace.getResourceInfo(linkParent, false, false).isSet(ICoreConstants.M_LINK); |
| } |
| |
| protected IPath makePathAbsolute(IPath target) { |
| if (target.isAbsolute()) |
| return target; |
| return getParent().getFullPath().append(target); |
| } |
| |
| /** |
| * @see IFile#move(IPath, boolean, boolean, IProgressMonitor) |
| * @see IFolder#move(IPath, boolean, boolean, IProgressMonitor) |
| */ |
| public void move(IPath destination, boolean force, boolean keepHistory, IProgressMonitor monitor) throws CoreException { |
| int updateFlags = force ? IResource.FORCE : IResource.NONE; |
| updateFlags |= keepHistory ? IResource.KEEP_HISTORY : IResource.NONE; |
| move(destination, updateFlags, monitor); |
| } |
| |
| @Override |
| public void move(IPath destination, boolean force, IProgressMonitor monitor) throws CoreException { |
| move(destination, force ? IResource.FORCE : IResource.NONE, monitor); |
| } |
| |
| @Override |
| public void move(IPath destination, int updateFlags, IProgressMonitor monitor) throws CoreException { |
| String message = NLS.bind(Messages.resources_moving, getFullPath()); |
| SubMonitor progress = SubMonitor.convert(monitor, message, 100).checkCanceled(); |
| destination = makePathAbsolute(destination); |
| checkValidPath(destination, getType(), false); |
| Resource destResource = workspace.newResource(destination, getType()); |
| final ISchedulingRule rule = workspace.getRuleFactory().moveRule(this, destResource); |
| try { |
| workspace.prepareOperation(rule, progress.split(1)); |
| // The following assert method throws CoreExceptions as stated in the IResource.move API |
| // and assert for programming errors. See checkMoveRequirements for more information. |
| assertMoveRequirements(destination, getType(), updateFlags); |
| workspace.beginOperation(true); |
| broadcastPreMoveEvent(destResource, updateFlags); |
| IFileStore originalStore = getStore(); |
| message = Messages.resources_moveProblem; |
| MultiStatus status = new MultiStatus(ResourcesPlugin.PI_RESOURCES, IStatus.ERROR, message, null); |
| WorkManager workManager = workspace.getWorkManager(); |
| ResourceTree tree = new ResourceTree(workspace.getFileSystemManager(), workManager.getLock(), status, updateFlags); |
| boolean success = false; |
| int depth = 0; |
| try { |
| depth = workManager.beginUnprotected(); |
| success = unprotectedMove(tree, destResource, updateFlags, progress.split(50)); |
| } finally { |
| workManager.endUnprotected(depth); |
| } |
| // Invalidate the tree for further use by clients. |
| tree.makeInvalid(); |
| // Update any aliases of this resource and the destination. |
| if (success) { |
| workspace.getAliasManager().updateAliases(this, originalStore, IResource.DEPTH_INFINITE, progress.split(24)); |
| workspace.getAliasManager().updateAliases(destResource, destResource.getStore(), IResource.DEPTH_INFINITE, progress.split(24)); |
| } |
| if (!tree.getStatus().isOK()) |
| throw new ResourceException(tree.getStatus()); |
| // If this is a project, make sure the move operation is remembered. |
| if (getType() == PROJECT) |
| workspace.getSaveManager().requestSnapshot(); |
| } catch (OperationCanceledException e) { |
| workspace.getWorkManager().operationCanceled(); |
| throw e; |
| } finally { |
| workspace.endOperation(rule, true); |
| } |
| } |
| |
| @Override |
| public void move(IProjectDescription description, boolean force, boolean keepHistory, IProgressMonitor monitor) throws CoreException { |
| int updateFlags = force ? IResource.FORCE : IResource.NONE; |
| updateFlags |= keepHistory ? IResource.KEEP_HISTORY : IResource.NONE; |
| move(description, updateFlags, monitor); |
| } |
| |
| @Override |
| public void move(IProjectDescription description, int updateFlags, IProgressMonitor monitor) throws CoreException { |
| Assert.isNotNull(description); |
| if (getType() != IResource.PROJECT) { |
| String message = NLS.bind(Messages.resources_moveNotProject, getFullPath(), description.getName()); |
| throw new ResourceException(IResourceStatus.INVALID_VALUE, getFullPath(), message, null); |
| } |
| ((Project) this).move(description, updateFlags, monitor); |
| } |
| |
| @Override |
| public void refreshLocal(int depth, IProgressMonitor monitor) throws CoreException { |
| boolean isRoot = getType() == ROOT; |
| String message = isRoot ? Messages.resources_refreshingRoot : NLS.bind(Messages.resources_refreshing, getFullPath()); |
| SubMonitor progress = SubMonitor.convert(monitor, 100).checkCanceled(); |
| progress.subTask(message); |
| boolean build = false; |
| final ISchedulingRule rule = workspace.getRuleFactory().refreshRule(this); |
| try { |
| workspace.prepareOperation(rule, progress.split(1)); |
| if (!isRoot && !getProject().isAccessible()) |
| return; |
| if (!exists() && isFiltered()) |
| return; |
| workspace.beginOperation(true); |
| if (getType() == IResource.PROJECT || getType() == IResource.ROOT) |
| workspace.broadcastEvent(LifecycleEvent.newEvent(LifecycleEvent.PRE_REFRESH, this)); |
| build = getLocalManager().refresh(this, depth, true, progress.split(98)); |
| } catch (OperationCanceledException e) { |
| workspace.getWorkManager().operationCanceled(); |
| throw e; |
| } finally { |
| workspace.endOperation(rule, build); |
| } |
| } |
| |
| @Override |
| public String requestName() { |
| return getName(); |
| } |
| |
| @Override |
| public IPath requestPath() { |
| return getFullPath(); |
| } |
| |
| @Override |
| public void revertModificationStamp(long value) throws CoreException { |
| if (value < 0) |
| throw new IllegalArgumentException("Illegal value: " + value); //$NON-NLS-1$ |
| // Fetch the info but don't bother making it mutable even though we are going to modify it. |
| // It really doesn't matter as the change we are making does not show up in deltas. |
| ResourceInfo info = checkAccessibleAndLocal(DEPTH_ZERO); |
| info.setModificationStamp(value); |
| } |
| |
| @Deprecated |
| @Override |
| public void setDerived(boolean isDerived) throws CoreException { |
| // Fetch the info but don't bother making it mutable even though we are going |
| // to modify it. We don't know whether or not the tree is open and it really doesn't |
| // matter as the change we are making does not show up in deltas. |
| ResourceInfo info = getResourceInfo(false, false); |
| int flags = getFlags(info); |
| checkAccessible(flags); |
| // Ignore attempts to set derived flag on anything except files and folders |
| if (info.getType() == FILE || info.getType() == FOLDER) { |
| if (isDerived) { |
| info.set(ICoreConstants.M_DERIVED); |
| } else { |
| info.clear(ICoreConstants.M_DERIVED); |
| } |
| } |
| } |
| |
| @Override |
| public void setDerived(boolean isDerived, IProgressMonitor monitor) throws CoreException { |
| String message = NLS.bind(Messages.resources_settingDerivedFlag, getFullPath()); |
| SubMonitor progress = SubMonitor.convert(monitor, message, 100).checkCanceled(); |
| final ISchedulingRule rule = workspace.getRuleFactory().derivedRule(this); |
| try { |
| workspace.prepareOperation(rule, progress.split(1)); |
| ResourceInfo info = getResourceInfo(false, false); |
| checkAccessible(getFlags(info)); |
| // Ignore attempts to set derived flag on anything except files and folders. |
| if (info.getType() != FILE && info.getType() != FOLDER) |
| return; |
| workspace.beginOperation(true); |
| info = getResourceInfo(false, true); |
| if (isDerived) { |
| info.set(ICoreConstants.M_DERIVED); |
| } else { |
| info.clear(ICoreConstants.M_DERIVED); |
| } |
| progress.split(98); |
| } catch (OperationCanceledException e) { |
| workspace.getWorkManager().operationCanceled(); |
| throw e; |
| } finally { |
| workspace.endOperation(rule, true); |
| } |
| } |
| |
| @Override |
| public void setHidden(boolean isHidden) throws CoreException { |
| // Fetch the info but don't bother making it mutable even though we are going |
| // to modify it. We don't know whether or not the tree is open and it really doesn't |
| // matter as the change we are making does not show up in deltas. |
| ResourceInfo info = getResourceInfo(false, false); |
| int flags = getFlags(info); |
| checkAccessible(flags); |
| if (isHidden) { |
| info.set(ICoreConstants.M_HIDDEN); |
| } else { |
| info.clear(ICoreConstants.M_HIDDEN); |
| } |
| } |
| |
| @Deprecated |
| @Override |
| public void setLocal(boolean flag, int depth, IProgressMonitor monitor) throws CoreException { |
| String message = Messages.resources_setLocal; |
| SubMonitor progress = SubMonitor.convert(monitor, message, 100).checkCanceled(); |
| try { |
| workspace.prepareOperation(null, progress.split(1)); |
| workspace.beginOperation(true); |
| internalSetLocal(flag, depth); |
| progress.split(98); |
| } finally { |
| workspace.endOperation(null, true); |
| } |
| } |
| |
| @Override |
| public long setLocalTimeStamp(long value) throws CoreException { |
| if (value < 0) |
| throw new IllegalArgumentException("Illegal value: " + value); //$NON-NLS-1$ |
| // Fetch the info but don't bother making it mutable even though we are going to modify it. |
| // It really doesn't matter as the change we are making does not show up in deltas. |
| ResourceInfo info = checkAccessibleAndLocal(DEPTH_ZERO); |
| return getLocalManager().setLocalTimeStamp(this, info, value); |
| } |
| |
| @Override |
| public void setPersistentProperty(QualifiedName key, String value) throws CoreException { |
| checkAccessibleAndLocal(DEPTH_ZERO); |
| getPropertyManager().setProperty(this, key, value); |
| } |
| |
| @Deprecated |
| @Override |
| public void setReadOnly(boolean readonly) { |
| ResourceAttributes attributes = getResourceAttributes(); |
| if (attributes == null) |
| return; |
| attributes.setReadOnly(readonly); |
| try { |
| setResourceAttributes(attributes); |
| } catch (CoreException e) { |
| // Failure is not an option. |
| } |
| } |
| |
| @Override |
| public void setResourceAttributes(ResourceAttributes attributes) throws CoreException { |
| checkAccessibleAndLocal(DEPTH_ZERO); |
| getLocalManager().setResourceAttributes(this, attributes); |
| } |
| |
| @Override |
| public void setSessionProperty(QualifiedName key, Object value) throws CoreException { |
| // Fetch the info but don't bother making it mutable even though we are going to modify it. |
| // We don't know whether or not the tree is open and it really doesn't matter as the change |
| // we are making does not show up in deltas. |
| ResourceInfo info = checkAccessibleAndLocal(DEPTH_ZERO); |
| info.setSessionProperty(key, value); |
| } |
| |
| @Override |
| public void setTeamPrivateMember(boolean isTeamPrivate) throws CoreException { |
| // Fetch the info but don't bother making it mutable even though we are going |
| // to modify it. We don't know whether or not the tree is open and it really doesn't |
| // matter as the change we are making does not show up in deltas. |
| ResourceInfo info = getResourceInfo(false, false); |
| int flags = getFlags(info); |
| checkAccessible(flags); |
| // ignore attempts to set team private member flag on anything except files and folders |
| if (info.getType() == FILE || info.getType() == FOLDER) { |
| if (isTeamPrivate) { |
| info.set(ICoreConstants.M_TEAM_PRIVATE_MEMBER); |
| } else { |
| info.clear(ICoreConstants.M_TEAM_PRIVATE_MEMBER); |
| } |
| } |
| } |
| |
| /** |
| * Returns true if this resource has the potential to be |
| * (or have been) synchronized. |
| */ |
| public boolean synchronizing(ResourceInfo info) { |
| return info != null && info.getSyncInfo(false) != null; |
| } |
| |
| @Override |
| public String toString() { |
| return getTypeString() + getFullPath().toString(); |
| } |
| |
| @Override |
| public void touch(IProgressMonitor monitor) throws CoreException { |
| String message = NLS.bind(Messages.resources_touch, getFullPath()); |
| SubMonitor progress = SubMonitor.convert(monitor, message, 100).checkCanceled(); |
| final ISchedulingRule rule = workspace.getRuleFactory().modifyRule(this); |
| try { |
| workspace.prepareOperation(rule, progress.split(1)); |
| ResourceInfo info = checkAccessibleAndLocal(DEPTH_ZERO); |
| |
| workspace.beginOperation(true); |
| // Fake a change by incrementing the content ID. |
| info = getResourceInfo(false, true); |
| info.incrementContentId(); |
| // Forget content-related caching flags. |
| info.clear(M_CONTENT_CACHE); |
| workspace.updateModificationStamp(info); |
| progress.split(98); |
| } catch (OperationCanceledException e) { |
| workspace.getWorkManager().operationCanceled(); |
| throw e; |
| } finally { |
| workspace.endOperation(rule, true); |
| } |
| } |
| |
| /** |
| * Calls the move/delete hook to perform the deletion. Since this method calls |
| * client code, it is run "unprotected", so the workspace lock is not held. |
| */ |
| private void unprotectedDelete(ResourceTree tree, int updateFlags, IProgressMonitor monitor) { |
| IMoveDeleteHook hook = workspace.getMoveDeleteHook(); |
| SubMonitor progress = SubMonitor.convert(monitor, 2).checkCanceled(); |
| switch (getType()) { |
| case IResource.FILE : |
| if (!hook.deleteFile(tree, (IFile) this, updateFlags, progress.split(1))) |
| tree.standardDeleteFile((IFile) this, updateFlags, progress.split(1)); |
| break; |
| case IResource.FOLDER : |
| if (!hook.deleteFolder(tree, (IFolder) this, updateFlags, progress.split(1))) |
| tree.standardDeleteFolder((IFolder) this, updateFlags, progress.split(1)); |
| break; |
| case IResource.PROJECT : |
| if (!hook.deleteProject(tree, (IProject) this, updateFlags, progress.split(1))) |
| tree.standardDeleteProject((IProject) this, updateFlags, progress.split(1)); |
| break; |
| case IResource.ROOT : |
| // When the root is deleted, all its children including hidden projects have to be deleted. |
| IProject[] projects = ((IWorkspaceRoot) this).getProjects(IContainer.INCLUDE_HIDDEN); |
| progress.setWorkRemaining(projects.length * 2); |
| for (IProject project : projects) { |
| if (!hook.deleteProject(tree, project, updateFlags, progress.split(1))) |
| tree.standardDeleteProject(project, updateFlags, progress.split(1)); |
| } |
| break; |
| } |
| } |
| |
| /** |
| * Calls the move/delete hook to perform the move. Since this method calls |
| * client code, it is run "unprotected", so the workspace lock is not held. |
| * Returns true if resources were actually moved, and false otherwise. |
| */ |
| private boolean unprotectedMove(ResourceTree tree, final IResource destination, int updateFlags, IProgressMonitor monitor) throws CoreException, ResourceException { |
| IMoveDeleteHook hook = workspace.getMoveDeleteHook(); |
| SubMonitor progress = SubMonitor.convert(monitor, 2).checkCanceled(); |
| switch (getType()) { |
| case IResource.FILE : |
| if (!hook.moveFile(tree, (IFile) this, (IFile) destination, updateFlags, progress.split(1))) |
| tree.standardMoveFile((IFile) this, (IFile) destination, updateFlags, progress.split(1)); |
| break; |
| case IResource.FOLDER : |
| if (!hook.moveFolder(tree, (IFolder) this, (IFolder) destination, updateFlags, progress.split(1))) |
| tree.standardMoveFolder((IFolder) this, (IFolder) destination, updateFlags, progress.split(1)); |
| break; |
| case IResource.PROJECT : |
| IProject project = (IProject) this; |
| // If there is no change in name, there is nothing to do so return. |
| if (getName().equals(destination.getName())) |
| return false; |
| IProjectDescription description = project.getDescription(); |
| description.setName(destination.getName()); |
| if (!hook.moveProject(tree, project, description, updateFlags, progress.split(1))) |
| tree.standardMoveProject(project, description, updateFlags, progress.split(1)); |
| break; |
| case IResource.ROOT : |
| String msg = Messages.resources_moveRoot; |
| throw new ResourceException(new ResourceStatus(IResourceStatus.INVALID_VALUE, getFullPath(), msg)); |
| } |
| return true; |
| } |
| |
| private void broadcastPreDeleteEvent() throws CoreException { |
| switch (getType()) { |
| case IResource.PROJECT : |
| workspace.broadcastEvent(LifecycleEvent.newEvent(LifecycleEvent.PRE_PROJECT_DELETE, this)); |
| break; |
| case IResource.ROOT : |
| // All root children including hidden projects will be deleted so notify. |
| IResource[] projects = ((Container) this).getChildren(IContainer.INCLUDE_HIDDEN); |
| for (int i = 0; i < projects.length; i++) { |
| workspace.broadcastEvent(LifecycleEvent.newEvent(LifecycleEvent.PRE_PROJECT_DELETE, projects[i])); |
| } |
| break; |
| } |
| } |
| |
| private void broadcastPreMoveEvent(final IResource destination, int updateFlags) throws CoreException { |
| switch (getType()) { |
| case IResource.FILE : |
| if (isLinked()) |
| workspace.broadcastEvent(LifecycleEvent.newEvent(LifecycleEvent.PRE_LINK_MOVE, this, destination, updateFlags)); |
| break; |
| case IResource.FOLDER : |
| if (isLinked()) |
| workspace.broadcastEvent(LifecycleEvent.newEvent(LifecycleEvent.PRE_LINK_MOVE, this, destination, updateFlags)); |
| if (isVirtual()) |
| workspace.broadcastEvent(LifecycleEvent.newEvent(LifecycleEvent.PRE_GROUP_MOVE, this, destination, updateFlags)); |
| break; |
| case IResource.PROJECT : |
| if (!getName().equals(destination.getName())) { |
| // If there is a change in name, we are deleting the source project so notify. |
| workspace.broadcastEvent(LifecycleEvent.newEvent(LifecycleEvent.PRE_PROJECT_MOVE, this, destination, updateFlags)); |
| } |
| break; |
| } |
| } |
| |
| @Override |
| public IPathVariableManager getPathVariableManager() { |
| if (getProject() == null) |
| return workspace.getPathVariableManager(); |
| return new ProjectPathVariableManager(this); |
| } |
| |
| /** |
| * Calculates whether the current resource is filtered out from the resource tree |
| * by resource filters. This can happen because resource filters apply to the resource, |
| * or because resource filters apply to one of its parent. For example, if "/foo/bar" |
| * is filtered out, then calling isFilteredFromParent() on "/foo/bar/sub/file.txt" will |
| * return true as well, even though there's no resource filters that apply to "file.txt" per se. |
| * |
| * @return true is the resource is filtered out from the resource tree |
| * @see IContainer#createFilter(int, FileInfoMatcherDescription, int, IProgressMonitor) |
| */ |
| public boolean isFiltered() { |
| try { |
| return isFilteredWithException(false); |
| } catch (CoreException e) { |
| // nothing |
| } |
| return false; |
| } |
| |
| public boolean isFilteredWithException(boolean throwExeception) throws CoreException { |
| if (isLinked() || isVirtual()) |
| return false; |
| |
| Project project = (Project) getProject(); |
| if (project == null) |
| return false; |
| final ProjectDescription description = project.internalGetDescription(); |
| if (description == null) |
| return false; |
| if (description.getFilters() == null) |
| return false; |
| |
| Resource currentResource = this; |
| while (currentResource != null && currentResource.getParent() != null) { |
| Resource parent = (Resource) currentResource.getParent(); |
| IFileStore store = currentResource.getStore(); |
| if (store != null) { |
| FileInfo fileInfo = new FileInfo(store.getName()); |
| fileInfo.setDirectory(currentResource.getType() == IResource.FOLDER); |
| if (fileInfo != null) { |
| IFileInfo[] filtered = parent.filterChildren(project, description, new IFileInfo[] {fileInfo}, throwExeception); |
| if (filtered.length == 0) |
| return true; |
| } |
| } |
| currentResource = parent; |
| } |
| return false; |
| } |
| |
| public IFileInfo[] filterChildren(IFileInfo[] list, boolean throwException) throws CoreException { |
| Project project = (Project) getProject(); |
| if (project == null) |
| return list; |
| final ProjectDescription description = project.internalGetDescription(); |
| if (description == null) |
| return list; |
| return filterChildren(project, description, list, throwException); |
| } |
| |
| private IFileInfo[] filterChildren(Project project, ProjectDescription description, IFileInfo[] list, boolean throwException) throws CoreException { |
| IPath relativePath = getProjectRelativePath(); |
| LinkedList<Filter> currentIncludeFilters = new LinkedList<>(); |
| LinkedList<Filter> currentExcludeFilters = new LinkedList<>(); |
| LinkedList<FilterDescription> filters = null; |
| |
| boolean firstSegment = true; |
| do { |
| if (!firstSegment) |
| relativePath = relativePath.removeLastSegments(1); |
| filters = description.getFilter(relativePath); |
| if (filters != null) { |
| for (Iterator<FilterDescription> it = filters.iterator(); it.hasNext();) { |
| FilterDescription desc = it.next(); |
| if (firstSegment || desc.isInheritable()) { |
| Filter filter = new Filter(project, desc); |
| if (filter.isIncludeOnly()) { |
| if (filter.isFirst()) |
| currentIncludeFilters.addFirst(filter); |
| else |
| currentIncludeFilters.addLast(filter); |
| } else { |
| if (filter.isFirst()) |
| currentExcludeFilters.addFirst(filter); |
| else |
| currentExcludeFilters.addLast(filter); |
| } |
| } |
| } |
| } |
| firstSegment = false; |
| } while (relativePath.segmentCount() > 0); |
| |
| if ((currentIncludeFilters.size() > 0) || (currentExcludeFilters.size() > 0)) { |
| try { |
| list = Filter.filter(project, currentIncludeFilters, currentExcludeFilters, (IContainer) this, list); |
| } catch (CoreException e) { |
| if (throwException) |
| throw e; |
| } |
| } |
| return list; |
| } |
| |
| /** |
| * @see IFolder#createLink(URI, int, IProgressMonitor) |
| * @see IFile#createLink(URI, int, IProgressMonitor) |
| */ |
| public void setLinkLocation(URI location, int updateFlags, IProgressMonitor monitor) throws CoreException { |
| if (!isLinked()) { |
| String message = NLS.bind(Messages.links_resourceIsNotALink, getFullPath()); |
| throw new ResourceException(IResourceStatus.INVALID_VALUE, getFullPath(), message, null); |
| } |
| |
| String message = NLS.bind(Messages.links_setLocation, getFullPath()); |
| SubMonitor progress = SubMonitor.convert(monitor, message, 100).checkCanceled(); |
| final ISchedulingRule rule = workspace.getRuleFactory().createRule(this); |
| try { |
| workspace.prepareOperation(rule, progress.split(1)); |
| workspace.broadcastEvent(LifecycleEvent.newEvent(LifecycleEvent.PRE_LINK_CHANGE, this)); |
| workspace.beginOperation(true); |
| |
| ResourceInfo info = workspace.getResourceInfo(getFullPath(), true, false); |
| getLocalManager().setLocation(this, info, location); |
| |
| LinkDescription linkDescription; |
| linkDescription = new LinkDescription(this, location); |
| Project project = (Project) getProject(); |
| project.internalGetDescription().setLinkLocation(getProjectRelativePath(), linkDescription); |
| project.writeDescription(updateFlags); |
| |
| // Refresh either in background or foreground. |
| if ((updateFlags & IResource.BACKGROUND_REFRESH) != 0) { |
| workspace.refreshManager.refresh(this); |
| progress.split(99); |
| } else { |
| refreshLocal(DEPTH_INFINITE, progress.split(98)); |
| } |
| } finally { |
| workspace.endOperation(rule, true); |
| } |
| } |
| |
| /** |
| * @see IFolder#createLink(IPath, int, IProgressMonitor) |
| * @see IFile#createLink(IPath, int, IProgressMonitor) |
| */ |
| public void setLinkLocation(IPath location, int updateFlags, IProgressMonitor monitor) throws CoreException { |
| if (location.isAbsolute()) { |
| setLinkLocation(URIUtil.toURI(location.toPortableString()), updateFlags, monitor); |
| } else { |
| URI uri; |
| try { |
| uri = new URI(null, null, location.toPortableString(), null); |
| } catch (URISyntaxException e) { |
| uri = URIUtil.toURI(location.toPortableString()); |
| } |
| setLinkLocation(uri, updateFlags, monitor); |
| } |
| } |
| } |