--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package net.sourceforge.phpdt.internal.ui.viewsupport;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Stack;
+
+import net.sourceforge.phpdt.core.ICompilationUnit;
+import net.sourceforge.phpdt.core.IJavaElement;
+
+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;
+
+/**
+ * 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 fResourceToItem;
+
+ private Stack fReuseLists;
+
+ private ContentViewer fContentViewer;
+
+ public ResourceToItemsMapper(ContentViewer viewer) {
+ fResourceToItem = new HashMap();
+ fReuseLists = new Stack();
+
+ 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
+ List list = (List) obj;
+ for (int k = 0; k < list.size(); k++) {
+ updateItem((Item) 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 (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 list = getNewList();
+ list.add(existingMapping);
+ list.add(item);
+ fResourceToItem.put(resource, list);
+ }
+ } else { // List
+ List list = (List) 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
+ List list = (List) existingMapping;
+ list.remove(item);
+ if (list.isEmpty()) {
+ fResourceToItem.remove(list);
+ releaseList(list);
+ }
+ }
+ }
+ }
+
+ private List getNewList() {
+ if (!fReuseLists.isEmpty()) {
+ return (List) fReuseLists.pop();
+ }
+ return new ArrayList(2);
+ }
+
+ private void releaseList(List 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 IJavaElement) {
+ IJavaElement elem = (IJavaElement) element;
+ if (!elem.isReadOnly()) { // only modifieable elements can get
+ // error ticks
+ IResource res = elem.getResource();
+ if (res == null) {
+ ICompilationUnit cu = (ICompilationUnit) elem
+ .getAncestor(IJavaElement.COMPILATION_UNIT);
+ if (cu != null) {
+ // elements in compilation units are mapped to the
+ // underlying resource of the original cu
+ res = cu.getResource();
+ }
+ }
+ return res;
+ }
+ return null;
+ } else if (element instanceof IResource) {
+ return (IResource) element;
+ }
+ return null;
+ }
+
+}