]>
Commit | Line | Data |
---|---|---|
1b2798f6 EK |
1 | /******************************************************************************* |
2 | * Copyright (c) 2000, 2011 IBM Corporation and others. | |
3 | * All rights reserved. This program and the accompanying materials | |
4 | * are made available under the terms of the Eclipse Public License v1.0 | |
5 | * which accompanies this distribution, and is available at | |
6 | * http://www.eclipse.org/legal/epl-v10.html | |
7 | * | |
8 | * Contributors: | |
9 | * IBM Corporation - initial API and implementation | |
10 | *******************************************************************************/ | |
11 | package org.eclipse.jdt.internal.ui.text.java.hover; | |
12 | ||
13 | import java.util.ArrayList; | |
14 | import java.util.Collections; | |
15 | import java.util.Comparator; | |
16 | import java.util.HashMap; | |
17 | import java.util.Iterator; | |
18 | import java.util.List; | |
19 | import java.util.Map; | |
20 | ||
21 | import org.eclipse.swt.SWT; | |
22 | import org.eclipse.swt.custom.StyledText; | |
23 | import org.eclipse.swt.graphics.Point; | |
24 | import org.eclipse.swt.widgets.Menu; | |
25 | import org.eclipse.swt.widgets.Shell; | |
26 | ||
27 | import org.eclipse.jface.viewers.IDoubleClickListener; | |
28 | ||
29 | import org.eclipse.jface.text.BadLocationException; | |
30 | import org.eclipse.jface.text.IDocument; | |
31 | import org.eclipse.jface.text.IInformationControl; | |
32 | import org.eclipse.jface.text.IInformationControlCreator; | |
33 | import org.eclipse.jface.text.IInformationControlCreatorExtension; | |
34 | import org.eclipse.jface.text.ITextViewerExtension5; | |
35 | import org.eclipse.jface.text.Position; | |
36 | import org.eclipse.jface.text.TextViewer; | |
37 | import org.eclipse.jface.text.source.Annotation; | |
38 | import org.eclipse.jface.text.source.CompositeRuler; | |
39 | import org.eclipse.jface.text.source.IAnnotationAccess; | |
40 | import org.eclipse.jface.text.source.IAnnotationAccessExtension; | |
41 | import org.eclipse.jface.text.source.IAnnotationHover; | |
42 | import org.eclipse.jface.text.source.IAnnotationHoverExtension; | |
43 | import org.eclipse.jface.text.source.IAnnotationModel; | |
44 | import org.eclipse.jface.text.source.ILineRange; | |
45 | import org.eclipse.jface.text.source.ISourceViewer; | |
46 | import org.eclipse.jface.text.source.IVerticalRulerListener; | |
47 | import org.eclipse.jface.text.source.LineRange; | |
48 | import org.eclipse.jface.text.source.VerticalRulerEvent; | |
49 | ||
50 | import org.eclipse.jdt.internal.ui.text.java.hover.AnnotationExpansionControl.AnnotationHoverInput; | |
51 | ||
52 | ||
53 | /** | |
54 | * This class got moved here form Platform Text since it was not used there | |
55 | * and caused discouraged access warnings. It will be moved down again once | |
56 | * annotation roll-over support is provided by Platform Text. | |
57 | * | |
58 | * @since 3.2 | |
59 | */ | |
60 | public class AnnotationExpandHover implements IAnnotationHover, IAnnotationHoverExtension { | |
61 | ||
62 | private class InformationControlCreator implements IInformationControlCreator, IInformationControlCreatorExtension { | |
63 | ||
64 | /* | |
65 | * @see org.eclipse.jface.text.IInformationControlCreator#createInformationControl(org.eclipse.swt.widgets.Shell) | |
66 | */ | |
67 | public IInformationControl createInformationControl(Shell parent) { | |
68 | return new AnnotationExpansionControl(parent, SWT.NONE, fAnnotationAccess); | |
69 | } | |
70 | ||
71 | /* | |
72 | * @see org.eclipse.jface.text.IInformationControlCreatorExtension#canReuse(org.eclipse.jface.text.IInformationControl) | |
73 | */ | |
74 | public boolean canReuse(IInformationControl control) { | |
75 | return control instanceof AnnotationExpansionControl; | |
76 | } | |
77 | ||
78 | /* | |
79 | * @see org.eclipse.jface.text.IInformationControlCreatorExtension#canReplace(org.eclipse.jface.text.IInformationControlCreator) | |
80 | */ | |
81 | public boolean canReplace(IInformationControlCreator creator) { | |
82 | return creator == this; | |
83 | } | |
84 | } | |
85 | ||
86 | private class VerticalRulerListener implements IVerticalRulerListener { | |
87 | ||
88 | /* | |
89 | * @see org.eclipse.jface.text.source.IVerticalRulerListener#annotationSelected(org.eclipse.jface.text.source.VerticalRulerEvent) | |
90 | */ | |
91 | public void annotationSelected(VerticalRulerEvent event) { | |
92 | fCompositeRuler.fireAnnotationSelected(event); | |
93 | } | |
94 | ||
95 | /* | |
96 | * @see org.eclipse.jface.text.source.IVerticalRulerListener#annotationDefaultSelected(org.eclipse.jface.text.source.VerticalRulerEvent) | |
97 | */ | |
98 | public void annotationDefaultSelected(VerticalRulerEvent event) { | |
99 | fCompositeRuler.fireAnnotationDefaultSelected(event); | |
100 | } | |
101 | ||
102 | /* | |
103 | * @see org.eclipse.jface.text.source.IVerticalRulerListener#annotationContextMenuAboutToShow(org.eclipse.jface.text.source.VerticalRulerEvent, org.eclipse.swt.widgets.Menu) | |
104 | */ | |
105 | public void annotationContextMenuAboutToShow(VerticalRulerEvent event, Menu menu) { | |
106 | fCompositeRuler.fireAnnotationContextMenuAboutToShow(event, menu); | |
107 | } | |
108 | } | |
109 | ||
110 | ||
111 | private final IInformationControlCreator fgCreator= new InformationControlCreator(); | |
112 | protected final IVerticalRulerListener fgListener= new VerticalRulerListener(); | |
113 | protected CompositeRuler fCompositeRuler; | |
114 | protected IDoubleClickListener fDblClickListener; | |
115 | protected IAnnotationAccess fAnnotationAccess; | |
116 | ||
117 | /** | |
118 | * Creates a new hover instance. | |
119 | * | |
120 | * @param ruler | |
121 | * @param access | |
122 | * @param doubleClickListener | |
123 | */ | |
124 | public AnnotationExpandHover(CompositeRuler ruler, IAnnotationAccess access, IDoubleClickListener doubleClickListener) { | |
125 | fCompositeRuler= ruler; | |
126 | fAnnotationAccess= access; | |
127 | fDblClickListener= doubleClickListener; | |
128 | } | |
129 | ||
130 | /* | |
131 | * @see org.eclipse.jface.text.source.IAnnotationHover#getHoverInfo(org.eclipse.jface.text.source.ISourceViewer, int) | |
132 | */ | |
133 | public String getHoverInfo(ISourceViewer sourceViewer, int line) { | |
134 | // we don't have any sensible return value as text | |
135 | return null; | |
136 | } | |
137 | ||
138 | protected Object getHoverInfoForLine(ISourceViewer viewer, int line) { | |
139 | IAnnotationModel model= viewer.getAnnotationModel(); | |
140 | IDocument document= viewer.getDocument(); | |
141 | ||
142 | if (model == null) | |
143 | return null; | |
144 | ||
145 | List<Annotation> exact= new ArrayList<Annotation>(); | |
146 | HashMap<Position, Object> messagesAtPosition= new HashMap<Position, Object>(); | |
147 | ||
148 | Iterator<Annotation> e= model.getAnnotationIterator(); | |
149 | while (e.hasNext()) { | |
150 | Annotation annotation= e.next(); | |
151 | Position position= model.getPosition(annotation); | |
152 | if (position == null) | |
153 | continue; | |
154 | ||
155 | if (compareRulerLine(position, document, line) == 1) { | |
156 | if (isDuplicateMessage(messagesAtPosition, position, annotation.getText())) | |
157 | continue; | |
158 | ||
159 | exact.add(annotation); | |
160 | } | |
161 | } | |
162 | ||
163 | if (exact.size() < 1) | |
164 | return null; | |
165 | ||
166 | sort(exact, model); | |
167 | ||
168 | if (exact.size() > 0) | |
169 | setLastRulerMouseLocation(viewer, line); | |
170 | ||
171 | AnnotationHoverInput input= new AnnotationHoverInput(); | |
172 | return input.generated_8997451761112746382(viewer, model, exact, this); | |
173 | } | |
174 | ||
175 | protected void sort(List<Annotation> exact, final IAnnotationModel model) { | |
176 | class AnnotationComparator implements Comparator<Annotation> { | |
177 | ||
178 | /* | |
179 | * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object) | |
180 | */ | |
181 | public int compare(Annotation a1, Annotation a2) { | |
182 | Position p1= model.getPosition(a1); | |
183 | Position p2= model.getPosition(a2); | |
184 | ||
185 | // annotation order: | |
186 | // primary order: by position in line | |
187 | // secondary: annotation importance | |
188 | if (p1.offset == p2.offset) | |
189 | return getOrder(a2) - getOrder(a1); | |
190 | return p1.offset - p2.offset; | |
191 | } | |
192 | } | |
193 | ||
194 | Collections.sort(exact, new AnnotationComparator()); | |
195 | ||
196 | } | |
197 | ||
198 | protected int getOrder(Annotation annotation) { | |
199 | if (fAnnotationAccess instanceof IAnnotationAccessExtension) { | |
200 | IAnnotationAccessExtension extension= (IAnnotationAccessExtension) fAnnotationAccess; | |
201 | return extension.getLayer(annotation); | |
202 | } | |
203 | return IAnnotationAccessExtension.DEFAULT_LAYER; | |
204 | } | |
205 | ||
206 | protected boolean isDuplicateMessage(Map<Position, Object> messagesAtPosition, Position position, String message) { | |
207 | if (message == null) | |
208 | return false; | |
209 | ||
210 | if (messagesAtPosition.containsKey(position)) { | |
211 | Object value= messagesAtPosition.get(position); | |
212 | if (message.equals(value)) | |
213 | return true; | |
214 | ||
215 | if (value instanceof List) { | |
216 | @SuppressWarnings("unchecked") | |
217 | List<String> messages= ((List<String>)value); | |
218 | if (messages.contains(message)) | |
219 | return true; | |
220 | messages.add(message); | |
221 | } else { | |
222 | ArrayList<Object> messages= new ArrayList<Object>(); | |
223 | messages.add(value); | |
224 | messages.add(message); | |
225 | messagesAtPosition.put(position, messages); | |
226 | } | |
227 | } else | |
228 | messagesAtPosition.put(position, message); | |
229 | return false; | |
230 | } | |
231 | ||
232 | protected void setLastRulerMouseLocation(ISourceViewer viewer, int line) { | |
233 | // set last mouse activity in order to get the correct context menu | |
234 | if (fCompositeRuler != null) { | |
235 | StyledText st= viewer.getTextWidget(); | |
236 | if (st != null && !st.isDisposed()) { | |
237 | if (viewer instanceof ITextViewerExtension5) { | |
238 | int widgetLine= ((ITextViewerExtension5)viewer).modelLine2WidgetLine(line); | |
239 | Point loc= st.getLocationAtOffset(st.getOffsetAtLine(widgetLine)); | |
240 | fCompositeRuler.setLocationOfLastMouseButtonActivity(0, loc.y); | |
241 | } else if (viewer instanceof TextViewer) { | |
242 | // TODO remove once TextViewer implements the extension | |
243 | int widgetLine= ((TextViewer)viewer).modelLine2WidgetLine(line); | |
244 | Point loc= st.getLocationAtOffset(st.getOffsetAtLine(widgetLine)); | |
245 | fCompositeRuler.setLocationOfLastMouseButtonActivity(0, loc.y); | |
246 | } | |
247 | } | |
248 | } | |
249 | } | |
250 | ||
251 | /** | |
252 | * Returns the distance to the ruler line. | |
253 | * | |
254 | * @param position the position | |
255 | * @param document the document | |
256 | * @param line the line number | |
257 | * @return the distance to the ruler line | |
258 | */ | |
259 | protected int compareRulerLine(Position position, IDocument document, int line) { | |
260 | ||
261 | if (position.getOffset() > -1 && position.getLength() > -1) { | |
262 | try { | |
263 | int firstLine= document.getLineOfOffset(position.getOffset()); | |
264 | if (line == firstLine) | |
265 | return 1; | |
266 | if (firstLine <= line && line <= document.getLineOfOffset(position.getOffset() + position.getLength())) | |
267 | return 2; | |
268 | } catch (BadLocationException x) { | |
269 | } | |
270 | } | |
271 | ||
272 | return 0; | |
273 | } | |
274 | ||
275 | /* | |
276 | * @see org.eclipse.jface.text.source.IAnnotationHoverExtension#getHoverControlCreator() | |
277 | */ | |
278 | public IInformationControlCreator getHoverControlCreator() { | |
279 | return fgCreator; | |
280 | } | |
281 | ||
282 | /* | |
283 | * @see org.eclipse.jface.text.source.IAnnotationHoverExtension#getHoverInfo(org.eclipse.jface.text.source.ISourceViewer, org.eclipse.jface.text.source.ILineRange, int) | |
284 | */ | |
285 | public Object getHoverInfo(ISourceViewer sourceViewer, ILineRange lineRange, int visibleLines) { | |
286 | return getHoverInfoForLine(sourceViewer, lineRange.getStartLine()); | |
287 | } | |
288 | ||
289 | /* | |
290 | * @see org.eclipse.jface.text.source.IAnnotationHoverExtension#getHoverLineRange(org.eclipse.jface.text.source.ISourceViewer, int) | |
291 | */ | |
292 | public ILineRange getHoverLineRange(ISourceViewer viewer, int lineNumber) { | |
293 | return new LineRange(lineNumber, 1); | |
294 | } | |
295 | ||
296 | /* | |
297 | * @see org.eclipse.jface.text.source.IAnnotationHoverExtension#canHandleMouseCursor() | |
298 | */ | |
299 | public boolean canHandleMouseCursor() { | |
300 | return true; | |
301 | } | |
302 | } |