/******************************************************************************* * Copyright (c) 2000, 2007 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 * *******************************************************************************/ package org.eclipse.dltk.internal.ui.workingsets; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.IdentityHashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.Assert; import org.eclipse.core.runtime.IAdaptable; import org.eclipse.core.runtime.ListenerList; import org.eclipse.dltk.core.IScriptProject; import org.eclipse.jface.util.IPropertyChangeListener; import org.eclipse.jface.util.PropertyChangeEvent; import org.eclipse.jface.viewers.IElementComparer; import org.eclipse.ui.ILocalWorkingSetManager; import org.eclipse.ui.IMemento; import org.eclipse.ui.IWorkingSet; import org.eclipse.ui.IWorkingSetManager; import org.eclipse.ui.IWorkingSetUpdater; import org.eclipse.ui.PlatformUI; public class WorkingSetModel { public static final String CHANGE_WORKING_SET_MODEL_CONTENT = "workingSetModelChanged"; //$NON-NLS-1$ public static final IElementComparer COMPARER = new WorkingSetComparar(); private static final String TAG_LOCAL_WORKING_SET_MANAGER = "localWorkingSetManager"; //$NON-NLS-1$ private static final String TAG_ACTIVE_WORKING_SET = "activeWorkingSet"; //$NON-NLS-1$ private static final String TAG_WORKING_SET_NAME = "workingSetName"; //$NON-NLS-1$ private static final String TAG_CONFIGURED = "configured"; //$NON-NLS-1$ private ILocalWorkingSetManager fLocalWorkingSetManager; private List<IWorkingSet> fActiveWorkingSets; private ListenerList fListeners; private IPropertyChangeListener fWorkingSetManagerListener; private OthersWorkingSetUpdater fOthersWorkingSetUpdater; private ElementMapper fElementMapper = new ElementMapper(); private boolean fConfigured; private static class WorkingSetComparar implements IElementComparer { public boolean equals(Object o1, Object o2) { IWorkingSet w1 = o1 instanceof IWorkingSet ? (IWorkingSet) o1 : null; IWorkingSet w2 = o2 instanceof IWorkingSet ? (IWorkingSet) o2 : null; if (w1 == null || w2 == null) return o1.equals(o2); return w1 == w2; } public int hashCode(Object element) { if (element instanceof IWorkingSet) return System.identityHashCode(element); return element.hashCode(); } } private static class ElementMapper { private Map fElementToWorkingSet = new HashMap(); private Map fWorkingSetToElement = new IdentityHashMap(); private Map fResourceToWorkingSet = new HashMap(); private List fNonProjectTopLevelElements = new ArrayList(); public void clear() { fElementToWorkingSet.clear(); fWorkingSetToElement.clear(); fResourceToWorkingSet.clear(); fNonProjectTopLevelElements.clear(); } public void rebuild(IWorkingSet[] workingSets) { clear(); for (int i = 0; i < workingSets.length; i++) { put(workingSets[i]); } } public IAdaptable[] remove(IWorkingSet ws) { IAdaptable[] elements = (IAdaptable[]) fWorkingSetToElement .remove(ws); if (elements != null) { for (int i = 0; i < elements.length; i++) { removeElement(elements[i], ws); } } return elements; } public IAdaptable[] refresh(IWorkingSet ws) { IAdaptable[] oldElements = (IAdaptable[]) fWorkingSetToElement .get(ws); if (oldElements == null) return null; IAdaptable[] newElements = ws.getElements(); List toRemove = new ArrayList(Arrays.asList(oldElements)); List toAdd = new ArrayList(Arrays.asList(newElements)); computeDelta(toRemove, toAdd, oldElements, newElements); for (Iterator iter = toAdd.iterator(); iter.hasNext();) { addElement((IAdaptable) iter.next(), ws); } for (Iterator iter = toRemove.iterator(); iter.hasNext();) { removeElement((IAdaptable) iter.next(), ws); } if (toRemove.size() > 0 || toAdd.size() > 0) fWorkingSetToElement.put(ws, newElements); return oldElements; } private void computeDelta(List toRemove, List toAdd, IAdaptable[] oldElements, IAdaptable[] newElements) { for (int i = 0; i < oldElements.length; i++) { toAdd.remove(oldElements[i]); } for (int i = 0; i < newElements.length; i++) { toRemove.remove(newElements[i]); } } public IWorkingSet getFirstWorkingSet(Object element) { return (IWorkingSet) getFirstElement(fElementToWorkingSet, element); } public List getAllWorkingSets(Object element) { return getAllElements(fElementToWorkingSet, element); } public IWorkingSet getFirstWorkingSetForResource(IResource resource) { return (IWorkingSet) getFirstElement(fResourceToWorkingSet, resource); } public List getAllWorkingSetsForResource(IResource resource) { return getAllElements(fResourceToWorkingSet, resource); } public List getNonProjectTopLevelElements() { return fNonProjectTopLevelElements; } private void put(IWorkingSet ws) { if (fWorkingSetToElement.containsKey(ws)) return; IAdaptable[] elements = ws.getElements(); fWorkingSetToElement.put(ws, elements); for (int i = 0; i < elements.length; i++) { IAdaptable element = elements[i]; addElement(element, ws); if (!(element instanceof IProject) && !(element instanceof IScriptProject)) { fNonProjectTopLevelElements.add(element); } } } private void addElement(IAdaptable element, IWorkingSet ws) { addToMap(fElementToWorkingSet, element, ws); IResource resource = (IResource) element .getAdapter(IResource.class); if (resource != null) { addToMap(fResourceToWorkingSet, resource, ws); } } private void removeElement(IAdaptable element, IWorkingSet ws) { removeFromMap(fElementToWorkingSet, element, ws); IResource resource = (IResource) element .getAdapter(IResource.class); if (resource != null) { removeFromMap(fResourceToWorkingSet, resource, ws); } } private void addToMap(Map map, IAdaptable key, IWorkingSet value) { Object obj = map.get(key); if (obj == null) { map.put(key, value); } else if (obj instanceof IWorkingSet) { List l = new ArrayList(2); l.add(obj); l.add(value); map.put(key, l); } else if (obj instanceof List) { ((List) obj).add(value); } } private void removeFromMap(Map map, IAdaptable key, IWorkingSet value) { Object current = map.get(key); if (current == null) { return; } else if (current instanceof List) { List list = (List) current; list.remove(value); switch (list.size()) { case 0: map.remove(key); break; case 1: map.put(key, list.get(0)); break; } } else if (current == value) { map.remove(key); } } private Object getFirstElement(Map map, Object key) { Object obj = map.get(key); if (obj instanceof List) return ((List) obj).get(0); return obj; } private List getAllElements(Map map, Object key) { Object obj = map.get(key); if (obj instanceof List) return (List) obj; if (obj == null) return Collections.EMPTY_LIST; List result = new ArrayList(1); result.add(obj); return result; } } public WorkingSetModel(IMemento memento) { fLocalWorkingSetManager = PlatformUI.getWorkbench() .createLocalWorkingSetManager(); addListenersToWorkingSetManagers(); fActiveWorkingSets = new ArrayList<IWorkingSet>(2); if (memento == null || !restoreState(memento)) { IWorkingSet others = fLocalWorkingSetManager.createWorkingSet( WorkingSetMessages.WorkingSetModel_others_name, new IAdaptable[0]); others.setId(WorkingSetIDs.OTHERS); fLocalWorkingSetManager.addWorkingSet(others); fActiveWorkingSets.add(others); } Assert.isNotNull(fOthersWorkingSetUpdater); fElementMapper.rebuild(getActiveWorkingSets()); fOthersWorkingSetUpdater.updateElements(); } private void addListenersToWorkingSetManagers() { fListeners = new ListenerList(ListenerList.IDENTITY); fWorkingSetManagerListener = new IPropertyChangeListener() { public void propertyChange(PropertyChangeEvent event) { workingSetManagerChanged(event); } }; PlatformUI.getWorkbench().getWorkingSetManager() .addPropertyChangeListener(fWorkingSetManagerListener); fLocalWorkingSetManager .addPropertyChangeListener(fWorkingSetManagerListener); } public void dispose() { if (fWorkingSetManagerListener != null) { PlatformUI.getWorkbench().getWorkingSetManager() .removePropertyChangeListener(fWorkingSetManagerListener); fLocalWorkingSetManager .removePropertyChangeListener(fWorkingSetManagerListener); fLocalWorkingSetManager.dispose(); fWorkingSetManagerListener = null; } } // ---- model relationships --------------------------------------- public IAdaptable[] getChildren(IWorkingSet workingSet) { return workingSet.getElements(); } public Object getParent(Object element) { if (element instanceof IWorkingSet && fActiveWorkingSets.contains(element)) return this; return fElementMapper.getFirstWorkingSet(element); } public Object[] getAllParents(Object element) { if (element instanceof IWorkingSet && fActiveWorkingSets.contains(element)) return new Object[] { this }; return fElementMapper.getAllWorkingSets(element).toArray(); } public Object[] addWorkingSets(Object[] elements) { List result = null; for (int i = 0; i < elements.length; i++) { Object element = elements[i]; List sets = null; if (element instanceof IResource) { sets = fElementMapper .getAllWorkingSetsForResource((IResource) element); } else { sets = fElementMapper.getAllWorkingSets(element); } if (sets != null && sets.size() > 0) { if (result == null) result = new ArrayList(Arrays.asList(elements)); result.addAll(sets); } } if (result == null) return elements; return result.toArray(); } public boolean needsConfiguration() { return !fConfigured && fActiveWorkingSets.size() == 1 && WorkingSetIDs.OTHERS.equals(fActiveWorkingSets.get(0) .getId()); } public void configured() { fConfigured = true; } // ---- working set management ----------------------------------- /** * Adds a property change listener. * * @param listener * the property change listener to add */ public void addPropertyChangeListener(IPropertyChangeListener listener) { fListeners.add(listener); } /** * Removes the property change listener. * * @param listener * the property change listener to remove */ public void removePropertyChangeListener(IPropertyChangeListener listener) { fListeners.remove(listener); } public IWorkingSet[] getActiveWorkingSets() { return fActiveWorkingSets.toArray(new IWorkingSet[fActiveWorkingSets .size()]); } public IWorkingSet[] getAllWorkingSets() { List<IWorkingSet> result = new ArrayList<IWorkingSet>(); result.addAll(fActiveWorkingSets); IWorkingSet[] locals = fLocalWorkingSetManager.getWorkingSets(); for (int i = 0; i < locals.length; i++) { if (!result.contains(locals[i])) result.add(locals[i]); } IWorkingSet[] globals = PlatformUI.getWorkbench() .getWorkingSetManager().getWorkingSets(); for (int i = 0; i < globals.length; i++) { if (!result.contains(globals[i])) result.add(globals[i]); } return result.toArray(new IWorkingSet[result.size()]); } public void setActiveWorkingSets(IWorkingSet[] workingSets) { fActiveWorkingSets = new ArrayList<IWorkingSet>(Arrays .asList(workingSets)); fElementMapper.rebuild(getActiveWorkingSets()); fOthersWorkingSetUpdater.updateElements(); fireEvent(new PropertyChangeEvent(this, CHANGE_WORKING_SET_MODEL_CONTENT, null, null)); } public void saveState(IMemento memento) { memento.putString(TAG_CONFIGURED, Boolean.toString(fConfigured)); fLocalWorkingSetManager.saveState(memento .createChild(TAG_LOCAL_WORKING_SET_MANAGER)); for (Iterator iter = fActiveWorkingSets.iterator(); iter.hasNext();) { IMemento active = memento.createChild(TAG_ACTIVE_WORKING_SET); IWorkingSet workingSet = (IWorkingSet) iter.next(); active.putString(TAG_WORKING_SET_NAME, workingSet.getName()); } } public List getNonProjectTopLevelElements() { return fElementMapper.getNonProjectTopLevelElements(); } private boolean restoreState(IMemento memento) { String configured = memento.getString(TAG_CONFIGURED); if (configured == null) { return false; } fConfigured = Boolean.valueOf(configured).booleanValue(); final IMemento wsManagerMemento = memento .getChild(TAG_LOCAL_WORKING_SET_MANAGER); if (wsManagerMemento != null) { fLocalWorkingSetManager.restoreState(wsManagerMemento); } IMemento[] actives = memento.getChildren(TAG_ACTIVE_WORKING_SET); for (int i = 0; i < actives.length; i++) { String name = actives[i].getString(TAG_WORKING_SET_NAME); if (name != null) { IWorkingSet ws = fLocalWorkingSetManager.getWorkingSet(name); if (ws == null) { ws = PlatformUI.getWorkbench().getWorkingSetManager() .getWorkingSet(name); } if (ws != null) { fActiveWorkingSets.add(ws); } } } return true; } private void workingSetManagerChanged(PropertyChangeEvent event) { String property = event.getProperty(); if (IWorkingSetManager.CHANGE_WORKING_SET_UPDATER_INSTALLED .equals(property) && event.getSource() == fLocalWorkingSetManager) { IWorkingSetUpdater updater = (IWorkingSetUpdater) event .getNewValue(); if (updater instanceof OthersWorkingSetUpdater) { fOthersWorkingSetUpdater = (OthersWorkingSetUpdater) updater; fOthersWorkingSetUpdater.init(this); } return; } // don't handle working sets not managed by the model if (!isAffected(event)) return; if (IWorkingSetManager.CHANGE_WORKING_SET_CONTENT_CHANGE .equals(property)) { IWorkingSet workingSet = (IWorkingSet) event.getNewValue(); IAdaptable[] elements = fElementMapper.refresh(workingSet); if (elements != null) { fireEvent(event); } } else if (IWorkingSetManager.CHANGE_WORKING_SET_REMOVE .equals(property)) { IWorkingSet workingSet = (IWorkingSet) event.getOldValue(); List<IWorkingSet> elements = new ArrayList<IWorkingSet>( fActiveWorkingSets); elements.remove(workingSet); setActiveWorkingSets(elements.toArray(new IWorkingSet[elements .size()])); } else if (IWorkingSetManager.CHANGE_WORKING_SET_NAME_CHANGE .equals(property)) { fireEvent(event); } } private void fireEvent(PropertyChangeEvent event) { Object[] listeners = fListeners.getListeners(); for (int i = 0; i < listeners.length; i++) { ((IPropertyChangeListener) listeners[i]).propertyChange(event); } } private boolean isAffected(PropertyChangeEvent event) { if (fActiveWorkingSets == null) return false; Object oldValue = event.getOldValue(); Object newValue = event.getNewValue(); if ((oldValue != null && fActiveWorkingSets.contains(oldValue)) || (newValue != null && fActiveWorkingSets.contains(newValue))) { return true; } return false; } public boolean isActiveWorkingSet(IWorkingSet changedWorkingSet) { return fActiveWorkingSets.contains(changedWorkingSet); } }