blob: b82089029a22241941f306f035d846577120fe1f [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2009 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
******************************************************************************/
package org.eclipse.ui.internal.views.markers;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
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.NullProgressMonitor;
import org.eclipse.ui.internal.ide.Policy;
import org.eclipse.ui.internal.util.Util;
import org.eclipse.ui.views.markers.internal.MarkerType;
import org.eclipse.ui.views.markers.internal.MarkerTypesModel;
import org.eclipse.ui.views.tasklist.ITaskListResourceAdapter;
/**
* A Resource helper class for the markers view code.
*
* @author hitesh soliwal
* @since 3.6
*
*/
class MarkerResourceUtil {
static final IProject[] EMPTY_PROJECT_ARRAY = new IProject[0];
/**
* Optimally gets the resources applicable to the current state of filters,
* the smaller the resources and more specific they are the less the
* filtering we have to do during processing.
*
* @return collection of resource we want to collect markers for, taking
* various enabled filters into account.
*/
static Set computeResources(IResource[] selectedResources,
Collection enabledFilters, boolean andFilters) {
IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
if (enabledFilters==null||enabledFilters.size() == 0) {
HashSet set = new HashSet(1);
set.add(root);
return set;
}
Set resourceSet = andFilters ? getResourcesFiltersAnded(enabledFilters,
selectedResources, root) : getResourcesFiltersOred(
enabledFilters, selectedResources, root);
//remove duplicates
return trim2ParentResources(root, resourceSet);
}
/**
* (optimization as side-effect): Compute common parents, if any. Remove further
* duplicates. We collect markers with a flag of DEPTH_INFINITE; so,
* effectively the children of a resource are also its duplicates.
*
* @param root
* @param resourceSet
* @return set
*/
static Set trim2ParentResources(IWorkspaceRoot root, Set resourceSet) {
if (resourceSet.isEmpty() || resourceSet.size() == 1) {
return resourceSet;
}
if (resourceSet.contains(root)) {
resourceSet.clear();
resourceSet.add(root);
return resourceSet;
}
Object[] clones = resourceSet.toArray();
for (int i = 0; i < clones.length; i++) {
IResource resource = (IResource) clones[i];
Iterator iterator = resourceSet.iterator();
while (iterator.hasNext()) {
IResource resToRemove = (IResource) iterator.next();
if (resToRemove.equals(root)) {
resourceSet.clear();
resourceSet.add(root);
return resourceSet;
}
if (resource.equals(resToRemove)) {
continue;
}
if (resource.getFullPath()
.isPrefixOf(resToRemove.getFullPath())) {
iterator.remove();
}
}
}
return resourceSet;
}
/**
* Since every filter provides it's on set of resources, instead of
* computing markers on filters individually and then ORing the markers; we
* would save a good amount of system-resources if we ORed them before
* gathering phase,removing duplicates.
*
* @param enabledFilters
* @param root
* @return set
*/
static Set getResourcesFiltersOred(Collection enabledFilters,
IResource[] selectedResources, IWorkspaceRoot root) {
if (enabledFilters==null||enabledFilters.size() == 0) {
HashSet set = new HashSet(1);
set.add(root);
return set;
}
Set resourceSet = new HashSet();
Iterator filtersIterator = enabledFilters.iterator();
while (filtersIterator.hasNext()) {
MarkerFieldFilterGroup group = (MarkerFieldFilterGroup) filtersIterator
.next();
Set set = getResourcesForFilter(group, selectedResources, root);
resourceSet.addAll(set);
if (resourceSet.contains(root)) {
set = new HashSet(1);
set.add(root);
return set;
}
}
return resourceSet;
}
/**
* The method may look long and a little time-consuming, but it actually
* performs a short-circuit AND operation on the resources, and therefore
* quick.
*
* Note: This is an optimization; we could have ORed the resources instead.
* Let us say, for example, we had a filter of workspace-scope(ANY), and
* others of scope on Selected element and maybe others.Now, if we computed
* markers by ORing the resources, then we would compute markers for the
* entire Workspace. The filters would anyways keep only the markers that
* are an intersection of all resources (filter by scope) .In other words,
* we spend more system-resources in both gathering and filtering.If we
* ANDed the scopes(resources) we'd, save a good amount of system-resources
* in both phases.
*
* @param enabledFilters
* @param selectedResources
* @param root
* @return set
*/
static Set getResourcesFiltersAnded(Collection enabledFilters,
IResource[] selectedResources, IWorkspaceRoot root) {
if (enabledFilters==null||enabledFilters.size() == 0) {
HashSet set = new HashSet(1);
set.add(root);
return set;
}
Set resourceSet = new HashSet();
Iterator filtersIterator = enabledFilters.iterator();
Set removeMain = new HashSet();
while (filtersIterator.hasNext()) {
MarkerFieldFilterGroup group = (MarkerFieldFilterGroup) filtersIterator
.next();
Set set = getResourcesForFilter(group, selectedResources, root);
if (resourceSet.isEmpty()) {
// first time
resourceSet.addAll(set);
} else {
Iterator resIterator = resourceSet.iterator();
while (resIterator.hasNext()) {
boolean remove = true;
IResource mainRes = (IResource) resIterator.next();
Iterator iterator = set.iterator();
while (iterator.hasNext() && remove) {
IResource grpRes = (IResource) iterator.next();
remove = !grpRes.equals(mainRes);
if (remove
&& grpRes.getFullPath().isPrefixOf(
mainRes.getFullPath())) {
remove = false;
} else if (remove
&& mainRes.getFullPath().isPrefixOf(
grpRes.getFullPath())) {
remove = false;
removeMain.add(mainRes);
}
}
if (remove) {
resIterator.remove();
}
}
Iterator iterator = set.iterator();
while (iterator.hasNext()) {
boolean remove = true;
IResource grpRes = (IResource) iterator.next();
resIterator = resourceSet.iterator();
while (resIterator.hasNext()&&remove) {
IResource mainRes = (IResource) resIterator.next();
remove = !grpRes.equals(mainRes);
if (remove
&& mainRes.getFullPath().isPrefixOf(
grpRes.getFullPath())) {
remove = false;
}
}
if (remove) {
iterator.remove();
}
}
resourceSet.addAll(set);
resourceSet.removeAll(removeMain);
removeMain.clear();
if (resourceSet.isEmpty()) {
// if the And between two is empty
// then its empty for all
return resourceSet;
}
}
}
return resourceSet;
}
/**
* Get the resources indicated by the filter's scope.
*
* @param group
* @param selectedResources
* @param root
*/
static Set getResourcesForFilter(MarkerFieldFilterGroup group,
IResource[] selectedResources, IWorkspaceRoot root) {
HashSet resourceSet = new HashSet();
switch (group.getScope()) {
case MarkerFieldFilterGroup.ON_ANY: {
resourceSet.add(root);
break;
}
case MarkerFieldFilterGroup.ON_SELECTED_ONLY:
case MarkerFieldFilterGroup.ON_SELECTED_AND_CHILDREN: {
for (int i = 0; i < selectedResources.length; i++) {
resourceSet.add(selectedResources[i]);
}
break;
}
case MarkerFieldFilterGroup.ON_ANY_IN_SAME_CONTAINER: {
IResource[] resources = getProjects(selectedResources);
for (int i = 0; i < resources.length; i++) {
resourceSet.add(resources[i]);
}
break;
}
case MarkerFieldFilterGroup.ON_WORKING_SET: {
group.refresh();
IResource[] resources = group.getResourcesInWorkingSet();
for (int i = 0; i < resources.length; i++) {
resourceSet.add(resources[i]);
}
break;
}
}
return resourceSet;
}
/**
* Returns the set of projects that contain the given set of resources.
*
* @param resources
* @return IProject[]
*/
static IProject[] getProjects(IResource[] resources) {
if (resources == null)
return EMPTY_PROJECT_ARRAY;
Collection projects = getProjectsAsCollection(resources);
return (IProject[]) projects.toArray(new IProject[projects.size()]);
}
/**
* Return the projects for the elements.
*
* @param elements
* collection of IResource or IResourceMapping
* @return Collection of IProject
*/
static Collection getProjectsAsCollection(Object[] elements) {
HashSet projects = new HashSet();
for (int idx = 0; idx < elements.length; idx++) {
if (elements[idx] instanceof IResource) {
projects.add(((IResource) elements[idx]).getProject());
} else {
IProject[] mappingProjects = (((ResourceMapping) elements[idx])
.getProjects());
for (int i = 0; i < mappingProjects.length; i++) {
projects.add(mappingProjects[i]);
}
}
}
return projects;
}
/**
* Add the resources in resourceMapping to the resourceCollection
*
* @param resourceCollection
* @param resourceMapping
*/
static void addResources(Collection resourceCollection,
ResourceMapping resourceMapping) {
try {
ResourceTraversal[] traversals = resourceMapping.getTraversals(
ResourceMappingContext.LOCAL_CONTEXT,
new NullProgressMonitor());
for (int i = 0; i < traversals.length; i++) {
ResourceTraversal traversal = traversals[i];
IResource[] result = traversal.getResources();
for (int j = 0; j < result.length; j++) {
resourceCollection.add(result[j]);
}
}
} catch (CoreException e) {
Policy.handle(e);
}
}
/**
* Adapts an object to a resource or resource mapping;
* If the object cannot be adapted,it return null.
* The method uses {@link Util#getAdapter(Object, Class)}
* The scheme for adapting follows the sequence
* If instance of {@link IAdaptable}, query ITaskListResourceAdapter
* if available for the object.
* Try to adapt to an IResource
* Try to adapt to an IFile
* Finally try adapting to a ResourceMapping
*
* @param object
*/
static Object adapt2ResourceElement(Object object) {
IResource resource = null;
if (object instanceof IAdaptable) {
Object adapter = Util.getAdapter(object,
ITaskListResourceAdapter.class);
if (adapter != null) {
resource = ((ITaskListResourceAdapter) adapter)
.getAffectedResource((IAdaptable) object);
}
}
if (resource == null) {
resource = (IResource) Util.getAdapter(object, IResource.class);
}
if (resource == null) {
resource = (IResource) Util.getAdapter(object, IFile.class);
}
if (resource == null) {
Object mapping = Util.getAdapter(object, ResourceMapping.class);
if (mapping != null) {
return mapping;
}
} else {
return resource;
}
return null;
}
/**
* Gets all sub-type id(s) including self, for the list of marker typeIds
*
* @param typeIds
*/
static String[] getAllSubTypesIds(String[] typeIds) {
HashSet set = getAllSubTypes(typeIds);
return toTypeStrings(set);
}
/**
* Gets all sub-types {@link MarkerType} including self for the list of
* marker typeIds
*
* @param typeIds
*/
static HashSet getAllSubTypes(String[] typeIds) {
HashSet set = new HashSet();
MarkerTypesModel typesModel = MarkerTypesModel.getInstance();
for (int i = 0; i < typeIds.length; i++) {
MarkerType type = typesModel.getType(typeIds[i]);
set.add(type);
MarkerType[] subs = type.getAllSubTypes();
for (int j = 0; j < subs.length; j++) {
set.add(subs[j]);
}
}
return set;
}
/**
* Gets mutually exclusive super-types ids for the list of
* marker typeIds
*
* @param typeIds
*/
static String[] getMutuallyExclusiveSupersIds(String[] typeIds) {
HashSet set = getMutuallyExclusiveSupers(typeIds);
return toTypeStrings(set);
}
/**
* Gets mutually exclusive super-types {@link MarkerType} for the list of
* marker typeIds
*
* @param typeIds
*/
static HashSet getMutuallyExclusiveSupers(String[] typeIds) {
HashSet set = new HashSet();
MarkerTypesModel typesModel = MarkerTypesModel.getInstance();
for (int i = 0; i < typeIds.length; i++) {
MarkerType type = typesModel.getType(typeIds[i]);
set.add(type);
}
for (int i = 0; i < typeIds.length; i++) {
MarkerType type = typesModel.getType(typeIds[i]);
MarkerType[] subs = type.getAllSubTypes();
HashSet subsOnly = new HashSet(Arrays.asList(subs));
subsOnly.remove(type);
set.removeAll(subsOnly);
}
return set;
}
/**
* Converts a collection of {@link MarkerType} into an array of marker
* typeIds
*
* @param collection
*/
private static String[] toTypeStrings(Collection collection) {
HashSet ids = new HashSet();
Iterator iterator = collection.iterator();
while (iterator.hasNext()) {
MarkerType type = (MarkerType) iterator.next();
ids.add(type.getId());
}
return (String[]) ids.toArray(new String[ids.size()]);
}
}