/******************************************************************************* * Copyright (c) 2008 Scott Stanchfield * 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 *******************************************************************************/ package com.javadude.workingsets; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IResourceChangeEvent; import org.eclipse.core.resources.IResourceChangeListener; import org.eclipse.core.resources.IResourceDelta; import org.eclipse.core.resources.IResourceDeltaVisitor; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IAdaptable; import org.eclipse.ui.IWorkingSet; import org.eclipse.ui.IWorkingSetUpdater; /** * Common functionality for both working set updaters. * This updater watches for changes to the workspace. In particular: * If projects are added or removed, we update the dynamic working * sets to add or remove them. This includes projects that are closed. * If a .project file is changed, assume its natures may have changed, so * update nature working sets. * * This class keeps track of all dynamic working sets that are in the * workspace, allowing us to iterate over them to update them on the fly. * @author Scott Stanchfield */ public abstract class DynamicWorkingSetUpdater implements IWorkingSetUpdater { private static final Map<Class<?>, Map<String, IWorkingSet>> workingSets_ = Collections.synchronizedMap(new HashMap<Class<?>, Map<String, IWorkingSet>>()); private String baseId_; protected abstract boolean shouldInclude(IResource resource, String workingSetId); public DynamicWorkingSetUpdater(String baseId) { baseId_ = baseId; ResourcesPlugin.getWorkspace().addResourceChangeListener(new IResourceChangeListener() { public void resourceChanged(IResourceChangeEvent event) { try { if (event.getDelta() == null) { return; } event.getDelta().accept(new IResourceDeltaVisitor() { public boolean visit(IResourceDelta delta) throws CoreException { IProject project = null; switch (delta.getKind()) { case IResourceDelta.ADDED: // if it's a project being added if (delta.getResource() instanceof IProject) { // add to appropriate working set based on project natures project = (IProject) delta.getResource(); addToWorkingSets(project, null); return false; } break; case IResourceDelta.CHANGED: // natures change or project opened/closed IResource resource = delta.getResource(); if ((resource instanceof IProject) && (delta.getFlags() & IResourceDelta.OPEN) != 0) { project = (IProject) resource; } else if (".project".equals(delta.getResource().getName())) { // natures could have changed -- might need to update the working sets project = delta.getResource().getProject(); } if (project != null) { Set<IWorkingSet> setsContainingProject = setsContainingProject(project); // add to appropriate working sets addToWorkingSets(project, setsContainingProject); for (IWorkingSet workingSet : setsContainingProject) { removeFromWorkingSet(workingSet, project); } return false; } break; case IResourceDelta.REMOVED: if (delta.getResource() instanceof IProject) { project = (IProject) delta.getResource(); // remove from all working sets Set<IWorkingSet> setsContainingProject = setsContainingProject(project); for (IWorkingSet workingSet : setsContainingProject) { removeFromWorkingSet(workingSet, project); } return false; } break; } return true; } }); } catch (CoreException e) { throw new RuntimeException(e); } } }); } protected void removeFromWorkingSet(IWorkingSet workingSet, IProject project) { IAdaptable[] elements = workingSet.getElements(); if (elements.length == 0) { return; } List<IAdaptable> newElements = new ArrayList<IAdaptable>(); boolean found = false; for (IAdaptable adaptable : elements) { if (adaptable != project) { newElements.add(adaptable); } else { found = true; } } if (!found) { return; } workingSet.setElements(newElements.toArray(new IAdaptable[newElements.size()])); } protected boolean allowClosedProjects() { return false; } protected void addToWorkingSets(IProject project, Set<IWorkingSet> setsContainingProject) { if (!allowClosedProjects() && !project.isOpen()) { return; } for (Map.Entry<String, IWorkingSet> entry : getMyWorkingSets().entrySet()) { if (shouldInclude(project, entry.getKey())) { // add project to working set IWorkingSet workingSet = entry.getValue(); if (setsContainingProject != null) { setsContainingProject.remove(workingSet); } IAdaptable[] elements = workingSet.getElements(); IAdaptable[] newElements = new IAdaptable[elements.length + 1]; System.arraycopy(elements, 0, newElements, 0, elements.length); newElements[elements.length] = project; workingSet.setElements(newElements); } } } protected Set<IWorkingSet> setsContainingProject(IProject project) { Set<IWorkingSet> workingSetsContainingProject = new HashSet<IWorkingSet>(); for (IWorkingSet workingSet : getMyWorkingSets().values()) { IAdaptable[] elements = workingSet.getElements(); for (IAdaptable element : elements) { if (element.equals(project)) { workingSetsContainingProject.add(workingSet); } } } return workingSetsContainingProject; } private String getId(IWorkingSet workingSet) { String id = workingSet.getName(); return id.substring(baseId_.length()); } public void add(IWorkingSet workingSet) { Map<String, IWorkingSet> workingSets = workingSets_.get(getClass()); if (workingSets == null) { workingSets = new HashMap<String, IWorkingSet>(); workingSets_.put(getClass(), workingSets); } workingSets.put(getId(workingSet), workingSet); } public boolean contains(IWorkingSet workingSet) { Map<String, IWorkingSet> workingSets = workingSets_.get(getClass()); if (workingSets == null) { return false; } return workingSets.values().contains(workingSet); } public void dispose() { workingSets_.remove(getClass()); } public boolean remove(IWorkingSet workingSet) { Map<String, IWorkingSet> workingSets = workingSets_.get(getClass()); if (workingSets == null) { return false; } return workingSets.remove(getId(workingSet)) != null; } private Map<String, IWorkingSet> getMyWorkingSets() { Map<String, IWorkingSet> workingSets = workingSets_.get(getClass()); if (workingSets == null) { return Collections.emptyMap(); } return workingSets; } }