1 /*******************************************************************************
2 * Copyright (c) 2000, 2006 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
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 package net.sourceforge.phpdt.internal.ui.text.java.hover;
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;
21 import net.sourceforge.phpdt.internal.ui.text.java.hover.AnnotationExpansionControl.AnnotationHoverInput;
23 import org.eclipse.jface.text.BadLocationException;
24 import org.eclipse.jface.text.IDocument;
25 import org.eclipse.jface.text.IInformationControl;
26 import org.eclipse.jface.text.IInformationControlCreator;
27 import org.eclipse.jface.text.IInformationControlCreatorExtension;
28 import org.eclipse.jface.text.ITextViewerExtension5;
29 import org.eclipse.jface.text.Position;
30 import org.eclipse.jface.text.TextViewer;
31 import org.eclipse.jface.text.source.Annotation;
32 import org.eclipse.jface.text.source.CompositeRuler;
33 import org.eclipse.jface.text.source.IAnnotationAccess;
34 import org.eclipse.jface.text.source.IAnnotationAccessExtension;
35 import org.eclipse.jface.text.source.IAnnotationHover;
36 import org.eclipse.jface.text.source.IAnnotationHoverExtension;
37 import org.eclipse.jface.text.source.IAnnotationModel;
38 import org.eclipse.jface.text.source.ILineRange;
39 import org.eclipse.jface.text.source.ISourceViewer;
40 import org.eclipse.jface.text.source.IVerticalRulerListener;
41 import org.eclipse.jface.text.source.LineRange;
42 import org.eclipse.jface.text.source.VerticalRulerEvent;
43 import org.eclipse.jface.viewers.IDoubleClickListener;
44 import org.eclipse.swt.SWT;
45 import org.eclipse.swt.custom.StyledText;
46 import org.eclipse.swt.graphics.Point;
47 import org.eclipse.swt.widgets.Menu;
48 import org.eclipse.swt.widgets.Shell;
51 * This class got moved here form Platform Text since it was not used there and
52 * caused discouraged access warnings. It will be moved down again once
53 * annotation roll-over support is provided by Platform Text.
57 public class AnnotationExpandHover implements IAnnotationHover,
58 IAnnotationHoverExtension {
60 private class InformationControlCreator implements
61 IInformationControlCreator, IInformationControlCreatorExtension {
64 * @see org.eclipse.jface.text.IInformationControlCreator#createInformationControl(org.eclipse.swt.widgets.Shell)
66 public IInformationControl createInformationControl(Shell parent) {
67 return new AnnotationExpansionControl(parent, SWT.NONE,
72 * @see org.eclipse.jface.text.IInformationControlCreatorExtension#canReuse(org.eclipse.jface.text.IInformationControl)
74 public boolean canReuse(IInformationControl control) {
75 return control instanceof AnnotationExpansionControl;
79 * @see org.eclipse.jface.text.IInformationControlCreatorExtension#canReplace(org.eclipse.jface.text.IInformationControlCreator)
81 public boolean canReplace(IInformationControlCreator creator) {
82 return creator == this;
86 private class VerticalRulerListener implements IVerticalRulerListener {
89 * @see org.eclipse.jface.text.source.IVerticalRulerListener#annotationSelected(org.eclipse.jface.text.source.VerticalRulerEvent)
91 public void annotationSelected(VerticalRulerEvent event) {
92 fCompositeRuler.fireAnnotationSelected(event);
96 * @see org.eclipse.jface.text.source.IVerticalRulerListener#annotationDefaultSelected(org.eclipse.jface.text.source.VerticalRulerEvent)
98 public void annotationDefaultSelected(VerticalRulerEvent event) {
99 fCompositeRuler.fireAnnotationDefaultSelected(event);
103 * @see org.eclipse.jface.text.source.IVerticalRulerListener#annotationContextMenuAboutToShow(org.eclipse.jface.text.source.VerticalRulerEvent,
104 * org.eclipse.swt.widgets.Menu)
106 public void annotationContextMenuAboutToShow(VerticalRulerEvent event,
108 fCompositeRuler.fireAnnotationContextMenuAboutToShow(event, menu);
112 private final IInformationControlCreator fgCreator = new InformationControlCreator();
114 protected final IVerticalRulerListener fgListener = new VerticalRulerListener();
116 protected CompositeRuler fCompositeRuler;
118 protected IDoubleClickListener fDblClickListener;
120 protected IAnnotationAccess fAnnotationAccess;
123 * Creates a new hover instance.
127 * @param doubleClickListener
129 public AnnotationExpandHover(CompositeRuler ruler,
130 IAnnotationAccess access, IDoubleClickListener doubleClickListener) {
131 fCompositeRuler = ruler;
132 fAnnotationAccess = access;
133 fDblClickListener = doubleClickListener;
137 * @see org.eclipse.jface.text.source.IAnnotationHover#getHoverInfo(org.eclipse.jface.text.source.ISourceViewer,
140 public String getHoverInfo(ISourceViewer sourceViewer, int line) {
141 // we don't have any sensible return value as text
145 protected Object getHoverInfoForLine(ISourceViewer viewer, int line) {
146 IAnnotationModel model = viewer.getAnnotationModel();
147 IDocument document = viewer.getDocument();
152 List exact = new ArrayList();
153 HashMap messagesAtPosition = new HashMap();
155 Iterator e = model.getAnnotationIterator();
156 while (e.hasNext()) {
157 Annotation annotation = (Annotation) e.next();
158 Position position = model.getPosition(annotation);
159 if (position == null)
162 if (compareRulerLine(position, document, line) == 1) {
163 if (isDuplicateMessage(messagesAtPosition, position, annotation
167 exact.add(annotation);
171 if (exact.size() < 1)
176 if (exact.size() > 0)
177 setLastRulerMouseLocation(viewer, line);
179 AnnotationHoverInput input = new AnnotationHoverInput();
180 input.fAnnotations = (Annotation[]) exact.toArray(new Annotation[0]);
181 input.fViewer = viewer;
182 input.fRulerInfo = fCompositeRuler;
183 input.fAnnotationListener = fgListener;
184 input.fDoubleClickListener = fDblClickListener;
190 protected void sort(List exact, final IAnnotationModel model) {
191 class AnnotationComparator implements Comparator {
194 * @see java.util.Comparator#compare(java.lang.Object,
197 public int compare(Object o1, Object o2) {
198 Annotation a1 = (Annotation) o1;
199 Annotation a2 = (Annotation) o2;
201 Position p1 = model.getPosition(a1);
202 Position p2 = model.getPosition(a2);
205 // primary order: by position in line
206 // secondary: annotation importance
207 if (p1.offset == p2.offset)
208 return getOrder(a2) - getOrder(a1);
209 return p1.offset - p2.offset;
213 Collections.sort(exact, new AnnotationComparator());
217 protected int getOrder(Annotation annotation) {
218 if (fAnnotationAccess instanceof IAnnotationAccessExtension) {
219 IAnnotationAccessExtension extension = (IAnnotationAccessExtension) fAnnotationAccess;
220 return extension.getLayer(annotation);
222 return IAnnotationAccessExtension.DEFAULT_LAYER;
225 protected boolean isDuplicateMessage(Map messagesAtPosition,
226 Position position, String message) {
230 if (messagesAtPosition.containsKey(position)) {
231 Object value = messagesAtPosition.get(position);
232 if (message == null || message.equals(value))
235 if (value instanceof List) {
236 List messages = (List) value;
237 if (messages.contains(message))
239 messages.add(message);
241 ArrayList messages = new ArrayList();
243 messages.add(message);
244 messagesAtPosition.put(position, messages);
247 messagesAtPosition.put(position, message);
251 protected void setLastRulerMouseLocation(ISourceViewer viewer, int line) {
252 // set last mouse activity in order to get the correct context menu
253 if (fCompositeRuler != null) {
254 StyledText st = viewer.getTextWidget();
255 if (st != null && !st.isDisposed()) {
256 if (viewer instanceof ITextViewerExtension5) {
257 int widgetLine = ((ITextViewerExtension5) viewer)
258 .modelLine2WidgetLine(line);
259 Point loc = st.getLocationAtOffset(st
260 .getOffsetAtLine(widgetLine));
261 fCompositeRuler.setLocationOfLastMouseButtonActivity(0,
263 } else if (viewer instanceof TextViewer) {
264 // TODO remove once TextViewer implements the extension
265 int widgetLine = ((TextViewer) viewer)
266 .modelLine2WidgetLine(line);
267 Point loc = st.getLocationAtOffset(st
268 .getOffsetAtLine(widgetLine));
269 fCompositeRuler.setLocationOfLastMouseButtonActivity(0,
277 * Returns the distance to the ruler line.
285 * @return the distance to the ruler line
287 protected int compareRulerLine(Position position, IDocument document,
290 if (position.getOffset() > -1 && position.getLength() > -1) {
292 int firstLine = document.getLineOfOffset(position.getOffset());
293 if (line == firstLine)
295 if (firstLine <= line
296 && line <= document.getLineOfOffset(position
298 + position.getLength()))
300 } catch (BadLocationException x) {
308 * @see org.eclipse.jface.text.source.IAnnotationHoverExtension#getHoverControlCreator()
310 public IInformationControlCreator getHoverControlCreator() {
315 * @see org.eclipse.jface.text.source.IAnnotationHoverExtension#getHoverInfo(org.eclipse.jface.text.source.ISourceViewer,
316 * org.eclipse.jface.text.source.ILineRange, int)
318 public Object getHoverInfo(ISourceViewer sourceViewer,
319 ILineRange lineRange, int visibleLines) {
320 return getHoverInfoForLine(sourceViewer, lineRange.getStartLine());
324 * @see org.eclipse.jface.text.source.IAnnotationHoverExtension#getHoverLineRange(org.eclipse.jface.text.source.ISourceViewer,
327 public ILineRange getHoverLineRange(ISourceViewer viewer, int lineNumber) {
328 return new LineRange(lineNumber, 1);
332 * @see org.eclipse.jface.text.source.IAnnotationHoverExtension#canHandleMouseCursor()
334 public boolean canHandleMouseCursor() {