/******************************************************************************* * 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()]); } }