/******************************************************************************* * Copyright (c) 2000, 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.cdt.internal.ui.util; 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.jface.viewers.ContentViewer; import org.eclipse.jface.viewers.ILabelProvider; import org.eclipse.jface.viewers.IViewerLabelProvider; import org.eclipse.jface.viewers.ViewerLabel; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.widgets.Item; import org.eclipse.cdt.core.model.ICElement; import org.eclipse.cdt.core.model.ITranslationUnit; /** * Helper class for updating error markers and other decorators that work on resources. * Items are mapped to their element's underlying resource. * Method <code>resourceChanged</code> updates all items that are affected from the changed * elements. */ public class ResourceToItemsMapper { private static final int NUMBER_LIST_REUSE= 10; // map from resource to item private HashMap<IResource, Object> fResourceToItem; private Stack<List<Item>> fReuseLists; private ContentViewer fContentViewer; public ResourceToItemsMapper(ContentViewer viewer) { fResourceToItem= new HashMap<IResource, Object>(); fReuseLists= new Stack<List<Item>>(); fContentViewer= viewer; } /** * Must be called from the UI thread. */ public void resourceChanged(IResource changedResource) { Object obj= fResourceToItem.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 (int k= 0; k < list.size(); k++) { updateItem(list.get(k)); } } } private void updateItem(Item item) { if (!item.isDisposed()) { // defensive code ILabelProvider lprovider= (ILabelProvider) fContentViewer.getLabelProvider(); Object data= item.getData(); // If it is an IItemLabelProvider than short circuit: patch Tod (bug 55012) if (data != null && lprovider instanceof IViewerLabelProvider) { IViewerLabelProvider provider= (IViewerLabelProvider) lprovider; ViewerLabel updateLabel= new ViewerLabel(item.getText(), item.getImage()); provider.updateLabel(updateLabel, data); if (updateLabel.hasNewImage()) { item.setImage(updateLabel.getImage()); } if (updateLabel.hasNewText()) { item.setText(updateLabel.getText()); } } else { Image oldImage= item.getImage(); Image image= lprovider.getImage(data); if (image != null && !image.equals(oldImage)) { item.setImage(image); } String oldText= item.getText(); String text= lprovider.getText(data); if (text != null && !text.equals(oldText)) { item.setText(text); } } } } /** * Adds a new item to the map. * @param element Element to map * @param item The item used for the element */ public void addToMap(Object element, Item item) { IResource resource= getCorrespondingResource(element); if (resource != null) { Object existingMapping= fResourceToItem.get(resource); if (existingMapping == null) { fResourceToItem.put(resource, item); } else if (existingMapping instanceof Item) { if (existingMapping != item) { List<Item> list= getNewList(); list.add((Item) existingMapping); list.add(item); fResourceToItem.put(resource, list); } } else { // List @SuppressWarnings("unchecked") List<Item> list= (List<Item>) existingMapping; if (!list.contains(item)) { list.add(item); } } } } /** * Removes an element from the map. */ public void removeFromMap(Object element, Item item) { IResource resource= getCorrespondingResource(element); if (resource != null) { Object existingMapping= fResourceToItem.get(resource); if (existingMapping == null) { return; } else if (existingMapping instanceof Item) { fResourceToItem.remove(resource); } else { // List @SuppressWarnings({ "unchecked", "rawtypes" }) List<Item> list= (List) existingMapping; list.remove(item); if (list.isEmpty()) { fResourceToItem.remove(list); releaseList(list); } } } } private List<Item> getNewList() { if (!fReuseLists.isEmpty()) { return fReuseLists.pop(); } return new ArrayList<Item>(2); } private void releaseList(List<Item> list) { if (fReuseLists.size() < NUMBER_LIST_REUSE) { fReuseLists.push(list); } } /** * Clears the map. */ public void clearMap() { fResourceToItem.clear(); } /** * Tests if the map is empty */ public boolean isEmpty() { return fResourceToItem.isEmpty(); } /** * Method that decides which elements can have error markers * Returns null if an element can not have error markers. */ private static IResource getCorrespondingResource(Object element) { if (element instanceof ICElement) { ICElement elem= (ICElement) element; IResource res= elem.getResource(); if (res == null) { ITranslationUnit cu= (ITranslationUnit) elem.getAncestor(ICElement.C_UNIT); if (cu != null) { // elements in compilation units are mapped to the underlying resource of the original cu res= cu.getResource(); } } return res; } else if (element instanceof IResource) { return (IResource) element; } return null; } }