| /******************************************************************************* |
| * Copyright (c) 2004, 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 - Initial API and implementation |
| * James Blackburn (Broadcom Corp.) - ongoing development |
| * Lars Vogel <Lars.Vogel@vogella.com> - Bug 473427 |
| *******************************************************************************/ |
| package org.eclipse.core.resources.team; |
| |
| import java.util.HashSet; |
| import org.eclipse.core.resources.*; |
| import org.eclipse.core.runtime.IPath; |
| import org.eclipse.core.runtime.jobs.ISchedulingRule; |
| import org.eclipse.core.runtime.jobs.MultiRule; |
| |
| /** |
| * Default implementation of IResourceRuleFactory. The teamHook extension |
| * may subclass to provide more specialized scheduling rules for workspace operations that |
| * they participate in. |
| * |
| * @see IResourceRuleFactory |
| * @since 3.0 |
| */ |
| public class ResourceRuleFactory implements IResourceRuleFactory { |
| private final IWorkspace workspace = ResourcesPlugin.getWorkspace(); |
| |
| /** |
| * Creates a new default resource rule factory. This constructor must only |
| * be called by subclasses. |
| */ |
| protected ResourceRuleFactory() { |
| super(); |
| } |
| |
| /** |
| * Default implementation of <code>IResourceRuleFactory#buildRule</code>. |
| * This default implementation always returns the workspace root. |
| * <p> |
| * Subclasses may not currently override this method. |
| * |
| * @see org.eclipse.core.resources.IResourceRuleFactory#buildRule() |
| */ |
| @Override |
| public final ISchedulingRule buildRule() { |
| return workspace.getRoot(); |
| } |
| |
| /** |
| * Default implementation of <code>IResourceRuleFactory#charsetRule</code>. |
| * This default implementation always returns the project of the resource |
| * whose charset setting is being changed, or <code>null</code> if the |
| * resource is the workspace root. |
| * <p> |
| * Subclasses may override this method. The rule provided by an overriding |
| * method must at least contain the rule from this default implementation. |
| * </p> |
| * |
| * @see org.eclipse.core.runtime.jobs.ISchedulingRule#contains(org.eclipse.core.runtime.jobs.ISchedulingRule) |
| * @see org.eclipse.core.resources.IResourceRuleFactory#charsetRule(IResource) |
| * @since 3.1 |
| */ |
| @Override |
| public ISchedulingRule charsetRule(IResource resource) { |
| if (resource.getType() == IResource.ROOT) |
| return null; |
| return resource.getProject(); |
| } |
| |
| /** |
| * Default implementation of <code>IResourceRuleFactory#derivedRule</code>. |
| * This default implementation always returns <code>null</code>. |
| * <p> |
| * Subclasses may not currently override this method. |
| * |
| * @see org.eclipse.core.runtime.jobs.ISchedulingRule#contains(org.eclipse.core.runtime.jobs.ISchedulingRule) |
| * @see org.eclipse.core.resources.IResourceRuleFactory#derivedRule(IResource) |
| * @since 3.6 |
| */ |
| @Override |
| public final ISchedulingRule derivedRule(IResource resource) { |
| return null; |
| } |
| |
| /** |
| * Default implementation of <code>IResourceRuleFactory#copyRule</code>. |
| * This default implementation always returns the parent of the destination |
| * resource. |
| * <p> |
| * Subclasses may override this method. The rule provided by an overriding |
| * method must at least contain the rule from this default implementation. |
| * |
| * @see org.eclipse.core.runtime.jobs.ISchedulingRule#contains(org.eclipse.core.runtime.jobs.ISchedulingRule) |
| * @see org.eclipse.core.resources.IResourceRuleFactory#copyRule(IResource, IResource) |
| */ |
| @Override |
| public ISchedulingRule copyRule(IResource source, IResource destination) { |
| //source is not modified, destination is created |
| return parent(destination); |
| } |
| |
| /** |
| * Default implementation of <code>IResourceRuleFactory#createRule</code>. |
| * This default implementation always returns the parent of the resource |
| * being created. |
| * <p> |
| * Subclasses may override this method. The rule provided by an overriding |
| * method must at least contain the rule from this default implementation. |
| * |
| * @see org.eclipse.core.runtime.jobs.ISchedulingRule#contains(org.eclipse.core.runtime.jobs.ISchedulingRule) |
| * @see org.eclipse.core.resources.IResourceRuleFactory#createRule(IResource) |
| */ |
| @Override |
| public ISchedulingRule createRule(IResource resource) { |
| return parent(resource); |
| } |
| |
| /** |
| * Default implementation of <code>IResourceRuleFactory#deleteRule</code>. |
| * This default implementation always returns the parent of the resource |
| * being deleted. |
| * <p> |
| * Subclasses may override this method. The rule provided by an overriding |
| * method must at least contain the rule from this default implementation. |
| * |
| * @see org.eclipse.core.runtime.jobs.ISchedulingRule#contains(org.eclipse.core.runtime.jobs.ISchedulingRule) |
| * @see org.eclipse.core.resources.IResourceRuleFactory#deleteRule(IResource) |
| */ |
| @Override |
| public ISchedulingRule deleteRule(IResource resource) { |
| return parent(resource); |
| } |
| |
| private boolean isReadOnly(IResource resource) { |
| ResourceAttributes attributes = resource.getResourceAttributes(); |
| return attributes == null ? false : attributes.isReadOnly(); |
| } |
| |
| /** |
| * Default implementation of <code>IResourceRuleFactory#markerRule</code>. |
| * This default implementation always returns <code>null</code>. |
| * <p> |
| * Subclasses may not currently override this method. |
| * |
| * @see org.eclipse.core.resources.IResourceRuleFactory#markerRule(IResource) |
| */ |
| @Override |
| public final ISchedulingRule markerRule(IResource resource) { |
| return null; |
| } |
| |
| /** |
| * Default implementation of <code>IResourceRuleFactory#modifyRule</code>. |
| * This default implementation returns the resource being modified, or the |
| * parent resource if modifying a project description file. |
| * Note that this must encompass any rule required by the <code>validateSave</code> hook. |
| * <p> |
| * Subclasses may override this method. The rule provided by an overriding |
| * method must at least contain the rule from this default implementation. |
| * |
| * @see org.eclipse.core.runtime.jobs.ISchedulingRule#contains(org.eclipse.core.runtime.jobs.ISchedulingRule) |
| * @see org.eclipse.core.resources.IResourceRuleFactory#modifyRule(IResource) |
| * @see FileModificationValidator#validateSave(IFile) |
| * @see IProjectDescription#DESCRIPTION_FILE_NAME |
| */ |
| @Override |
| public ISchedulingRule modifyRule(IResource resource) { |
| IPath path = resource.getFullPath(); |
| //modifying the project description may cause linked resources to be created or deleted |
| if (path.segmentCount() == 2 && path.segment(1).equals(IProjectDescription.DESCRIPTION_FILE_NAME)) |
| return parent(resource); |
| return resource; |
| } |
| |
| /** |
| * Default implementation of <code>IResourceRuleFactory#moveRule</code>. |
| * This default implementation returns a rule that combines the parent |
| * of the source resource and the parent of the destination resource. |
| * <p> |
| * Subclasses may override this method. The rule provided by an overriding |
| * method must at least contain the rule from this default implementation. |
| * |
| * @see org.eclipse.core.runtime.jobs.ISchedulingRule#contains(org.eclipse.core.runtime.jobs.ISchedulingRule) |
| * @see org.eclipse.core.resources.IResourceRuleFactory#moveRule(IResource, IResource) |
| */ |
| @Override |
| public ISchedulingRule moveRule(IResource source, IResource destination) { |
| //move needs the parent of both source and destination |
| return MultiRule.combine(parent(source), parent(destination)); |
| } |
| |
| /** |
| * Convenience method to return the parent of the given resource, |
| * or the resource itself for projects and the workspace root. |
| * @param resource the resource to compute the parent of |
| * @return the parent resource for folders and files, and the |
| * resource itself for projects and the workspace root. |
| */ |
| protected final ISchedulingRule parent(IResource resource) { |
| switch (resource.getType()) { |
| case IResource.ROOT : |
| case IResource.PROJECT : |
| return resource; |
| default : |
| return resource.getParent(); |
| } |
| } |
| |
| /** |
| * Default implementation of <code>IResourceRuleFactory#refreshRule</code>. |
| * This default implementation always returns the parent of the resource |
| * being refreshed. |
| * <p> |
| * Subclasses may override this method. The rule provided by an overriding |
| * method must at least contain the rule from this default implementation. |
| * |
| * @see org.eclipse.core.runtime.jobs.ISchedulingRule#contains(org.eclipse.core.runtime.jobs.ISchedulingRule) |
| * @see org.eclipse.core.resources.IResourceRuleFactory#refreshRule(IResource) |
| */ |
| @Override |
| public ISchedulingRule refreshRule(IResource resource) { |
| return parent(resource); |
| } |
| |
| /** |
| * Default implementation of <code>IResourceRuleFactory#validateEditRule</code>. |
| * This default implementation returns a rule that combines the parents of |
| * all read-only resources, or <code>null</code> if there are no read-only |
| * resources. |
| * <p> |
| * Subclasses may override this method. The rule provided by an overriding |
| * method must at least contain the rule from this default implementation. |
| * |
| * @see org.eclipse.core.runtime.jobs.ISchedulingRule#contains(org.eclipse.core.runtime.jobs.ISchedulingRule) |
| * @see org.eclipse.core.resources.IResourceRuleFactory#validateEditRule(IResource[]) |
| */ |
| @Override |
| public ISchedulingRule validateEditRule(IResource[] resources) { |
| if (resources.length == 0) |
| return null; |
| //optimize rule for single file |
| if (resources.length == 1) |
| return isReadOnly(resources[0]) ? parent(resources[0]) : null; |
| //need a lock on the parents of all read-only files |
| HashSet<ISchedulingRule> rules = new HashSet<>(); |
| for (IResource resource : resources) |
| if (isReadOnly(resource)) |
| rules.add(parent(resource)); |
| if (rules.isEmpty()) |
| return null; |
| if (rules.size() == 1) |
| return rules.iterator().next(); |
| ISchedulingRule[] ruleArray = rules.toArray(new ISchedulingRule[rules.size()]); |
| return new MultiRule(ruleArray); |
| } |
| } |