dba7cae5c5060f5d271b54f18da432aab7fe2b18
[phpeclipse.git] / net.sourceforge.phpeclipse.ui / src / net / sourceforge / phpdt / internal / ui / viewsupport / ResourceToItemsMapper.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2004 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials 
4  * are made available under the terms of the Common Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/cpl-v10.html
7  * 
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  *******************************************************************************/
11 package net.sourceforge.phpdt.internal.ui.viewsupport;
12
13 import java.util.ArrayList;
14 import java.util.HashMap;
15 import java.util.List;
16 import java.util.Stack;
17
18 import net.sourceforge.phpdt.core.ICompilationUnit;
19 import net.sourceforge.phpdt.core.IJavaElement;
20
21 import org.eclipse.core.resources.IResource;
22 import org.eclipse.jface.viewers.ContentViewer;
23 import org.eclipse.jface.viewers.ILabelProvider;
24 import org.eclipse.jface.viewers.IViewerLabelProvider;
25 import org.eclipse.jface.viewers.ViewerLabel;
26 import org.eclipse.swt.graphics.Image;
27 import org.eclipse.swt.widgets.Item;
28
29 /**
30  * Helper class for updating error markers and other decorators that work on
31  * resources. Items are mapped to their element's underlying resource. Method
32  * <code>resourceChanged</code> updates all items that are affected from the
33  * changed elements.
34  */
35 public class ResourceToItemsMapper {
36
37         private static final int NUMBER_LIST_REUSE = 10;
38
39         // map from resource to item
40         private HashMap fResourceToItem;
41
42         private Stack fReuseLists;
43
44         private ContentViewer fContentViewer;
45
46         public ResourceToItemsMapper(ContentViewer viewer) {
47                 fResourceToItem = new HashMap();
48                 fReuseLists = new Stack();
49
50                 fContentViewer = viewer;
51         }
52
53         /**
54          * Must be called from the UI thread.
55          */
56         public void resourceChanged(IResource changedResource) {
57                 Object obj = fResourceToItem.get(changedResource);
58                 if (obj == null) {
59                         // not mapped
60                 } else if (obj instanceof Item) {
61                         updateItem((Item) obj);
62                 } else { // List of Items
63                         List list = (List) obj;
64                         for (int k = 0; k < list.size(); k++) {
65                                 updateItem((Item) list.get(k));
66                         }
67                 }
68         }
69
70         private void updateItem(Item item) {
71                 if (!item.isDisposed()) { // defensive code
72                         ILabelProvider lprovider = (ILabelProvider) fContentViewer
73                                         .getLabelProvider();
74
75                         Object data = item.getData();
76
77                         // If it is an IItemLabelProvider than short circuit: patch Tod (bug
78                         // 55012)
79                         if (lprovider instanceof IViewerLabelProvider) {
80                                 IViewerLabelProvider provider = (IViewerLabelProvider) lprovider;
81
82                                 ViewerLabel updateLabel = new ViewerLabel(item.getText(), item
83                                                 .getImage());
84                                 provider.updateLabel(updateLabel, data);
85
86                                 if (updateLabel.hasNewImage()) {
87                                         item.setImage(updateLabel.getImage());
88                                 }
89                                 if (updateLabel.hasNewText()) {
90                                         item.setText(updateLabel.getText());
91                                 }
92                         } else {
93                                 Image oldImage = item.getImage();
94                                 Image image = lprovider.getImage(data);
95                                 if (image != null && !image.equals(oldImage)) {
96                                         item.setImage(image);
97                                 }
98                                 String oldText = item.getText();
99                                 String text = lprovider.getText(data);
100                                 if (text != null && !text.equals(oldText)) {
101                                         item.setText(text);
102                                 }
103                         }
104                 }
105         }
106
107         /**
108          * Adds a new item to the map.
109          * 
110          * @param element
111          *            Element to map
112          * @param item
113          *            The item used for the element
114          */
115         public void addToMap(Object element, Item item) {
116                 IResource resource = getCorrespondingResource(element);
117                 if (resource != null) {
118                         Object existingMapping = fResourceToItem.get(resource);
119                         if (existingMapping == null) {
120                                 fResourceToItem.put(resource, item);
121                         } else if (existingMapping instanceof Item) {
122                                 if (existingMapping != item) {
123                                         List list = getNewList();
124                                         list.add(existingMapping);
125                                         list.add(item);
126                                         fResourceToItem.put(resource, list);
127                                 }
128                         } else { // List
129                                 List list = (List) existingMapping;
130                                 if (!list.contains(item)) {
131                                         list.add(item);
132                                 }
133                         }
134                 }
135         }
136
137         /**
138          * Removes an element from the map.
139          */
140         public void removeFromMap(Object element, Item item) {
141                 IResource resource = getCorrespondingResource(element);
142                 if (resource != null) {
143                         Object existingMapping = fResourceToItem.get(resource);
144                         if (existingMapping == null) {
145                                 return;
146                         } else if (existingMapping instanceof Item) {
147                                 fResourceToItem.remove(resource);
148                         } else { // List
149                                 List list = (List) existingMapping;
150                                 list.remove(item);
151                                 if (list.isEmpty()) {
152                                         fResourceToItem.remove(list);
153                                         releaseList(list);
154                                 }
155                         }
156                 }
157         }
158
159         private List getNewList() {
160                 if (!fReuseLists.isEmpty()) {
161                         return (List) fReuseLists.pop();
162                 }
163                 return new ArrayList(2);
164         }
165
166         private void releaseList(List list) {
167                 if (fReuseLists.size() < NUMBER_LIST_REUSE) {
168                         fReuseLists.push(list);
169                 }
170         }
171
172         /**
173          * Clears the map.
174          */
175         public void clearMap() {
176                 fResourceToItem.clear();
177         }
178
179         /**
180          * Tests if the map is empty
181          */
182         public boolean isEmpty() {
183                 return fResourceToItem.isEmpty();
184         }
185
186         /**
187          * Method that decides which elements can have error markers Returns null if
188          * an element can not have error markers.
189          */
190         private static IResource getCorrespondingResource(Object element) {
191                 if (element instanceof IJavaElement) {
192                         IJavaElement elem = (IJavaElement) element;
193                         if (!elem.isReadOnly()) { // only modifieable elements can get
194                                                                                 // error ticks
195                                 IResource res = elem.getResource();
196                                 if (res == null) {
197                                         ICompilationUnit cu = (ICompilationUnit) elem
198                                                         .getAncestor(IJavaElement.COMPILATION_UNIT);
199                                         if (cu != null) {
200                                                 // elements in compilation units are mapped to the
201                                                 // underlying resource of the original cu
202                                                 res = cu.getResource();
203                                         }
204                                 }
205                                 return res;
206                         }
207                         return null;
208                 } else if (element instanceof IResource) {
209                         return (IResource) element;
210                 }
211                 return null;
212         }
213
214 }