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 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;
27 import org.eclipse.jface.viewers.IDoubleClickListener;
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;
50 import net.sourceforge.phpdt.internal.ui.text.java.hover.AnnotationExpansionControl.AnnotationHoverInput;
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.
60 public class AnnotationExpandHover implements IAnnotationHover, IAnnotationHoverExtension {
62 private class InformationControlCreator implements IInformationControlCreator, IInformationControlCreatorExtension {
65 * @see org.eclipse.jface.text.IInformationControlCreator#createInformationControl(org.eclipse.swt.widgets.Shell)
67 public IInformationControl createInformationControl(Shell parent) {
68 return new AnnotationExpansionControl(parent, SWT.NONE, fAnnotationAccess);
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, org.eclipse.swt.widgets.Menu)
105 public void annotationContextMenuAboutToShow(VerticalRulerEvent event, Menu menu) {
106 fCompositeRuler.fireAnnotationContextMenuAboutToShow(event, menu);
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;
118 * Creates a new hover instance.
122 * @param doubleClickListener
124 public AnnotationExpandHover(CompositeRuler ruler, IAnnotationAccess access, IDoubleClickListener doubleClickListener) {
125 fCompositeRuler= ruler;
126 fAnnotationAccess= access;
127 fDblClickListener= doubleClickListener;
131 * @see org.eclipse.jface.text.source.IAnnotationHover#getHoverInfo(org.eclipse.jface.text.source.ISourceViewer, int)
133 public String getHoverInfo(ISourceViewer sourceViewer, int line) {
134 // we don't have any sensible return value as text
138 protected Object getHoverInfoForLine(ISourceViewer viewer, int line) {
139 IAnnotationModel model= viewer.getAnnotationModel();
140 IDocument document= viewer.getDocument();
145 List exact= new ArrayList();
146 HashMap messagesAtPosition= new HashMap();
148 Iterator e= model.getAnnotationIterator();
149 while (e.hasNext()) {
150 Annotation annotation= (Annotation) e.next();
151 Position position= model.getPosition(annotation);
152 if (position == null)
155 if (compareRulerLine(position, document, line) == 1) {
156 if (isDuplicateMessage(messagesAtPosition, position, annotation.getText()))
159 exact.add(annotation);
163 if (exact.size() < 1)
168 if (exact.size() > 0)
169 setLastRulerMouseLocation(viewer, line);
171 AnnotationHoverInput input= new AnnotationHoverInput();
172 input.fAnnotations= (Annotation[]) exact.toArray(new Annotation[0]);
173 input.fViewer= viewer;
174 input.fRulerInfo= fCompositeRuler;
175 input.fAnnotationListener= fgListener;
176 input.fDoubleClickListener= fDblClickListener;
182 protected void sort(List exact, final IAnnotationModel model) {
183 class AnnotationComparator implements Comparator {
186 * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
188 public int compare(Object o1, Object o2) {
189 Annotation a1= (Annotation) o1;
190 Annotation a2= (Annotation) o2;
192 Position p1= model.getPosition(a1);
193 Position p2= model.getPosition(a2);
196 // primary order: by position in line
197 // secondary: annotation importance
198 if (p1.offset == p2.offset)
199 return getOrder(a2) - getOrder(a1);
200 return p1.offset - p2.offset;
204 Collections.sort(exact, new AnnotationComparator());
208 protected int getOrder(Annotation annotation) {
209 if (fAnnotationAccess instanceof IAnnotationAccessExtension) {
210 IAnnotationAccessExtension extension= (IAnnotationAccessExtension) fAnnotationAccess;
211 return extension.getLayer(annotation);
213 return IAnnotationAccessExtension.DEFAULT_LAYER;
216 protected boolean isDuplicateMessage(Map messagesAtPosition, Position position, String message) {
220 if (messagesAtPosition.containsKey(position)) {
221 Object value= messagesAtPosition.get(position);
222 if (message == null || message.equals(value))
225 if (value instanceof List) {
226 List messages= (List)value;
227 if (messages.contains(message))
229 messages.add(message);
231 ArrayList messages= new ArrayList();
233 messages.add(message);
234 messagesAtPosition.put(position, messages);
237 messagesAtPosition.put(position, message);
241 protected void setLastRulerMouseLocation(ISourceViewer viewer, int line) {
242 // set last mouse activity in order to get the correct context menu
243 if (fCompositeRuler != null) {
244 StyledText st= viewer.getTextWidget();
245 if (st != null && !st.isDisposed()) {
246 if (viewer instanceof ITextViewerExtension5) {
247 int widgetLine= ((ITextViewerExtension5)viewer).modelLine2WidgetLine(line);
248 Point loc= st.getLocationAtOffset(st.getOffsetAtLine(widgetLine));
249 fCompositeRuler.setLocationOfLastMouseButtonActivity(0, loc.y);
250 } else if (viewer instanceof TextViewer) {
251 // TODO remove once TextViewer implements the extension
252 int widgetLine= ((TextViewer)viewer).modelLine2WidgetLine(line);
253 Point loc= st.getLocationAtOffset(st.getOffsetAtLine(widgetLine));
254 fCompositeRuler.setLocationOfLastMouseButtonActivity(0, loc.y);
261 * Returns the distance to the ruler line.
263 * @param position the position
264 * @param document the document
265 * @param line the line number
266 * @return the distance to the ruler line
268 protected int compareRulerLine(Position position, IDocument document, int line) {
270 if (position.getOffset() > -1 && position.getLength() > -1) {
272 int firstLine= document.getLineOfOffset(position.getOffset());
273 if (line == firstLine)
275 if (firstLine <= line && line <= document.getLineOfOffset(position.getOffset() + position.getLength()))
277 } catch (BadLocationException x) {
285 * @see org.eclipse.jface.text.source.IAnnotationHoverExtension#getHoverControlCreator()
287 public IInformationControlCreator getHoverControlCreator() {
292 * @see org.eclipse.jface.text.source.IAnnotationHoverExtension#getHoverInfo(org.eclipse.jface.text.source.ISourceViewer, org.eclipse.jface.text.source.ILineRange, int)
294 public Object getHoverInfo(ISourceViewer sourceViewer, ILineRange lineRange, int visibleLines) {
295 return getHoverInfoForLine(sourceViewer, lineRange.getStartLine());
299 * @see org.eclipse.jface.text.source.IAnnotationHoverExtension#getHoverLineRange(org.eclipse.jface.text.source.ISourceViewer, int)
301 public ILineRange getHoverLineRange(ISourceViewer viewer, int lineNumber) {
302 return new LineRange(lineNumber, 1);
306 * @see org.eclipse.jface.text.source.IAnnotationHoverExtension#canHandleMouseCursor()
308 public boolean canHandleMouseCursor() {