Applying pteague's patch (re #685)
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / ui / text / JavaAnnotationHover.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2003 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.text;
12
13 import java.util.ArrayList;
14 import java.util.HashMap;
15 import java.util.Iterator;
16 import java.util.List;
17 import java.util.Map;
18
19 import net.sourceforge.phpdt.internal.corext.Assert;
20 import net.sourceforge.phpdt.internal.ui.PHPUIMessages;
21 import net.sourceforge.phpeclipse.PHPeclipsePlugin;
22
23 import org.eclipse.jface.preference.IPreferenceStore;
24 import org.eclipse.jface.text.BadLocationException;
25 import org.eclipse.jface.text.IDocument;
26 import org.eclipse.jface.text.Position;
27 import org.eclipse.jface.text.source.Annotation;
28 import org.eclipse.jface.text.source.IAnnotationHover;
29 import org.eclipse.jface.text.source.IAnnotationModel;
30 import org.eclipse.jface.text.source.ISourceViewer;
31 import org.eclipse.ui.editors.text.EditorsUI;
32 import org.eclipse.ui.texteditor.AnnotationPreference;
33
34 /**
35  * Determines all markers for the given line and collects, concatenates, and
36  * formates their messages.
37  */
38 public class JavaAnnotationHover implements IAnnotationHover {
39         private static class JavaAnnotationHoverType {
40         }
41
42         public static final JavaAnnotationHoverType OVERVIEW_RULER_HOVER = new JavaAnnotationHoverType();
43
44         public static final JavaAnnotationHoverType TEXT_RULER_HOVER = new JavaAnnotationHoverType();
45
46         public static final JavaAnnotationHoverType VERTICAL_RULER_HOVER = new JavaAnnotationHoverType();
47
48         // private IPreferenceStore fStore =
49         // PHPeclipsePlugin.getDefault().getPreferenceStore();
50         private IPreferenceStore fStore = EditorsUI.getPreferenceStore();
51
52         private JavaAnnotationHoverType fType;
53
54         public JavaAnnotationHover(JavaAnnotationHoverType type) {
55                 Assert.isTrue(OVERVIEW_RULER_HOVER.equals(type)
56                                 || TEXT_RULER_HOVER.equals(type)
57                                 || VERTICAL_RULER_HOVER.equals(type));
58                 fType = type;
59         }
60
61         /**
62          * Returns the distance to the ruler line.
63          */
64         protected int compareRulerLine(Position position, IDocument document,
65                         int line) {
66
67                 if (position.getOffset() > -1 && position.getLength() > -1) {
68                         try {
69                                 int javaAnnotationLine = document.getLineOfOffset(position
70                                                 .getOffset());
71                                 if (line == javaAnnotationLine)
72                                         return 1;
73                                 if (javaAnnotationLine <= line
74                                                 && line <= document.getLineOfOffset(position
75                                                                 .getOffset()
76                                                                 + position.getLength()))
77                                         return 2;
78                         } catch (BadLocationException x) {
79                         }
80                 }
81
82                 return 0;
83         }
84
85         /**
86          * Selects a set of markers from the two lists. By default, it just returns
87          * the set of exact matches.
88          */
89         protected List select(List exactMatch, List including) {
90                 return exactMatch;
91         }
92
93         /**
94          * Returns one marker which includes the ruler's line of activity.
95          */
96         protected List getJavaAnnotationsForLine(ISourceViewer viewer, int line) {
97
98                 IDocument document = viewer.getDocument();
99                 IAnnotationModel model = viewer.getAnnotationModel();
100
101                 if (model == null)
102                         return null;
103
104                 List exact = new ArrayList();
105                 List including = new ArrayList();
106
107                 Iterator e = model.getAnnotationIterator();
108                 HashMap messagesAtPosition = new HashMap();
109                 while (e.hasNext()) {
110                         Annotation annotation = (Annotation) e.next();
111
112                         if (annotation.getText() == null)
113                                 continue;
114
115                         Position position = model.getPosition(annotation);
116                         if (position == null)
117                                 continue;
118
119                         AnnotationPreference preference = getAnnotationPreference(annotation);
120                         if (preference == null)
121                                 continue;
122
123                         if (OVERVIEW_RULER_HOVER.equals(fType)) {
124                                 String key = preference.getOverviewRulerPreferenceKey();
125                                 if (key == null || !fStore.getBoolean(key))
126                                         continue;
127                         } else if (TEXT_RULER_HOVER.equals(fType)) {
128                                 String key = preference.getTextPreferenceKey();
129                                 if (key != null) {
130                                         if (!fStore.getBoolean(key))
131                                                 continue;
132                                 } else {
133                                         key = preference.getHighlightPreferenceKey();
134                                         if (key == null || !fStore.getBoolean(key))
135                                                 continue;
136                                 }
137                         } else if (VERTICAL_RULER_HOVER.equals(fType)) {
138                                 String key = preference.getVerticalRulerPreferenceKey();
139                                 // backward compatibility
140                                 if (key != null && !fStore.getBoolean(key))
141                                         continue;
142                         }
143
144                         if (isDuplicateJavaAnnotation(messagesAtPosition, position,
145                                         annotation.getText()))
146                                 continue;
147
148                         switch (compareRulerLine(position, document, line)) {
149                         case 1:
150                                 exact.add(annotation);
151                                 break;
152                         case 2:
153                                 including.add(annotation);
154                                 break;
155                         }
156                 }
157
158                 return select(exact, including);
159         }
160
161         // /**
162         // * Returns one marker which includes the ruler's line of activity.
163         // */
164         // protected List getJavaAnnotationsForLine(ISourceViewer viewer, int line)
165         // {
166         //              
167         // IDocument document= viewer.getDocument();
168         // IAnnotationModel model= viewer.getAnnotationModel();
169         //              
170         // if (model == null)
171         // return null;
172         //                      
173         // List exact= new ArrayList();
174         // List including= new ArrayList();
175         //              
176         // Iterator e= model.getAnnotationIterator();
177         // HashMap messagesAtPosition= new HashMap();
178         // while (e.hasNext()) {
179         // Object o= e.next();
180         // if (o instanceof IJavaAnnotation) {
181         // IJavaAnnotation a= (IJavaAnnotation)o;
182         // if (!a.hasOverlay()) {
183         // Position position= model.getPosition((Annotation)a);
184         // if (position == null)
185         // continue;
186         //
187         // if (isDuplicateJavaAnnotation(messagesAtPosition, position,
188         // a.getMessage()))
189         // continue;
190         //      
191         // switch (compareRulerLine(position, document, line)) {
192         // case 1:
193         // exact.add(a);
194         // break;
195         // case 2:
196         // including.add(a);
197         // break;
198         // }
199         // }
200         // }
201         // }
202         //              
203         // return select(exact, including);
204         // }
205
206         private boolean isDuplicateJavaAnnotation(Map messagesAtPosition,
207                         Position position, String message) {
208                 if (messagesAtPosition.containsKey(position)) {
209                         Object value = messagesAtPosition.get(position);
210                         if (message.equals(value))
211                                 return true;
212
213                         if (value instanceof List) {
214                                 List messages = (List) value;
215                                 if (messages.contains(message))
216                                         return true;
217                                 else
218                                         messages.add(message);
219                         } else {
220                                 ArrayList messages = new ArrayList();
221                                 messages.add(value);
222                                 messages.add(message);
223                                 messagesAtPosition.put(position, messages);
224                         }
225                 } else
226                         messagesAtPosition.put(position, message);
227                 return false;
228         }
229
230         /*
231          * @see IVerticalRulerHover#getHoverInfo(ISourceViewer, int)
232          */
233         public String getHoverInfo(ISourceViewer sourceViewer, int lineNumber) {
234                 List javaAnnotations = getJavaAnnotationsForLine(sourceViewer,
235                                 lineNumber);
236                 if (javaAnnotations != null) {
237
238                         if (javaAnnotations.size() == 1) {
239
240                                 // optimization
241                                 Annotation annotation = (Annotation) javaAnnotations.get(0);
242                                 String message = annotation.getText();
243                                 if (message != null && message.trim().length() > 0)
244                                         return formatSingleMessage(message);
245
246                         } else {
247
248                                 List messages = new ArrayList();
249
250                                 Iterator e = javaAnnotations.iterator();
251                                 while (e.hasNext()) {
252                                         Annotation annotation = (Annotation) e.next();
253                                         String message = annotation.getText();
254                                         if (message != null && message.trim().length() > 0)
255                                                 messages.add(message.trim());
256                                 }
257
258                                 if (messages.size() == 1)
259                                         return formatSingleMessage((String) messages.get(0));
260
261                                 if (messages.size() > 1)
262                                         return formatMultipleMessages(messages);
263                         }
264                 }
265
266                 return null;
267         }
268
269         /*
270          * @see IVerticalRulerHover#getHoverInfo(ISourceViewer, int)
271          */
272         // public String getHoverInfo(ISourceViewer sourceViewer, int lineNumber) {
273         // List javaAnnotations= getJavaAnnotationsForLine(sourceViewer,
274         // lineNumber);
275         // if (javaAnnotations != null) {
276         //                      
277         // if (javaAnnotations.size() == 1) {
278         //                              
279         // // optimization
280         // IJavaAnnotation javaAnnotation= (IJavaAnnotation) javaAnnotations.get(0);
281         // String message= javaAnnotation.getMessage();
282         // if (message != null && message.trim().length() > 0)
283         // return formatSingleMessage(message);
284         //                                      
285         // } else {
286         //                                      
287         // List messages= new ArrayList();
288         //                              
289         // Iterator e= javaAnnotations.iterator();
290         // while (e.hasNext()) {
291         // IJavaAnnotation javaAnnotation= (IJavaAnnotation) e.next();
292         // String message= javaAnnotation.getMessage();
293         // if (message != null && message.trim().length() > 0)
294         // messages.add(message.trim());
295         // }
296         //                              
297         // if (messages.size() == 1)
298         // return formatSingleMessage((String) messages.get(0));
299         //                                      
300         // if (messages.size() > 1)
301         // return formatMultipleMessages(messages);
302         // }
303         // }
304         //              
305         // return null;
306         // }
307         /*
308          * Formats a message as HTML text.
309          */
310         private String formatSingleMessage(String message) {
311                 StringBuffer buffer = new StringBuffer();
312                 HTMLPrinter.addPageProlog(buffer);
313                 HTMLPrinter.addParagraph(buffer, HTMLPrinter
314                                 .convertToHTMLContent(message));
315                 HTMLPrinter.addPageEpilog(buffer);
316                 return buffer.toString();
317         }
318
319         /*
320          * Formats several message as HTML text.
321          */
322         private String formatMultipleMessages(List messages) {
323                 StringBuffer buffer = new StringBuffer();
324                 HTMLPrinter.addPageProlog(buffer);
325                 HTMLPrinter
326                                 .addParagraph(
327                                                 buffer,
328                                                 HTMLPrinter
329                                                                 .convertToHTMLContent(PHPUIMessages
330                                                                                 .getString("JavaAnnotationHover.multipleMarkersAtThisLine"))); //$NON-NLS-1$
331
332                 HTMLPrinter.startBulletList(buffer);
333                 Iterator e = messages.iterator();
334                 while (e.hasNext())
335                         HTMLPrinter.addBullet(buffer, HTMLPrinter
336                                         .convertToHTMLContent((String) e.next()));
337                 HTMLPrinter.endBulletList(buffer);
338
339                 HTMLPrinter.addPageEpilog(buffer);
340                 return buffer.toString();
341         }
342
343         /**
344          * Returns the annotation preference for the given annotation.
345          * 
346          * @param annotation
347          *            the annotation
348          * @return the annotation preference or <code>null</code> if none
349          */
350         private AnnotationPreference getAnnotationPreference(Annotation annotation) {
351                 return EditorsUI.getAnnotationPreferenceLookup()
352                                 .getAnnotationPreference(annotation);
353         }
354 }