blob: 2052d44d6301542164e3b664999567edd9e03cc3 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2006, 2017 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.team.internal.ui.mapping;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.mapping.ModelProvider;
import org.eclipse.core.resources.mapping.ResourceTraversal;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.jface.viewers.TreePath;
import org.eclipse.osgi.util.NLS;
import org.eclipse.team.core.diff.IDiff;
import org.eclipse.team.core.mapping.IResourceDiffTree;
import org.eclipse.team.core.mapping.ISynchronizationContext;
import org.eclipse.team.core.mapping.provider.ResourceDiffTree;
import org.eclipse.team.internal.core.subscribers.ChangeSet;
import org.eclipse.team.internal.core.subscribers.DiffChangeSet;
import org.eclipse.team.internal.ui.IPreferenceIds;
import org.eclipse.team.internal.ui.TeamUIMessages;
import org.eclipse.team.internal.ui.TeamUIPlugin;
import org.eclipse.team.ui.mapping.ITeamContentProviderManager;
import org.eclipse.team.ui.synchronize.ISynchronizePageConfiguration;
public class ResourceModelTraversalCalculator {
public static final String PROP_TRAVERSAL_CALCULATOR = "org.eclipse.team.ui.resourceModelTraversalCalculator"; //$NON-NLS-1$
private static ResourceModelTraversalCalculator instance;
private final ISynchronizePageConfiguration configuration;
public ResourceModelTraversalCalculator(
ISynchronizePageConfiguration configuration) {
this.configuration = configuration;
}
public ResourceModelTraversalCalculator() {
configuration = null;
}
public int getLayoutDepth(IResource resource, TreePath path) {
if (isFlatPageLayout()) {
return (resource instanceof IWorkspaceRoot) ? IResource.DEPTH_INFINITE : IResource.DEPTH_ZERO;
}
if (resource.getType() == IResource.PROJECT)
return IResource.DEPTH_INFINITE;
if (resource.getType() == IResource.FILE)
return IResource.DEPTH_ZERO;
if (path != null && hasNonResource(path))
return IResource.DEPTH_INFINITE;
if (getLayout().equals(IPreferenceIds.FLAT_LAYOUT)) {
return IResource.DEPTH_ZERO;
} else if (getLayout().equals(IPreferenceIds.COMPRESSED_LAYOUT)) {
return IResource.DEPTH_ONE;
}
return IResource.DEPTH_INFINITE;
}
public String getLayout() {
return TeamUIPlugin.getPlugin().getPreferenceStore().getString(IPreferenceIds.SYNCVIEW_DEFAULT_LAYOUT);
}
public Object[] filterChildren(IResourceDiffTree diffTree, IResource resource, Object parentOrPath, Object[] children) {
if (parentOrPath instanceof TreePath) {
TreePath tp = (TreePath) parentOrPath;
if (hasNonResource(tp)) {
return getTreeChildren(diffTree, resource, children);
}
}
if (isFlatPageLayout()) {
if (resource instanceof IWorkspaceRoot) {
return diffTree.getAffectedResources();
} else {
return new Object[0];
}
} else if (getLayout().equals(IPreferenceIds.FLAT_LAYOUT) && resource.getType() == IResource.PROJECT) {
return getFlatChildren(diffTree, resource);
} else if (getLayout().equals(IPreferenceIds.COMPRESSED_LAYOUT) && resource.getType() == IResource.PROJECT) {
return getCompressedChildren(diffTree, (IProject)resource, children);
} else if (getLayout().equals(IPreferenceIds.COMPRESSED_LAYOUT) && resource.getType() == IResource.FOLDER) {
return getCompressedChildren(diffTree, (IFolder)resource, children);
}
return getTreeChildren(diffTree, resource, children);
}
private boolean hasNonResource(TreePath parentPath) {
for (int i = 0; i < parentPath.getSegmentCount(); i++) {
Object o = parentPath.getSegment(i);
if (!(o instanceof IResource) && !(o instanceof ModelProvider) && !(o instanceof ChangeSet)) {
return true;
}
}
return false;
}
private Object[] getCompressedChildren(IResourceDiffTree diffTree, IProject project, Object[] children) {
Set<Object> result = new HashSet<>();
IDiff[] diffs = diffTree.getDiffs(project, IResource.DEPTH_INFINITE);
for (int i = 0; i < diffs.length; i++) {
IDiff diff = diffs[i];
IResource resource = diffTree.getResource(diff);
if (resource.getType() == IResource.FILE) {
IContainer parent = resource.getParent();
if (parent.getType() == IResource.FOLDER)
result.add(parent);
else
result.add(resource);
} else if (resource.getType() == IResource.FOLDER)
result.add(resource);
}
return result.toArray();
}
/*
* Only return the files that are direct children of the folder
*/
private Object[] getCompressedChildren(IResourceDiffTree diffTree, IFolder folder, Object[] children) {
Set<Object> result = new HashSet<>();
for (int i = 0; i < children.length; i++) {
Object object = children[i];
if (object instanceof IResource) {
IResource resource = (IResource) object;
if (resource.getType() == IResource.FILE)
result.add(resource);
}
}
IDiff[] diffs = diffTree.getDiffs(folder, IResource.DEPTH_ONE);
for (int i = 0; i < diffs.length; i++) {
IDiff diff = diffs[i];
IResource resource = diffTree.getResource(diff);
if (resource.getType() == IResource.FILE)
result.add(resource);
}
return result.toArray();
}
private Object[] getFlatChildren(IResourceDiffTree diffTree, IResource resource) {
Object[] allChildren;
IDiff[] diffs = diffTree.getDiffs(resource, IResource.DEPTH_INFINITE);
ArrayList<Object> result = new ArrayList<>();
for (int i = 0; i < diffs.length; i++) {
IDiff diff = diffs[i];
result.add(diffTree.getResource(diff));
}
allChildren = result.toArray();
return allChildren;
}
private Object[] getTreeChildren(IResourceDiffTree diffTree, IResource resource, Object[] children) {
Set<Object> result = new HashSet<>();
for (int i = 0; i < children.length; i++) {
Object object = children[i];
result.add(object);
}
IResource[] setChildren = getChildren(diffTree, resource);
for (int i = 0; i < setChildren.length; i++) {
IResource child = setChildren[i];
result.add(child);
}
Object[] allChildren = result.toArray(new Object[result.size()]);
return allChildren;
}
public static IResource[] getChildren(IResourceDiffTree diffTree, IResource resource) {
Set<IResource> result = new HashSet<>();
IPath[] childPaths = diffTree.getChildren(resource.getFullPath());
for (int i = 0; i < childPaths.length; i++) {
IPath path = childPaths[i];
IDiff delta = diffTree.getDiff(path);
IResource child;
if (delta == null) {
// the path has descendent deltas so it must be a folder
if (path.segmentCount() == 1) {
child = ((IWorkspaceRoot)resource).getProject(path.lastSegment());
} else {
child = ((IContainer)resource).getFolder(new Path(path.lastSegment()));
}
} else {
child = diffTree.getResource(delta);
}
result.add(child);
}
return result.toArray(new IResource[result.size()]);
}
public ResourceTraversal[] getTraversals(DiffChangeSet dcs, TreePath tp) {
IResource[] resources = getResource(dcs, tp);
return new ResourceTraversal[] { new ResourceTraversal(resources, IResource.DEPTH_ZERO, IResource.NONE) };
}
private IResource[] getResource(DiffChangeSet dcs, TreePath tp) {
if (tp.getSegmentCount() == 1 && tp.getFirstSegment() == dcs) {
return dcs.getResources();
}
Set<IResource> result = new HashSet<>();
Object o = tp.getLastSegment();
if (o instanceof IResource) {
IResource resource = (IResource) o;
int depth = getLayoutDepth(resource, tp);
IDiff[] diffs = dcs.getDiffTree().getDiffs(resource, depth);
for (int i = 0; i < diffs.length; i++) {
IDiff diff = diffs[i];
IResource r = ResourceDiffTree.getResourceFor(diff);
if (r != null)
result.add(r);
}
}
return result.toArray(new IResource[result.size()]);
}
public ResourceTraversal[] getTraversals(IResource resource, TreePath tp) {
return new ResourceTraversal[] { new ResourceTraversal(new IResource[] { resource }, getLayoutDepth(resource, tp), IResource.NONE) };
}
public boolean isResourcePath(TreePath path) {
for (int i = 0; i < path.getSegmentCount(); i++) {
Object o = path.getSegment(i);
if (!(o instanceof IResource)) {
return false;
}
}
return true;
}
public String getLabel(Object elementOrPath) {
if (elementOrPath instanceof TreePath && hasNonResource((TreePath)elementOrPath)) {
return null;
}
Object element = internalGetElement(elementOrPath);
Object parent = internalGetElementParent(elementOrPath);
if (element instanceof IResource) {
IResource resource = (IResource) element;
if (isFlatPageLayout()) {
IPath path = resource.getFullPath();
if (!path.isEmpty())
return NLS.bind(TeamUIMessages.ResourceModelLabelProvider_0, resource.getName(), path.toString());
}
if (getLayout().equals(IPreferenceIds.COMPRESSED_LAYOUT)
&& resource.getType() == IResource.FOLDER
&& (parent == null || parent instanceof IProject)) {
return resource.getProjectRelativePath().toString();
}
if (getLayout().equals(IPreferenceIds.FLAT_LAYOUT)
&& resource.getType() == IResource.FILE
&& (parent == null || parent instanceof IProject)) {
IPath parentPath = resource.getProjectRelativePath().removeLastSegments(1);
if (!parentPath.isEmpty())
return NLS.bind(TeamUIMessages.ResourceModelLabelProvider_0, resource.getName(), parentPath.toString());
}
}
return null;
}
public boolean isCompressedFolder(Object elementOrPath) {
if (elementOrPath instanceof TreePath && hasNonResource((TreePath)elementOrPath)) {
return false;
}
Object element = internalGetElement(elementOrPath);
Object parent = internalGetElementParent(elementOrPath);
if (element instanceof IResource) {
IResource resource = (IResource) element;
// Only use the compressed folder icon if the parent is not known
// or the parent is a project
return getLayout().equals(IPreferenceIds.COMPRESSED_LAYOUT)
&& resource.getType() == IResource.FOLDER
&& (parent == null || parent instanceof IProject);
}
return false;
}
private TreePath internalGetPath(Object elementOrPath) {
if (elementOrPath instanceof TreePath) {
return (TreePath) elementOrPath;
}
return null;
}
private Object internalGetElement(Object elementOrPath) {
if (elementOrPath instanceof TreePath) {
TreePath tp = (TreePath) elementOrPath;
return tp.getLastSegment();
}
return elementOrPath;
}
private Object internalGetElementParent(Object elementOrPath) {
if (elementOrPath instanceof TreePath) {
TreePath tp = (TreePath) elementOrPath;
if (tp.getSegmentCount() > 1) {
return tp.getSegment(tp.getSegmentCount() - 2);
}
}
return null;
}
public boolean hasChildren(ISynchronizationContext context, Object elementOrPath) {
Object element = internalGetElement(elementOrPath);
if (element instanceof IContainer) {
IContainer container = (IContainer) element;
// For containers check to see if the delta contains any children
if (context != null) {
int depth = getLayoutDepth(container, internalGetPath(elementOrPath));
if (depth == IResource.DEPTH_ZERO)
return false;
IResourceDiffTree tree = context.getDiffTree();
IResource[] members = tree.members(container);
if (members.length > 0) {
if (depth == IResource.DEPTH_INFINITE)
return true;
for (int i = 0; i < members.length; i++) {
IResource resource = members[i];
if (resource.getType() == IResource.FILE)
return true;
}
}
}
}
return false;
}
public TreePath getParentPath(ISynchronizationContext context, ModelProvider provider, Object element) {
if (element instanceof IResource) {
IResource resource = (IResource) element;
TreePath treePath = getProviderRootPath(context, provider);
if (resource.getType() == IResource.ROOT){
return null;
}
if (resource.getType() == IResource.PROJECT){
return treePath;
}
if (getLayout().equals(IPreferenceIds.FLAT_LAYOUT)) {
return treePath.createChildPath(resource.getProject());
} else if (getLayout().equals(IPreferenceIds.COMPRESSED_LAYOUT) && resource.getType() == IResource.FOLDER) {
return treePath.createChildPath(resource.getProject());
} else if (getLayout().equals(IPreferenceIds.COMPRESSED_LAYOUT) && resource.getType() == IResource.FILE) {
if (resource.getParent().getType() == IResource.PROJECT)
return treePath.createChildPath(resource.getProject());
return treePath.createChildPath(resource.getProject()).createChildPath(resource.getParent());
}
IResource parent = resource.getParent();
IResource[] resourcePath = new IResource[parent.getFullPath().segmentCount()];
for (int i = resourcePath.length - 1; i >= 0; i--) {
resourcePath[i] = parent;
parent = parent.getParent();
}
for (int i = 0; i < resourcePath.length; i++) {
IResource r = resourcePath[i];
treePath = treePath.createChildPath(r);
}
return treePath;
}
return null;
}
private TreePath getProviderRootPath(ISynchronizationContext context, ModelProvider provider) {
if (context == null)
return TreePath.EMPTY.createChildPath(provider);
return TreePath.EMPTY;
}
private boolean isFlatPageLayout() {
if (configuration != null) {
String p = (String)configuration.getProperty(ITeamContentProviderManager.PROP_PAGE_LAYOUT);
return p != null && p.equals(ITeamContentProviderManager.FLAT_LAYOUT);
}
return false;
}
public synchronized static ResourceModelTraversalCalculator getDefault() {
if (instance == null)
instance = new ResourceModelTraversalCalculator();
return instance;
}
public synchronized static ResourceModelTraversalCalculator getTraversalCalculator(ISynchronizePageConfiguration configuration) {
if (configuration == null)
return ResourceModelTraversalCalculator.getDefault();
ResourceModelTraversalCalculator tc = (ResourceModelTraversalCalculator)configuration.getProperty(ResourceModelTraversalCalculator.PROP_TRAVERSAL_CALCULATOR);
if (tc == null) {
tc = new ResourceModelTraversalCalculator(configuration);
configuration.setProperty(ResourceModelTraversalCalculator.PROP_TRAVERSAL_CALCULATOR, tc);
}
return tc;
}
}