blob: c3fdbf6716626f3895684ff0080413c2d834d965 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 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.dialogs;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.mapping.RemoteResourceMappingContext;
import org.eclipse.core.resources.mapping.ResourceMapping;
import org.eclipse.core.resources.mapping.ResourceMappingContext;
import org.eclipse.core.resources.mapping.ResourceTraversal;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.team.internal.core.Policy;
import org.eclipse.team.internal.ui.TeamUIPlugin;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.model.IWorkbenchAdapter;
import org.eclipse.ui.model.WorkbenchContentProvider;
import org.eclipse.ui.model.WorkbenchLabelProvider;
import org.eclipse.ui.views.navigator.ResourceComparator;
/**
* Dialog area which displays the resources for a resource mapping
*/
public class ResourceMappingResourceDisplayArea extends DialogArea {
private ResourceMapping mapping;
private ResourceMappingContext context = ResourceMappingContext.LOCAL_CONTEXT;
private TreeViewer viewer;
private Label label;
private IResourceMappingResourceFilter filter;
private Map<ResourceMapping, Map<IResource, List<IResource>>> cachedFiltering = new HashMap<>();
private String message;
private static IWorkbenchAdapter getWorkbenchAdapter(IAdaptable o) {
return o.getAdapter(IWorkbenchAdapter.class);
}
/**
* Return the label that should be used for the given mapping
* as determined using the IWorkbnchAdaptable for the mapping
* or it's model object.
* @param mapping the mappings
* @return it's label
*/
public static String getLabel(ResourceMapping mapping) {
Object o = mapping;
IWorkbenchAdapter workbenchAdapter = getWorkbenchAdapter((IAdaptable)o);
if (workbenchAdapter == null) {
Object modelObject = mapping.getModelObject();
if (modelObject instanceof IAdaptable) {
workbenchAdapter = getWorkbenchAdapter((IAdaptable)modelObject);
o = modelObject;
}
}
if (workbenchAdapter == null) {
return mapping.toString();
}
return workbenchAdapter.getLabel(o);
}
public class ResourceMappingElement implements IWorkbenchAdapter, IAdaptable {
private ResourceMapping mapping;
private ResourceMappingContext context;
public ResourceMappingElement(ResourceMapping mapping, ResourceMappingContext context) {
this.mapping = mapping;
this.context = context;
}
@Override
public Object[] getChildren(Object o) {
ResourceTraversal[] traversals = getTraversals();
List<ResourceTraversalElement> result = new ArrayList<>();
for (int i = 0; i < traversals.length; i++) {
ResourceTraversal traversal = traversals[i];
IResource[] resources = traversal.getResources();
for (int j = 0; j < resources.length; j++) {
IResource resource = resources[j];
if (isIncludedInFilter(resource, traversal))
result.add(new ResourceTraversalElement(this, traversal, resource, context));
}
}
return result.toArray(new Object[result.size()]);
}
private ResourceTraversal[] getTraversals() {
return ResourceMappingResourceDisplayArea.getTraversals(mapping, context);
}
@Override
public ImageDescriptor getImageDescriptor(Object o) {
o = mapping;
IWorkbenchAdapter workbenchAdapter = getWorkbenchAdapter((IAdaptable)o);
if (workbenchAdapter == null) {
Object modelObject = mapping.getModelObject();
if (modelObject instanceof IAdaptable) {
workbenchAdapter = getWorkbenchAdapter((IAdaptable)modelObject);
o = modelObject;
}
}
if (workbenchAdapter == null) {
return null;
}
return workbenchAdapter.getImageDescriptor(o);
}
@Override
public String getLabel(Object o) {
return ResourceMappingResourceDisplayArea.getLabel(mapping);
}
@Override
public Object getParent(Object o) {
return null;
}
@Override
@SuppressWarnings("unchecked")
public <T> T getAdapter(Class<T> adapter) {
if (adapter == IWorkbenchAdapter.class)
return (T) this;
return null;
}
}
/**
* The model element for resources that are obtained from a traversal.
*/
public class ResourceTraversalElement implements IWorkbenchAdapter, IAdaptable {
private ResourceTraversal traversal;
private ResourceMappingContext context;
private IResource resource;
private Object parent;
public ResourceTraversalElement(Object parent, ResourceTraversal traversal, IResource resource, ResourceMappingContext context) {
this.parent = parent;
this.traversal = traversal;
this.resource = resource;
this.context = context;
}
@Override
public Object[] getChildren(Object o) {
if (traversal.getDepth() == IResource.DEPTH_INFINITE) {
return getChildren(true);
} else if (traversal.getDepth() == IResource.DEPTH_ONE && isTraversalRoot(resource)) {
return getChildren(false);
}
return new Object[0];
}
private Object[] getChildren(boolean includeFolders) {
try {
if (resource.getType() != IResource.FILE) {
IResource[] members = members(((IContainer)resource));
List<ResourceTraversalElement> result = new ArrayList<ResourceTraversalElement>();
for (int i = 0; i < members.length; i++) {
IResource child = members[i];
if ((includeFolders || child.getType() == IResource.FILE)
&& isIncludedInFilter(child, traversal))
result.add(new ResourceTraversalElement(this, traversal, child, context));
}
return result.toArray(new Object[result.size()]);
}
} catch (CoreException e) {
TeamUIPlugin.log(IStatus.ERROR, "An error occurred fetching the members of " + resource.getFullPath(), e); //$NON-NLS-1$
}
return new Object[0];
}
private IResource[] members(IContainer container) throws CoreException {
if (context instanceof RemoteResourceMappingContext) {
RemoteResourceMappingContext remoteContext = (RemoteResourceMappingContext) context;
return ResourceMappingResourceDisplayArea.members(container, remoteContext);
}
return container.members();
}
@Override
public ImageDescriptor getImageDescriptor(Object object) {
IWorkbenchAdapter workbenchAdapter = getWorkbenchAdapter(resource);
if (workbenchAdapter == null)
return null;
return workbenchAdapter.getImageDescriptor(resource);
}
@Override
public String getLabel(Object o) {
if (resource.getType() != IResource.PROJECT && isTraversalRoot(resource))
return resource.getFullPath().toString();
IWorkbenchAdapter workbenchAdapter = getWorkbenchAdapter(resource);
if (workbenchAdapter == null)
return resource.getName();
return workbenchAdapter.getLabel(resource);
}
private boolean isTraversalRoot(IResource resource) {
return ResourceMappingResourceDisplayArea.isTraversalRoot(traversal, resource);
}
@Override
public Object getParent(Object o) {
return parent;
}
@Override
@SuppressWarnings("unchecked")
public <T> T getAdapter(Class<T> adapter) {
if (adapter == IWorkbenchAdapter.class)
return (T) this;
return null;
}
public IResource getResource() {
return resource;
}
}
/**
* Create a dialog area that will display the resources contained in the
* given mapping.
*
* @param mapping the mapping
* @param filter the filter
* @param string the message to display
*/
public ResourceMappingResourceDisplayArea(ResourceMapping mapping, String string, IResourceMappingResourceFilter filter) {
this.mapping = mapping;
this.filter = filter;
this.message = string;
}
@Override
public void createArea(Composite parent) {
Composite composite = createComposite(parent, 1, true);
label = createWrappingLabel(composite, message, 1);
viewer = new TreeViewer(composite);
GridData gridData = new GridData(GridData.FILL_BOTH);
gridData.heightHint = 100;
viewer.getControl().setLayoutData(gridData);
viewer.setContentProvider(new WorkbenchContentProvider());
viewer.setLabelProvider(new WorkbenchLabelProvider());
viewer.setComparator(new ResourceComparator(ResourceComparator.NAME) {
@Override
public int compare(Viewer viewer, Object o1, Object o2) {
if (o1 instanceof ResourceTraversalElement && o2 instanceof ResourceTraversalElement) {
ResourceTraversalElement e1 = (ResourceTraversalElement) o1;
ResourceTraversalElement e2 = (ResourceTraversalElement) o2;
return super.compare(viewer, e1.getResource(), e2.getResource());
}
return super.compare(viewer, o1, o2);
}
});
setInput(message);
Dialog.applyDialogFont(parent);
}
private void setInput(String labelText) {
if (viewer != null) {
Object o = null;
if (mapping != null)
o = new ResourceMappingElement(mapping, context);
viewer.setInput(o);
}
if (label != null) {
this.message = labelText;
label.setText(labelText);
}
}
public void setMapping(ResourceMapping mapping, String labelText) {
this.mapping = mapping;
setInput(labelText);
}
private boolean isIncludedInFilter(IResource resource, ResourceTraversal traversal) {
if (filter == null)
return true;
Map<IResource, List<IResource>> mappingResources = cachedFiltering.get(mapping);
if (mappingResources == null) {
mappingResources = buildFilteredResourceMap(mapping, context);
cachedFiltering.put(mapping, mappingResources);
}
return mappingResources.containsKey(resource);
}
private Map<IResource, List<IResource>> buildFilteredResourceMap(final ResourceMapping mapping, final ResourceMappingContext context) {
final Map<IResource, List<IResource>> result = new HashMap<>();
try {
PlatformUI.getWorkbench().getProgressService().busyCursorWhile(new IRunnableWithProgress() {
@Override
public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
try {
monitor.beginTask(null, IProgressMonitor.UNKNOWN);
ResourceTraversal[] traversals = mapping.getTraversals(context, Policy.subMonitorFor(monitor, IProgressMonitor.UNKNOWN));
for (int i = 0; i < traversals.length; i++) {
ResourceTraversal traversal = traversals[i];
buildFilteredResourceMap(mapping, traversal, Policy.subMonitorFor(monitor, IProgressMonitor.UNKNOWN), result);
}
} catch (CoreException e) {
throw new InvocationTargetException(e);
} finally {
monitor.done();
}
}
private void buildFilteredResourceMap(final ResourceMapping mapping,
final ResourceTraversal traversal, IProgressMonitor monitor,
final Map<IResource, List<IResource>> result) throws CoreException {
traversal.accept(resource -> {
if (filter.select(resource, mapping, traversal)) {
// Add the resource to the result
result.put(resource, new ArrayList<>());
// Make sure that there are parent folders for the resource up to the traversal root
IResource child = resource;
while (!isTraversalRoot(traversal, child)) {
IContainer parent = child.getParent();
List<IResource> children = result.get(parent);
if (children == null) {
children = new ArrayList<>();
result.put(parent, children);
}
children.add(child);
child = parent;
}
}
return true;
});
}
});
} catch (InvocationTargetException e) {
TeamUIPlugin.log(IStatus.ERROR, "An error occurred while filtering " + getLabel(mapping), e); //$NON-NLS-1$
} catch (InterruptedException e) {
// Ignore
}
return result;
}
/* private */ static ResourceTraversal[] getTraversals(final ResourceMapping mapping, final ResourceMappingContext context) {
final List<ResourceTraversal[]> traversals = new ArrayList<>();
try {
PlatformUI.getWorkbench().getProgressService().busyCursorWhile(monitor -> {
try {
traversals.add(mapping.getTraversals(context, monitor));
} catch (CoreException e) {
throw new InvocationTargetException(e);
}
});
return traversals.get(0);
} catch (InvocationTargetException e) {
TeamUIPlugin.log(IStatus.ERROR, "An error occurred while traversing " + getLabel(mapping), e); //$NON-NLS-1$
} catch (InterruptedException e) {
// Ignore
}
return new ResourceTraversal[0];
}
/* private */ static IResource[] members(final IContainer container, final RemoteResourceMappingContext context) {
final List<IResource[]> members = new ArrayList<>();
try {
PlatformUI.getWorkbench().getProgressService().busyCursorWhile(monitor -> {
try {
members.add(context.fetchMembers(container, monitor));
} catch (CoreException e) {
throw new InvocationTargetException(e);
}
});
return members.get(0);
} catch (InvocationTargetException e) {
TeamUIPlugin.log(IStatus.ERROR, "An error occurred while fetching the members of" + container.getFullPath(), e); //$NON-NLS-1$
} catch (InterruptedException e) {
// Ignore
}
return new IResource[0];
}
/* private */ static boolean isTraversalRoot(ResourceTraversal traversal, IResource resource) {
IResource[] resources = traversal.getResources();
for (int i = 0; i < resources.length; i++) {
IResource root = resources[i];
if (root.equals(resource)) {
return true;
}
}
return false;
}
}