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