/******************************************************************************* * Copyright (c) 2000, 2016 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.navigator.resources; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Stack; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.Adapters; import org.eclipse.swt.widgets.Item; import org.eclipse.ui.navigator.CommonViewer; import org.eclipse.ui.navigator.ICommonViewerMapper; /** * Adds a supplemental map for the CommonViewer to efficiently handle resource * changes. When objects are added to the Viewer's map, this is called to see * if there is an associated resource. If so, it's added to the map here. * When resource change notifications happen, this map is checked, and if the * resource is found, this class causes the Viewer to be updated. If the * resource is not found, the notification can be ignored because the object * corresponding to the resource is not present in the viewer. * */ public class ResourceToItemsMapper implements ICommonViewerMapper { private static final int NUMBER_LIST_REUSE = 10; // map from resource to item. Value can be single Item of List<Item> private HashMap<IResource, Object> _resourceToItem; private Stack<List<Item>> _reuseLists; private CommonViewer _commonViewer; public ResourceToItemsMapper(CommonViewer viewer) { _resourceToItem = new HashMap<IResource, Object>(); _reuseLists = new Stack<List<Item>>(); _commonViewer = viewer; viewer.setMapper(this); } @Override public void addToMap(Object element, Item item) { IResource resource = getCorrespondingResource(element); if (resource != null) { Object existingMapping = _resourceToItem.get(resource); if (existingMapping == null) { _resourceToItem.put(resource, item); } else if (existingMapping instanceof Item) { if (existingMapping != item) { List<Item> list = getNewList(); list.add((Item)existingMapping); list.add(item); _resourceToItem.put(resource, list); } } else { // List @SuppressWarnings("unchecked") List<Item> list = (List<Item>) existingMapping; if (!list.contains(item)) { list.add(item); } } } } @Override public void removeFromMap(Object element, Item item) { IResource resource = getCorrespondingResource(element); if (resource != null) { Object existingMapping = _resourceToItem.get(resource); if (existingMapping == null) { return; } else if (existingMapping instanceof Item) { _resourceToItem.remove(resource); } else { // List @SuppressWarnings("unchecked") List<Item> list = (List<Item>) existingMapping; list.remove(item); if (list.isEmpty()) { _resourceToItem.remove(resource); releaseList(list); } } } } @Override public void clearMap() { _resourceToItem.clear(); } @Override public boolean isEmpty() { return _resourceToItem.isEmpty(); } private List<Item> getNewList() { if (!_reuseLists.isEmpty()) { return _reuseLists.pop(); } return new ArrayList<Item>(2); } private void releaseList(List<Item> list) { if (_reuseLists.size() < NUMBER_LIST_REUSE) { _reuseLists.push(list); } } @Override public boolean handlesObject(Object object) { return object instanceof IResource; } /** * Must be called from the UI thread. * * @param changedResource * Changed resource */ @Override public void objectChanged(Object changedResource) { Object obj = _resourceToItem.get(changedResource); if (obj == null) { // not mapped } else if (obj instanceof Item) { updateItem((Item) obj); } else { // List of Items @SuppressWarnings("unchecked") List<Item> list = (List<Item>) obj; for (Item item : list) { updateItem(item); } } } private void updateItem(Item item) { if (!item.isDisposed()) { _commonViewer.doUpdateItem(item); } } private static IResource getCorrespondingResource(Object element) { return Adapters.adapt(element, IResource.class); } }