X-Git-Url: http://secure.phpeclipse.com diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/java/hover/AnnotationExpandHover.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/java/hover/AnnotationExpandHover.java new file mode 100644 index 0000000..f8cea73 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/text/java/hover/AnnotationExpandHover.java @@ -0,0 +1,311 @@ +/******************************************************************************* + * Copyright (c) 2000, 2006 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package net.sourceforge.phpdt.internal.ui.text.java.hover; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.StyledText; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.widgets.Menu; +import org.eclipse.swt.widgets.Shell; + +import org.eclipse.jface.viewers.IDoubleClickListener; + +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.IInformationControl; +import org.eclipse.jface.text.IInformationControlCreator; +import org.eclipse.jface.text.IInformationControlCreatorExtension; +import org.eclipse.jface.text.ITextViewerExtension5; +import org.eclipse.jface.text.Position; +import org.eclipse.jface.text.TextViewer; +import org.eclipse.jface.text.source.Annotation; +import org.eclipse.jface.text.source.CompositeRuler; +import org.eclipse.jface.text.source.IAnnotationAccess; +import org.eclipse.jface.text.source.IAnnotationAccessExtension; +import org.eclipse.jface.text.source.IAnnotationHover; +import org.eclipse.jface.text.source.IAnnotationHoverExtension; +import org.eclipse.jface.text.source.IAnnotationModel; +import org.eclipse.jface.text.source.ILineRange; +import org.eclipse.jface.text.source.ISourceViewer; +import org.eclipse.jface.text.source.IVerticalRulerListener; +import org.eclipse.jface.text.source.LineRange; +import org.eclipse.jface.text.source.VerticalRulerEvent; + +import net.sourceforge.phpdt.internal.ui.text.java.hover.AnnotationExpansionControl.AnnotationHoverInput; + + +/** + * This class got moved here form Platform Text since it was not used there + * and caused discouraged access warnings. It will be moved down again once + * annotation roll-over support is provided by Platform Text. + * + * @since 3.2 + */ +public class AnnotationExpandHover implements IAnnotationHover, IAnnotationHoverExtension { + + private class InformationControlCreator implements IInformationControlCreator, IInformationControlCreatorExtension { + + /* + * @see org.eclipse.jface.text.IInformationControlCreator#createInformationControl(org.eclipse.swt.widgets.Shell) + */ + public IInformationControl createInformationControl(Shell parent) { + return new AnnotationExpansionControl(parent, SWT.NONE, fAnnotationAccess); + } + + /* + * @see org.eclipse.jface.text.IInformationControlCreatorExtension#canReuse(org.eclipse.jface.text.IInformationControl) + */ + public boolean canReuse(IInformationControl control) { + return control instanceof AnnotationExpansionControl; + } + + /* + * @see org.eclipse.jface.text.IInformationControlCreatorExtension#canReplace(org.eclipse.jface.text.IInformationControlCreator) + */ + public boolean canReplace(IInformationControlCreator creator) { + return creator == this; + } + } + + private class VerticalRulerListener implements IVerticalRulerListener { + + /* + * @see org.eclipse.jface.text.source.IVerticalRulerListener#annotationSelected(org.eclipse.jface.text.source.VerticalRulerEvent) + */ + public void annotationSelected(VerticalRulerEvent event) { + fCompositeRuler.fireAnnotationSelected(event); + } + + /* + * @see org.eclipse.jface.text.source.IVerticalRulerListener#annotationDefaultSelected(org.eclipse.jface.text.source.VerticalRulerEvent) + */ + public void annotationDefaultSelected(VerticalRulerEvent event) { + fCompositeRuler.fireAnnotationDefaultSelected(event); + } + + /* + * @see org.eclipse.jface.text.source.IVerticalRulerListener#annotationContextMenuAboutToShow(org.eclipse.jface.text.source.VerticalRulerEvent, org.eclipse.swt.widgets.Menu) + */ + public void annotationContextMenuAboutToShow(VerticalRulerEvent event, Menu menu) { + fCompositeRuler.fireAnnotationContextMenuAboutToShow(event, menu); + } + } + + + private final IInformationControlCreator fgCreator= new InformationControlCreator(); + protected final IVerticalRulerListener fgListener= new VerticalRulerListener(); + protected CompositeRuler fCompositeRuler; + protected IDoubleClickListener fDblClickListener; + protected IAnnotationAccess fAnnotationAccess; + + /** + * Creates a new hover instance. + * + * @param ruler + * @param access + * @param doubleClickListener + */ + public AnnotationExpandHover(CompositeRuler ruler, IAnnotationAccess access, IDoubleClickListener doubleClickListener) { + fCompositeRuler= ruler; + fAnnotationAccess= access; + fDblClickListener= doubleClickListener; + } + + /* + * @see org.eclipse.jface.text.source.IAnnotationHover#getHoverInfo(org.eclipse.jface.text.source.ISourceViewer, int) + */ + public String getHoverInfo(ISourceViewer sourceViewer, int line) { + // we don't have any sensible return value as text + return null; + } + + protected Object getHoverInfoForLine(ISourceViewer viewer, int line) { + IAnnotationModel model= viewer.getAnnotationModel(); + IDocument document= viewer.getDocument(); + + if (model == null) + return null; + + List exact= new ArrayList(); + HashMap messagesAtPosition= new HashMap(); + + Iterator e= model.getAnnotationIterator(); + while (e.hasNext()) { + Annotation annotation= (Annotation) e.next(); + Position position= model.getPosition(annotation); + if (position == null) + continue; + + if (compareRulerLine(position, document, line) == 1) { + if (isDuplicateMessage(messagesAtPosition, position, annotation.getText())) + continue; + + exact.add(annotation); + } + } + + if (exact.size() < 1) + return null; + + sort(exact, model); + + if (exact.size() > 0) + setLastRulerMouseLocation(viewer, line); + + AnnotationHoverInput input= new AnnotationHoverInput(); + input.fAnnotations= (Annotation[]) exact.toArray(new Annotation[0]); + input.fViewer= viewer; + input.fRulerInfo= fCompositeRuler; + input.fAnnotationListener= fgListener; + input.fDoubleClickListener= fDblClickListener; + input.model= model; + + return input; + } + + protected void sort(List exact, final IAnnotationModel model) { + class AnnotationComparator implements Comparator { + + /* + * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object) + */ + public int compare(Object o1, Object o2) { + Annotation a1= (Annotation) o1; + Annotation a2= (Annotation) o2; + + Position p1= model.getPosition(a1); + Position p2= model.getPosition(a2); + + // annotation order: + // primary order: by position in line + // secondary: annotation importance + if (p1.offset == p2.offset) + return getOrder(a2) - getOrder(a1); + return p1.offset - p2.offset; + } + } + + Collections.sort(exact, new AnnotationComparator()); + + } + + protected int getOrder(Annotation annotation) { + if (fAnnotationAccess instanceof IAnnotationAccessExtension) { + IAnnotationAccessExtension extension= (IAnnotationAccessExtension) fAnnotationAccess; + return extension.getLayer(annotation); + } + return IAnnotationAccessExtension.DEFAULT_LAYER; + } + + protected boolean isDuplicateMessage(Map messagesAtPosition, Position position, String message) { + if (message == null) + return false; + + if (messagesAtPosition.containsKey(position)) { + Object value= messagesAtPosition.get(position); + if (message == null || message.equals(value)) + return true; + + if (value instanceof List) { + List messages= (List)value; + if (messages.contains(message)) + return true; + messages.add(message); + } else { + ArrayList messages= new ArrayList(); + messages.add(value); + messages.add(message); + messagesAtPosition.put(position, messages); + } + } else + messagesAtPosition.put(position, message); + return false; + } + + protected void setLastRulerMouseLocation(ISourceViewer viewer, int line) { + // set last mouse activity in order to get the correct context menu + if (fCompositeRuler != null) { + StyledText st= viewer.getTextWidget(); + if (st != null && !st.isDisposed()) { + if (viewer instanceof ITextViewerExtension5) { + int widgetLine= ((ITextViewerExtension5)viewer).modelLine2WidgetLine(line); + Point loc= st.getLocationAtOffset(st.getOffsetAtLine(widgetLine)); + fCompositeRuler.setLocationOfLastMouseButtonActivity(0, loc.y); + } else if (viewer instanceof TextViewer) { + // TODO remove once TextViewer implements the extension + int widgetLine= ((TextViewer)viewer).modelLine2WidgetLine(line); + Point loc= st.getLocationAtOffset(st.getOffsetAtLine(widgetLine)); + fCompositeRuler.setLocationOfLastMouseButtonActivity(0, loc.y); + } + } + } + } + + /** + * Returns the distance to the ruler line. + * + * @param position the position + * @param document the document + * @param line the line number + * @return the distance to the ruler line + */ + protected int compareRulerLine(Position position, IDocument document, int line) { + + if (position.getOffset() > -1 && position.getLength() > -1) { + try { + int firstLine= document.getLineOfOffset(position.getOffset()); + if (line == firstLine) + return 1; + if (firstLine <= line && line <= document.getLineOfOffset(position.getOffset() + position.getLength())) + return 2; + } catch (BadLocationException x) { + } + } + + return 0; + } + + /* + * @see org.eclipse.jface.text.source.IAnnotationHoverExtension#getHoverControlCreator() + */ + public IInformationControlCreator getHoverControlCreator() { + return fgCreator; + } + + /* + * @see org.eclipse.jface.text.source.IAnnotationHoverExtension#getHoverInfo(org.eclipse.jface.text.source.ISourceViewer, org.eclipse.jface.text.source.ILineRange, int) + */ + public Object getHoverInfo(ISourceViewer sourceViewer, ILineRange lineRange, int visibleLines) { + return getHoverInfoForLine(sourceViewer, lineRange.getStartLine()); + } + + /* + * @see org.eclipse.jface.text.source.IAnnotationHoverExtension#getHoverLineRange(org.eclipse.jface.text.source.ISourceViewer, int) + */ + public ILineRange getHoverLineRange(ISourceViewer viewer, int lineNumber) { + return new LineRange(lineNumber, 1); + } + + /* + * @see org.eclipse.jface.text.source.IAnnotationHoverExtension#canHandleMouseCursor() + */ + public boolean canHandleMouseCursor() { + return true; + } +}