From 5eb63f47003d637147bca6a5af8bf010f6335397 Mon Sep 17 00:00:00 2001 From: Sergey Prigogin Date: Thu, 8 May 2008 13:21:52 +0000 Subject: [PATCH] Spell correction hover. --- .../icons/dlcl16/configure_annotations.gif | Bin 0 -> 357 bytes .../icons/elcl16/configure_annotations.gif | Bin 0 -> 383 bytes core/org.eclipse.cdt.ui/plugin.xml | 24 +- .../cdt/internal/ui/CPluginImages.java | 54 +- .../ui/editor/CAnnotationIterator.java | 62 +- .../cdt/internal/ui/editor/CEditor.java | 25 +- .../internal/ui/editor/asm/AsmTextEditor.java | 17 +- .../text/c/hover/AbstractAnnotationHover.java | 752 ++++++++++++++++-- .../ui/text/c/hover/CHoverMessages.java | 5 + .../ui/text/c/hover/CHoverMessages.properties | 5 + .../ui/text/c/hover/CInformationProvider.java | 25 +- .../internal/ui/text/c/hover/CTypeHover.java | 90 +++ .../ui/text/c/hover/ProblemHover.java | 140 ++++ .../src/org/eclipse/cdt/ui/CUIPlugin.java | 3 +- 14 files changed, 1086 insertions(+), 116 deletions(-) create mode 100644 core/org.eclipse.cdt.ui/icons/dlcl16/configure_annotations.gif create mode 100644 core/org.eclipse.cdt.ui/icons/elcl16/configure_annotations.gif create mode 100644 core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CTypeHover.java create mode 100644 core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/ProblemHover.java diff --git a/core/org.eclipse.cdt.ui/icons/dlcl16/configure_annotations.gif b/core/org.eclipse.cdt.ui/icons/dlcl16/configure_annotations.gif new file mode 100644 index 0000000000000000000000000000000000000000..a52a650ba3e8f308e7f2a145a4885c05e30b204e GIT binary patch literal 357 zcmZ?wbhEHb6krfwxXQrr_43yrKYsoG{pZ)O-#>r;`tjrEr_WzMeEht0`KlGG*Y{7I zGk?+2A3uM6|MBzN_a9%segE?H+xqQ${`~#>^3}^H&mNpPvH$e(eK)V2zjW@{=Z|mq zty*>I$dRXa?|%9C@zBA8fB*jd^XJe1|Nj|i1{8m?FfuSGGU$M80Qrf5t?9sofESul z-G@_7FlSlm%BcoAtWDAiT$+C1ZJa@XZlaG`db?bwi*uUrqT?P(hi;mf{9vnTWKggw zlBwXYDB!4(l;svI5$KaDsN?1qkQd-&?(1ultGPU4)Us&QvT54AeATjP|L)Gew4&e4x7oV?#LLQJuq{}&QfPXv~4-WtjJ9;{R6M#58A%zb#I}ady z7MVCVJRXOI2?q=w1Pi7MH9R1b4 - - + + + + - useMissingImageDescriptor decides if either + * the 'missing image descriptor' is returned or null. + * or null. + */ + private static ImageDescriptor create(String prefix, String name, boolean useMissingImageDescriptor) { + IPath path= ICONS_PATH.append(prefix).append(name); + return createImageDescriptor(CUIPlugin.getDefault().getBundle(), path, useMissingImageDescriptor); + } + + /* + * Creates an image descriptor for the given prefix and name in the JDT UI bundle. The path can + * contain variables like $NL$. + * If no image could be found, the 'missing image descriptor' is returned. + */ + private static ImageDescriptor createUnManaged(String prefix, String name) { + return create(prefix, name, true); + } + private static URL makeIconFileURL(String prefix, String name) { StringBuffer buffer= new StringBuffer(prefix); buffer.append(name); @@ -374,6 +406,24 @@ public class CPluginImages { } } + /* + * Creates an image descriptor for the given path in a bundle. The path can contain variables + * like $NL$. + * If no image could be found, useMissingImageDescriptor decides if either + * the 'missing image descriptor' is returned or null. + * Added for 3.1.1. + */ + public static ImageDescriptor createImageDescriptor(Bundle bundle, IPath path, boolean useMissingImageDescriptor) { + URL url= FileLocator.find(bundle, path, null); + if (url != null) { + return ImageDescriptor.createFromURL(url); + } + if (useMissingImageDescriptor) { + return ImageDescriptor.getMissingImageDescriptor(); + } + return null; + } + /** * Sets the three image descriptors for enabled, disabled, and hovered to an action. The actions * are retrieved from the *tool16 folders. diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CAnnotationIterator.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CAnnotationIterator.java index 16c867a9a2a..30c66fb6181 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CAnnotationIterator.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CAnnotationIterator.java @@ -7,71 +7,61 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Sergey Prigogin (Google) *******************************************************************************/ package org.eclipse.cdt.internal.ui.editor; -import java.util.Collections; import java.util.Iterator; +import org.eclipse.core.resources.IMarker; +import org.eclipse.core.runtime.CoreException; import org.eclipse.jface.text.source.Annotation; -import org.eclipse.jface.text.source.IAnnotationModel; - +import org.eclipse.ui.texteditor.MarkerAnnotation; /** * Filters problems based on their types. */ public class CAnnotationIterator implements Iterator { - private Iterator fIterator; private Annotation fNext; - private boolean fSkipIrrelevants; private boolean fReturnAllAnnotations; /** - * Equivalent to CAnnotationIterator(model, skipIrrelevants, false). + * Returns a new CAnnotationIterator. + * @param parent the parent iterator to iterate over annotations + * @param returnAllAnnotations whether to return all annotations or just problem annotations */ - public CAnnotationIterator(IAnnotationModel model, boolean skipIrrelevants) { - this(model, skipIrrelevants, false); - } - - /** - * Returns a new CAnnotationIterator. - * @param model the annotation model - * @param skipIrrelevants whether to skip irrelevant annotations - * @param returnAllAnnotations Whether to return non IJavaAnnotations as well - */ - @SuppressWarnings("unchecked") // using api without generics - public CAnnotationIterator(IAnnotationModel model, boolean skipIrrelevants, boolean returnAllAnnotations) { + public CAnnotationIterator(Iterator parent, boolean returnAllAnnotations) { fReturnAllAnnotations= returnAllAnnotations; - if (model != null) - fIterator= model.getAnnotationIterator(); - else - fIterator= Collections.EMPTY_LIST.iterator(); - fSkipIrrelevants= skipIrrelevants; + fIterator= parent; skip(); } - + private void skip() { while (fIterator.hasNext()) { Annotation next= fIterator.next(); - if (next instanceof ICAnnotation) { - if (fSkipIrrelevants) { - if (!next.isMarkedDeleted()) { - fNext= next; - return; - } - } else { - fNext= next; - return; - } - } else if (fReturnAllAnnotations) { + + if (next.isMarkedDeleted()) + continue; + + if (fReturnAllAnnotations || next instanceof ICAnnotation || isProblemMarkerAnnotation(next)) { fNext= next; return; } } fNext= null; } - + + private static boolean isProblemMarkerAnnotation(Annotation annotation) { + if (!(annotation instanceof MarkerAnnotation)) + return false; + try { + return(((MarkerAnnotation)annotation).getMarker().isSubtypeOf(IMarker.PROBLEM)); + } catch (CoreException e) { + return false; + } + } + /* * @see Iterator#hasNext() */ diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CEditor.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CEditor.java index 3b21f6d5fab..2cd821ba6b8 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CEditor.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CEditor.java @@ -14,7 +14,6 @@ *******************************************************************************/ package org.eclipse.cdt.internal.ui.editor; - import java.text.CharacterIterator; import java.util.ArrayList; import java.util.HashMap; @@ -90,6 +89,7 @@ import org.eclipse.jface.text.link.LinkedModeUI.IExitPolicy; import org.eclipse.jface.text.source.Annotation; import org.eclipse.jface.text.source.IAnnotationModel; import org.eclipse.jface.text.source.IAnnotationModelExtension; +import org.eclipse.jface.text.source.IAnnotationModelExtension2; import org.eclipse.jface.text.source.ICharacterPairMatcher; import org.eclipse.jface.text.source.IOverviewRuler; import org.eclipse.jface.text.source.ISourceViewer; @@ -222,7 +222,6 @@ import org.eclipse.cdt.internal.ui.util.EditorUtility; import org.eclipse.cdt.internal.ui.viewsupport.ISelectionListenerWithAST; import org.eclipse.cdt.internal.ui.viewsupport.SelectionListenerWithASTManager; - /** * C/C++ source editor. */ @@ -402,7 +401,6 @@ public class CEditor extends TextEditor implements ISelectionChangedListener, IC } private class ExitPolicy implements IExitPolicy { - final char fExitCharacter; final char fEscapeCharacter; final Stack fStack; @@ -484,7 +482,6 @@ public class CEditor extends TextEditor implements ISelectionChangedListener, IC * @see org.eclipse.jface.text.IPositionUpdater#update(org.eclipse.jface.text.DocumentEvent) */ public void update(DocumentEvent event) { - int eventOffset = event.getOffset(); int eventOldLength = event.getLength(); int eventNewLength = event.getText() == null ? 0 : event.getText().length(); @@ -504,11 +501,11 @@ public class CEditor extends TextEditor implements ISelectionChangedListener, IC int length = position.getLength(); int end = offset + length; - if (offset >= eventOffset + eventOldLength) + if (offset >= eventOffset + eventOldLength) { // position comes // after change - shift position.setOffset(offset + deltaLength); - else if (end <= eventOffset) { + } else if (end <= eventOffset) { // position comes way before change - // leave alone } else if (offset <= eventOffset && end >= eventOffset + eventOldLength) { @@ -2455,8 +2452,20 @@ public class CEditor extends TextEditor implements ISelectionChangedListener, IC * @since 3.0 */ private Annotation getAnnotation(int offset, int length) { - IAnnotationModel model = getDocumentProvider().getAnnotationModel(getEditorInput()); - Iterator e = new CAnnotationIterator(model, true, true); + IAnnotationModel model= getDocumentProvider().getAnnotationModel(getEditorInput()); + if (model == null) + return null; + + @SuppressWarnings("unchecked") + Iterator parent; + if (model instanceof IAnnotationModelExtension2) { + parent= ((IAnnotationModelExtension2)model).getAnnotationIterator(offset, length, true, true); + } else { + parent= model.getAnnotationIterator(); + } + + @SuppressWarnings("unchecked") + Iterator e= new CAnnotationIterator(parent, false); while (e.hasNext()) { Annotation a = e.next(); if (!isNavigationTarget(a)) diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/asm/AsmTextEditor.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/asm/AsmTextEditor.java index 3407697508c..fd36f87d107 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/asm/AsmTextEditor.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/asm/AsmTextEditor.java @@ -26,6 +26,7 @@ import org.eclipse.jface.text.ITextViewerExtension5; import org.eclipse.jface.text.Position; import org.eclipse.jface.text.source.Annotation; import org.eclipse.jface.text.source.IAnnotationModel; +import org.eclipse.jface.text.source.IAnnotationModelExtension2; import org.eclipse.jface.text.source.ISourceViewer; import org.eclipse.jface.text.source.SourceViewerConfiguration; import org.eclipse.jface.util.PropertyChangeEvent; @@ -268,8 +269,20 @@ public class AsmTextEditor extends TextEditor implements ISelectionChangedListen * @return the found annotation or null */ private Annotation getAnnotation(int offset, int length) { - IAnnotationModel model = getDocumentProvider().getAnnotationModel(getEditorInput()); - Iterator e = new CAnnotationIterator(model, true, true); + IAnnotationModel model= getDocumentProvider().getAnnotationModel(getEditorInput()); + if (model == null) + return null; + + @SuppressWarnings("unchecked") + Iterator parent; + if (model instanceof IAnnotationModelExtension2) { + parent= ((IAnnotationModelExtension2)model).getAnnotationIterator(offset, length, true, true); + } else { + parent= model.getAnnotationIterator(); + } + + @SuppressWarnings("unchecked") + Iterator e= new CAnnotationIterator(parent, false); while (e.hasNext()) { Annotation a = e.next(); if (!isNavigationTarget(a)) diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/AbstractAnnotationHover.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/AbstractAnnotationHover.java index 5e0aec27ebb..81f43a4f723 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/AbstractAnnotationHover.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/AbstractAnnotationHover.java @@ -6,30 +6,83 @@ * http://www.eclipse.org/legal/epl-v10.html * * Contributors: - * QNX Software Systems - Initial API and implementation + * QNX Software Systems - Initial API and implementation + * Sergey Prigogin (Google) *******************************************************************************/ package org.eclipse.cdt.internal.ui.text.c.hover; +import java.text.MessageFormat; import java.util.Iterator; +import org.eclipse.core.filebuffers.FileBuffers; +import org.eclipse.core.filebuffers.ITextFileBufferManager; +import org.eclipse.core.filebuffers.LocationKind; +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.jface.action.Action; +import org.eclipse.jface.action.ToolBarManager; import org.eclipse.jface.preference.IPreferenceStore; +import org.eclipse.jface.resource.JFaceResources; +import org.eclipse.jface.text.AbstractInformationControl; +import org.eclipse.jface.text.AbstractReusableInformationControlCreator; +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.IInformationControl; +import org.eclipse.jface.text.IInformationControlCreator; +import org.eclipse.jface.text.IInformationControlExtension2; +import org.eclipse.jface.text.IInformationControlExtension4; import org.eclipse.jface.text.IRegion; +import org.eclipse.jface.text.IRewriteTarget; import org.eclipse.jface.text.ITextViewer; +import org.eclipse.jface.text.ITextViewerExtension; import org.eclipse.jface.text.Position; +import org.eclipse.jface.text.contentassist.ICompletionProposal; +import org.eclipse.jface.text.contentassist.ICompletionProposalExtension; +import org.eclipse.jface.text.contentassist.ICompletionProposalExtension2; import org.eclipse.jface.text.source.Annotation; import org.eclipse.jface.text.source.IAnnotationModel; -import org.eclipse.ui.IEditorPart; +import org.eclipse.jface.text.source.IAnnotationModelExtension2; +import org.eclipse.jface.text.source.ISourceViewer; +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.ScrolledComposite; +import org.eclipse.swt.custom.StyledText; +import org.eclipse.swt.events.FocusEvent; +import org.eclipse.swt.events.FocusListener; +import org.eclipse.swt.events.KeyEvent; +import org.eclipse.swt.events.KeyListener; +import org.eclipse.swt.events.MouseEvent; +import org.eclipse.swt.events.MouseListener; +import org.eclipse.swt.events.PaintEvent; +import org.eclipse.swt.events.PaintListener; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.Font; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Canvas; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Link; +import org.eclipse.swt.widgets.ScrollBar; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.ui.IEditorInput; +import org.eclipse.ui.IStorageEditorInput; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.dialogs.PreferencesUtil; import org.eclipse.ui.editors.text.EditorsUI; import org.eclipse.ui.texteditor.AnnotationPreference; import org.eclipse.ui.texteditor.DefaultMarkerAnnotationAccess; -import org.eclipse.ui.texteditor.IDocumentProvider; import org.eclipse.cdt.ui.CUIPlugin; +import org.eclipse.cdt.internal.ui.CPluginImages; import org.eclipse.cdt.internal.ui.editor.CAnnotationIterator; -import org.eclipse.cdt.internal.ui.editor.CEditor; -import org.eclipse.cdt.internal.ui.text.HTMLPrinter; /** * AbstractAnnotationHover @@ -37,42 +90,585 @@ import org.eclipse.cdt.internal.ui.text.HTMLPrinter; */ public class AbstractAnnotationHover extends AbstractCEditorTextHover { - private IPreferenceStore fStore= CUIPlugin.getDefault().getCombinedPreferenceStore(); - private DefaultMarkerAnnotationAccess fAnnotationAccess= new DefaultMarkerAnnotationAccess(); - private boolean fAllAnnotations; + /** + * An annotation info contains information about an {@link Annotation} + * + * @since 5.0 + */ + protected static class AnnotationInfo { + public final Annotation annotation; + public final Position position; + public final ITextViewer viewer; + + public AnnotationInfo(Annotation annotation, Position position, ITextViewer textViewer) { + this.annotation= annotation; + this.position= position; + this.viewer= textViewer; + } + + /** + * Create completion proposals which can resolve the given annotation at + * the given position. Returns an empty array if no such proposals exist. + * + * @return the proposals or an empty array + */ + public ICompletionProposal[] getCompletionProposals() { + return new ICompletionProposal[0]; + } + + /** + * Adds actions to the given toolbar. + * + * @param manager the toolbar manager to add actions to + * @param infoControl the information control + */ + public void fillToolBar(ToolBarManager manager, IInformationControl infoControl) { + ConfigureAnnotationsAction configureAnnotationsAction= new ConfigureAnnotationsAction(annotation, infoControl); + manager.add(configureAnnotationsAction); + } + } + + /** + * The annotation information control shows informations about a given + * {@link AbstractAnnotationHover.AnnotationInfo}. It can also show a toolbar + * and a list of {@link ICompletionProposal}s. + * + * @since 5.0 + */ + private static class AnnotationInformationControl extends AbstractInformationControl implements IInformationControlExtension2 { + private final DefaultMarkerAnnotationAccess fMarkerAnnotationAccess; + private Control fFocusControl; + private AnnotationInfo fInput; + private Composite fParent; + + public AnnotationInformationControl(Shell parentShell, String statusFieldText) { + super(parentShell, statusFieldText); + + fMarkerAnnotationAccess= new DefaultMarkerAnnotationAccess(); + create(); + } + + public AnnotationInformationControl(Shell parentShell, ToolBarManager toolBarManager) { + super(parentShell, toolBarManager); + + fMarkerAnnotationAccess= new DefaultMarkerAnnotationAccess(); + create(); + } + + /* + * @see org.eclipse.jface.text.IInformationControl#setInformation(java.lang.String) + */ + @Override + public void setInformation(String information) { + //replaced by IInformationControlExtension2#setInput + } + + /* + * @see org.eclipse.jface.text.IInformationControlExtension2#setInput(java.lang.Object) + */ + public void setInput(Object input) { + Assert.isLegal(input instanceof AnnotationInfo); + fInput= (AnnotationInfo)input; + disposeDeferredCreatedContent(); + deferredCreateContent(); + } + + /* + * @see org.eclipse.jface.text.IInformationControlExtension#hasContents() + */ + public boolean hasContents() { + return fInput != null; + } + + private AnnotationInfo getAnnotationInfo() { + return fInput; + } + + /* + * @see org.eclipse.jdt.internal.ui.text.java.hover.AbstractAnnotationHover.AbstractInformationControl#setFocus() + */ + @Override + public void setFocus() { + super.setFocus(); + if (fFocusControl != null) + fFocusControl.setFocus(); + } + + /* + * @see org.eclipse.jface.text.AbstractInformationControl#setVisible(boolean) + */ + @Override + public final void setVisible(boolean visible) { + if (!visible) + disposeDeferredCreatedContent(); + super.setVisible(visible); + } + + protected void disposeDeferredCreatedContent() { + Control[] children= fParent.getChildren(); + for (int i= 0; i < children.length; i++) { + children[i].dispose(); + } + ToolBarManager toolBarManager= getToolBarManager(); + if (toolBarManager != null) + toolBarManager.removeAll(); + } + + /* + * @see org.eclipse.jface.text.AbstractInformationControl#createContent(org.eclipse.swt.widgets.Composite) + */ + @Override + protected void createContent(Composite parent) { + fParent= parent; + GridLayout layout= new GridLayout(1, false); + layout.verticalSpacing= 0; + layout.marginWidth= 0; + layout.marginHeight= 0; + fParent.setLayout(layout); + } + + /* + * @see org.eclipse.jface.text.AbstractInformationControl#computeSizeHint() + */ + @Override + public Point computeSizeHint() { + Point preferedSize= getShell().computeSize(SWT.DEFAULT, SWT.DEFAULT, true); + + Point constrains= getSizeConstraints(); + if (constrains == null) + return preferedSize; + + Point constrainedSize= getShell().computeSize(constrains.x, SWT.DEFAULT, true); + + int width= Math.min(preferedSize.x, constrainedSize.x); + int height= Math.max(preferedSize.y, constrainedSize.y); + + return new Point(width, height); + } + + /** + * Fills the toolbar actions, if a toolbar is available. This + * is called after the input has been set. + */ + protected void fillToolbar() { + ToolBarManager toolBarManager= getToolBarManager(); + if (toolBarManager == null) + return; + fInput.fillToolBar(toolBarManager, this); + toolBarManager.update(true); + } + + /** + * Create content of the hover. This is called after + * the input has been set. + */ + protected void deferredCreateContent() { + fillToolbar(); + + createAnnotationInformation(fParent, getAnnotationInfo().annotation); + setColorAndFont(fParent, fParent.getForeground(), fParent.getBackground(), JFaceResources.getDialogFont()); + + ICompletionProposal[] proposals= getAnnotationInfo().getCompletionProposals(); + if (proposals.length > 0) + createCompletionProposalsControl(fParent, proposals); + + fParent.layout(true); + } + + private void setColorAndFont(Control control, Color foreground, Color background, Font font) { + control.setForeground(foreground); + control.setBackground(background); + control.setFont(font); + + if (control instanceof Composite) { + Control[] children= ((Composite) control).getChildren(); + for (int i= 0; i < children.length; i++) { + setColorAndFont(children[i], foreground, background, font); + } + } + } + + private void createAnnotationInformation(Composite parent, final Annotation annotation) { + Composite composite= new Composite(parent, SWT.NONE); + composite.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); + GridLayout layout= new GridLayout(2, false); + layout.marginHeight= 2; + layout.marginWidth= 2; + layout.horizontalSpacing= 0; + composite.setLayout(layout); + + final Canvas canvas= new Canvas(composite, SWT.NO_FOCUS); + GridData gridData= new GridData(SWT.BEGINNING, SWT.BEGINNING, false, false); + gridData.widthHint= 17; + gridData.heightHint= 16; + canvas.setLayoutData(gridData); + canvas.addPaintListener(new PaintListener() { + public void paintControl(PaintEvent e) { + e.gc.setFont(null); + fMarkerAnnotationAccess.paint(annotation, e.gc, canvas, new Rectangle(0, 0, 16, 16)); + } + }); + + StyledText text= new StyledText(composite, SWT.MULTI | SWT.WRAP | SWT.READ_ONLY); + GridData data= new GridData(SWT.FILL, SWT.FILL, true, true); + text.setLayoutData(data); + text.setText(annotation.getText()); + } + + private void createCompletionProposalsControl(Composite parent, ICompletionProposal[] proposals) { + Composite composite= new Composite(parent, SWT.NONE); + composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + GridLayout layout2= new GridLayout(1, false); + layout2.marginHeight= 0; + layout2.marginWidth= 0; + layout2.verticalSpacing= 2; + composite.setLayout(layout2); + + Label separator= new Label(composite, SWT.SEPARATOR | SWT.HORIZONTAL); + GridData gridData= new GridData(SWT.FILL, SWT.CENTER, true, false); + separator.setLayoutData(gridData); + + Label quickFixLabel= new Label(composite, SWT.NONE); + GridData layoutData= new GridData(SWT.BEGINNING, SWT.CENTER, false, false); + layoutData.horizontalIndent= 4; + quickFixLabel.setLayoutData(layoutData); + String text; + if (proposals.length == 1) { + text= CHoverMessages.AbstractAnnotationHover_message_singleQuickFix; + } else { + text= MessageFormat.format(CHoverMessages.AbstractAnnotationHover_message_multipleQuickFix, String.valueOf(proposals.length)); + } + quickFixLabel.setText(text); + + setColorAndFont(composite, parent.getForeground(), parent.getBackground(), JFaceResources.getDialogFont()); + createCompletionProposalsList(composite, proposals); + } + + private void createCompletionProposalsList(Composite parent, ICompletionProposal[] proposals) { + final ScrolledComposite scrolledComposite= new ScrolledComposite(parent, SWT.V_SCROLL | SWT.H_SCROLL); + GridData gridData= new GridData(SWT.FILL, SWT.FILL, true, true); + scrolledComposite.setLayoutData(gridData); + scrolledComposite.setExpandVertical(false); + scrolledComposite.setExpandHorizontal(false); + + Composite composite= new Composite(scrolledComposite, SWT.NONE); + composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + GridLayout layout= new GridLayout(3, false); + layout.verticalSpacing= 2; + composite.setLayout(layout); + + final Link[] links= new Link[proposals.length]; + for (int i= 0; i < proposals.length; i++) { + Label indent= new Label(composite, SWT.NONE); + GridData gridData1= new GridData(SWT.BEGINNING, SWT.CENTER, false, false); + gridData1.widthHint= 0; + indent.setLayoutData(gridData1); + + links[i]= createCompletionProposalLink(composite, proposals[i]); + } + + scrolledComposite.setContent(composite); + setColorAndFont(scrolledComposite, parent.getForeground(), parent.getBackground(), JFaceResources.getDialogFont()); + + Point contentSize= composite.computeSize(SWT.DEFAULT, SWT.DEFAULT); + composite.setSize(contentSize); + + Point constraints= getSizeConstraints(); + if (constraints != null && contentSize.x < constraints.x) { + ScrollBar horizontalBar= scrolledComposite.getHorizontalBar(); + + int scrollBarHeight; + if (horizontalBar == null) { + Point scrollSize= scrolledComposite.computeSize(SWT.DEFAULT, SWT.DEFAULT); + scrollBarHeight= scrollSize.y - contentSize.y; + } else { + scrollBarHeight= horizontalBar.getSize().y; + } + gridData.heightHint= contentSize.y - scrollBarHeight; + } + + fFocusControl= links[0]; + for (int i= 0; i < links.length; i++) { + final int index= i; + final Link link= links[index]; + link.addKeyListener(new KeyListener() { + public void keyPressed(KeyEvent e) { + switch (e.keyCode) { + case SWT.ARROW_DOWN: + if (index + 1 < links.length) { + links[index + 1].setFocus(); + } + break; + case SWT.ARROW_UP: + if (index > 0) { + links[index - 1].setFocus(); + } + break; + default: + break; + } + } + + public void keyReleased(KeyEvent e) { + } + }); + + link.addFocusListener(new FocusListener() { + public void focusGained(FocusEvent e) { + int currentPosition= scrolledComposite.getOrigin().y; + int hight= scrolledComposite.getSize().y; + int linkPosition= link.getLocation().y; + + if (linkPosition < currentPosition) { + if (linkPosition < 10) + linkPosition= 0; + + scrolledComposite.setOrigin(0, linkPosition); + } else if (linkPosition + 20 > currentPosition + hight) { + scrolledComposite.setOrigin(0, linkPosition - hight + link.getSize().y); + } + } + + public void focusLost(FocusEvent e) { + } + }); + } + } + + private Link createCompletionProposalLink(Composite parent, final ICompletionProposal proposal) { + Label proposalImage= new Label(parent, SWT.NONE); + proposalImage.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, false, false)); + Image image= proposal.getImage(); + if (image != null) { + proposalImage.setImage(image); + + proposalImage.addMouseListener(new MouseListener() { + + public void mouseDoubleClick(MouseEvent e) { + } + + public void mouseDown(MouseEvent e) { + } + + public void mouseUp(MouseEvent e) { + if (e.button == 1) { + apply(proposal, fInput.viewer, fInput.position.offset); + } + } + + }); + } + + Link proposalLink= new Link(parent, SWT.WRAP); + proposalLink.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, false, false)); + proposalLink.setText("" + proposal.getDisplayString() + ""); //$NON-NLS-1$ //$NON-NLS-2$ + proposalLink.addSelectionListener(new SelectionAdapter() { + /* + * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent) + */ + @Override + public void widgetSelected(SelectionEvent e) { + apply(proposal, fInput.viewer, fInput.position.offset); + } + }); + + return proposalLink; + } + + private void apply(ICompletionProposal p, ITextViewer viewer, int offset) { + //Focus needs to be in the text viewer, otherwise linked mode does not work + dispose(); + + IRewriteTarget target= null; + try { + IDocument document= viewer.getDocument(); + + if (viewer instanceof ITextViewerExtension) { + ITextViewerExtension extension= (ITextViewerExtension) viewer; + target= extension.getRewriteTarget(); + } + + if (target != null) + target.beginCompoundChange(); + + if (p instanceof ICompletionProposalExtension2) { + ICompletionProposalExtension2 e= (ICompletionProposalExtension2) p; + e.apply(viewer, (char) 0, SWT.NONE, offset); + } else if (p instanceof ICompletionProposalExtension) { + ICompletionProposalExtension e= (ICompletionProposalExtension) p; + e.apply(document, (char) 0, offset); + } else { + p.apply(document); + } + + Point selection= p.getSelection(document); + if (selection != null) { + viewer.setSelectedRange(selection.x, selection.y); + viewer.revealRange(selection.x, selection.y); + } + } finally { + if (target != null) + target.endCompoundChange(); + } + } + } + + /** + * Presenter control creator. + * + * @since 5.0 + */ + private static final class PresenterControlCreator extends AbstractReusableInformationControlCreator { + /* + * @see org.eclipse.jdt.internal.ui.text.java.hover.AbstractReusableInformationControlCreator#doCreateInformationControl(org.eclipse.swt.widgets.Shell) + */ + @Override + public IInformationControl doCreateInformationControl(Shell parent) { + return new AnnotationInformationControl(parent, new ToolBarManager(SWT.FLAT)); + } + } + + + /** + * Hover control creator. + * + * @since 5.0 + */ + private static final class HoverControlCreator extends AbstractReusableInformationControlCreator { + private final IInformationControlCreator fPresenterControlCreator; + + public HoverControlCreator(IInformationControlCreator presenterControlCreator) { + fPresenterControlCreator= presenterControlCreator; + } + + /* + * @see org.eclipse.jdt.internal.ui.text.java.hover.AbstractReusableInformationControlCreator#doCreateInformationControl(org.eclipse.swt.widgets.Shell) + */ + @Override + public IInformationControl doCreateInformationControl(Shell parent) { + return new AnnotationInformationControl(parent, EditorsUI.getTooltipAffordanceString()) { + /* + * @see org.eclipse.jface.text.IInformationControlExtension5#getInformationPresenterControlCreator() + */ + @Override + public IInformationControlCreator getInformationPresenterControlCreator() { + return fPresenterControlCreator; + } + }; + } + + /* + * @see org.eclipse.jdt.internal.ui.text.java.hover.AbstractReusableInformationControlCreator#canReuse(org.eclipse.jface.text.IInformationControl) + */ + @Override + public boolean canReuse(IInformationControl control) { + if (!super.canReuse(control)) + return false; + + if (control instanceof IInformationControlExtension4) + ((IInformationControlExtension4) control).setStatusText(EditorsUI.getTooltipAffordanceString()); + + return true; + } + } + /** + * Action to configure the annotation preferences. + * + * @since 5.0 + */ + private static final class ConfigureAnnotationsAction extends Action { + + private final Annotation fAnnotation; + private final IInformationControl fInfoControl; + + public ConfigureAnnotationsAction(Annotation annotation, IInformationControl infoControl) { + super(); + fAnnotation= annotation; + fInfoControl= infoControl; + setImageDescriptor(CPluginImages.DESC_ELCL_CONFIGURE_ANNOTATIONS); + setDisabledImageDescriptor(CPluginImages.DESC_DLCL_CONFIGURE_ANNOTATIONS); + setToolTipText(CHoverMessages.AbstractAnnotationHover_action_configureAnnotationPreferences); + } + + /* + * @see org.eclipse.jface.action.Action#run() + */ + @Override + public void run() { + Shell shell= PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(); + + Object data= null; + AnnotationPreference preference= getAnnotationPreference(fAnnotation); + if (preference != null) + data= preference.getPreferenceLabel(); + + fInfoControl.dispose(); //FIXME: should have protocol to hide, rather than dispose + PreferencesUtil.createPreferenceDialogOn(shell, "org.eclipse.ui.editors.preferencePages.Annotations", null, data).open(); //$NON-NLS-1$ + } + } + + private final IPreferenceStore fStore= CUIPlugin.getDefault().getCombinedPreferenceStore(); + private final DefaultMarkerAnnotationAccess fAnnotationAccess= new DefaultMarkerAnnotationAccess(); + private final boolean fAllAnnotations; + + /** + * The hover control creator. + * + * @since 5.0 + */ + private IInformationControlCreator fHoverControlCreator; + /** + * The presentation control creator. + * + * @since 5.0 + */ + private IInformationControlCreator fPresenterControlCreator; public AbstractAnnotationHover(boolean allAnnotations) { fAllAnnotations= allAnnotations; } /* - * Formats a message as HTML text. - */ - private String formatMessage(String message) { - StringBuffer buffer= new StringBuffer(); - HTMLPrinter.addPageProlog(buffer); - HTMLPrinter.addParagraph(buffer, HTMLPrinter.convertToHTMLContent(message)); - HTMLPrinter.addPageEpilog(buffer); - return buffer.toString(); - } - - /* - * @see ITextHover#getHoverInfo(ITextViewer, IRegion) + * @see org.eclipse.jface.text.ITextHover#getHoverInfo(org.eclipse.jface.text.ITextViewer, org.eclipse.jface.text.IRegion) */ @Override public String getHoverInfo(ITextViewer textViewer, IRegion hoverRegion) { - - if (getEditor() == null) + return null; + } + + /* + * @see org.eclipse.jdt.internal.ui.text.java.hover.AbstractJavaEditorTextHover#getHoverInfo2(org.eclipse.jface.text.ITextViewer, org.eclipse.jface.text.IRegion) + * @since 5.0 + */ + @Override + public Object getHoverInfo2(ITextViewer textViewer, IRegion hoverRegion) { + IPath path; + IAnnotationModel model; + if (textViewer instanceof ISourceViewer) { + path= null; + model= ((ISourceViewer)textViewer).getAnnotationModel(); + } else { + // Get annotation model from file buffer manager + path= getEditorInputPath(); + model= getAnnotationModel(path); + } + if (model == null) return null; - - IDocumentProvider provider= CUIPlugin.getDefault().getDocumentProvider(); - IAnnotationModel model= provider.getAnnotationModel(getEditor().getEditorInput()); - - if (model != null) { - Iterator e= new CAnnotationIterator(model, true, fAllAnnotations); + + try { + @SuppressWarnings("unchecked") + Iterator parent; + if (model instanceof IAnnotationModelExtension2) + parent= ((IAnnotationModelExtension2) model).getAnnotationIterator(hoverRegion.getOffset(), hoverRegion.getLength(), true, true); + else + parent= model.getAnnotationIterator(); + @SuppressWarnings("unchecked") + Iterator e= new CAnnotationIterator(parent, fAllAnnotations); + int layer= -1; - String message= null; + Annotation annotation= null; + Position position= null; while (e.hasNext()) { Annotation a= e.next(); @@ -81,33 +677,101 @@ public class AbstractAnnotationHover extends AbstractCEditorTextHover { continue; Position p= model.getPosition(a); - + int l= fAnnotationAccess.getLayer(a); - + if (l > layer && p != null && p.overlapsWith(hoverRegion.getOffset(), hoverRegion.getLength())) { String msg= a.getText(); if (msg != null && msg.trim().length() > 0) { - message= msg; layer= l; + annotation= a; + position= p; } } } if (layer > -1) - return formatMessage(message); + return createAnnotationInfo(annotation, position, textViewer); + + } finally { + try { + if (path != null) { + ITextFileBufferManager manager= FileBuffers.getTextFileBufferManager(); + manager.disconnect(path, LocationKind.NORMALIZE, null); + } + } catch (CoreException e) { + CUIPlugin.log(e.getStatus()); + } } - + return null; } - + + protected AnnotationInfo createAnnotationInfo(Annotation annotation, Position position, ITextViewer textViewer) { + return new AnnotationInfo(annotation, position, textViewer); + } + /* - * @see IJavaEditorTextHover#setEditor(IEditorPart) + * @see ITextHoverExtension#getHoverControlCreator() + * @since 5.0 */ @Override - public void setEditor(IEditorPart editor) { - if (editor instanceof CEditor) - super.setEditor(editor); - else - super.setEditor(null); + public IInformationControlCreator getHoverControlCreator() { + if (fHoverControlCreator == null) + fHoverControlCreator= new HoverControlCreator(getInformationPresenterControlCreator()); + return fHoverControlCreator; + } + + /* + * @see org.eclipse.jface.text.ITextHoverExtension2#getInformationPresenterControlCreator() + * @since 5.0 + */ + @Override + public IInformationControlCreator getInformationPresenterControlCreator() { + if (fPresenterControlCreator == null) + fPresenterControlCreator= new PresenterControlCreator(); + return fPresenterControlCreator; + } + + private IPath getEditorInputPath() { + if (getEditor() == null) + return null; + + IEditorInput input= getEditor().getEditorInput(); + if (input instanceof IStorageEditorInput) { + try { + return ((IStorageEditorInput)input).getStorage().getFullPath(); + } catch (CoreException e) { + CUIPlugin.log(e.getStatus()); + } + } + return null; + } + + private IAnnotationModel getAnnotationModel(IPath path) { + if (path == null) + return null; + + ITextFileBufferManager manager= FileBuffers.getTextFileBufferManager(); + try { + manager.connect(path, LocationKind.NORMALIZE, null); + } catch (CoreException e) { + CUIPlugin.log(e.getStatus()); + return null; + } + + IAnnotationModel model= null; + try { + model= manager.getTextFileBuffer(path, LocationKind.NORMALIZE).getAnnotationModel(); + return model; + } finally { + if (model == null) { + try { + manager.disconnect(path, LocationKind.NORMALIZE, null); + } catch (CoreException e) { + CUIPlugin.log(e.getStatus()); + } + } + } } /** @@ -115,12 +779,10 @@ public class AbstractAnnotationHover extends AbstractCEditorTextHover { * * @param annotation the annotation * @return the annotation preference or null if none - */ - private AnnotationPreference getAnnotationPreference(Annotation annotation) { - + */ + private static AnnotationPreference getAnnotationPreference(Annotation annotation) { if (annotation.isMarkedDeleted()) return null; return EditorsUI.getAnnotationPreferenceLookup().getAnnotationPreference(annotation); } - } diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CHoverMessages.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CHoverMessages.java index 47d0390a405..b4c1b9e2acc 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CHoverMessages.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CHoverMessages.java @@ -8,6 +8,7 @@ * Contributors: * QNX Software Systems - Initial API and implementation * Anton Leherbauer (Wind River Systems) + * Sergey Prigogin (Google) *******************************************************************************/ package org.eclipse.cdt.internal.ui.text.c.hover; @@ -21,6 +22,10 @@ public final class CHoverMessages extends NLS { // Do not instantiate } + public static String AbstractAnnotationHover_action_configureAnnotationPreferences; + public static String AbstractAnnotationHover_message_singleQuickFix; + public static String AbstractAnnotationHover_message_multipleQuickFix; + public static String CMacroExpansionControl_statusText; public static String CMacroExpansionControl_title_expansion; diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CHoverMessages.properties b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CHoverMessages.properties index b0b833490c5..303793fa34a 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CHoverMessages.properties +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CHoverMessages.properties @@ -8,8 +8,13 @@ # Contributors: # IBM Corporation - initial API and implementation # Anton Leherbauer (Wind River Systems) +# Sergey Prigogin (Google) ############################################################################### +AbstractAnnotationHover_action_configureAnnotationPreferences= Configure Annotation Preferences +AbstractAnnotationHover_message_singleQuickFix= 1 quick fix available: +AbstractAnnotationHover_message_multipleQuickFix= {0} quick fixes available: + CMacroExpansionControl_statusText=Press {0} or {1} to step through macro expansion CMacroExpansionControl_title_expansion=Expansion \#{0} of {1} CMacroExpansionControl_title_fullyExpanded=Fully Expanded diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CInformationProvider.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CInformationProvider.java index 8f84d911bc9..b53fe9846d4 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CInformationProvider.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CInformationProvider.java @@ -8,6 +8,7 @@ * Contributors: * IBM Corporation - initial API and implementation * Anton Leherbauer (Wind River Systems) + * Sergey Prigogin (Google) *******************************************************************************/ package org.eclipse.cdt.internal.ui.text.c.hover; @@ -25,13 +26,11 @@ import org.eclipse.ui.IPartListener; import org.eclipse.ui.IWorkbenchPart; import org.eclipse.ui.IWorkbenchWindow; -import org.eclipse.cdt.ui.text.c.hover.ICEditorTextHover; - - /** - * Provides information for the current word under the cursor based on the documentation hover. + * Provides information for the current word under the cursor based on the documentation hover + * and spelling correction hover. * - * @see CDocHover + * @see CTypeHover * @since 5.0 */ public class CInformationProvider implements IInformationProvider, IInformationProviderExtension2 { @@ -70,23 +69,21 @@ public class CInformationProvider implements IInformationProvider, IInformationP protected IEditorPart fEditor; protected IPartListener fPartListener; - protected ICEditorTextHover fImplementation; + protected CTypeHover fImplementation; /** * The default presentation control creator. */ private IInformationControlCreator fPresenterControlCreator; - public CInformationProvider(IEditorPart editor) { - fEditor= editor; if (fEditor != null) { fPartListener= new EditorWatcher(); IWorkbenchWindow window= fEditor.getSite().getWorkbenchWindow(); window.getPartService().addPartListener(fPartListener); - fImplementation= new CDocHover(); + fImplementation= new CTypeHover(); fImplementation.setEditor(fEditor); } } @@ -104,7 +101,6 @@ public class CInformationProvider implements IInformationProvider, IInformationP /* * @see IInformationProvider#getInformation(ITextViewer, IRegion) */ - @SuppressWarnings("deprecation") public String getInformation(ITextViewer textViewer, IRegion subject) { if (fImplementation != null) { String s= fImplementation.getHoverInfo(textViewer, subject); @@ -115,6 +111,15 @@ public class CInformationProvider implements IInformationProvider, IInformationP return null; } + /* + * @see org.eclipse.jface.text.information.IInformationProviderExtension#getInformation2(org.eclipse.jface.text.ITextViewer, org.eclipse.jface.text.IRegion) + */ + public Object getInformation2(ITextViewer textViewer, IRegion subject) { + if (fImplementation == null) + return null; + return fImplementation.getHoverInfo2(textViewer, subject); + } + /* * @see IInformationProviderExtension2#getInformationPresenterControlCreator() */ diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CTypeHover.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CTypeHover.java new file mode 100644 index 00000000000..258ab067339 --- /dev/null +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CTypeHover.java @@ -0,0 +1,90 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 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 + * Sergey Prigogin (Google) + *******************************************************************************/ +package org.eclipse.cdt.internal.ui.text.c.hover; + +import org.eclipse.jface.text.IInformationControlCreator; +import org.eclipse.jface.text.IRegion; +import org.eclipse.jface.text.ITextHoverExtension; +import org.eclipse.jface.text.ITextHoverExtension2; +import org.eclipse.jface.text.ITextViewer; + +import org.eclipse.ui.IEditorPart; + +import org.eclipse.cdt.ui.text.c.hover.ICEditorTextHover; + +/** + * Aggregator of problem and doc hovers. + * @since 5.0 + */ +public class CTypeHover implements ICEditorTextHover, ITextHoverExtension, ITextHoverExtension2 { + private AbstractCEditorTextHover fProblemHover; + private AbstractCEditorTextHover fCDocHover; + + private AbstractCEditorTextHover fCurrentHover; + + public CTypeHover() { + fProblemHover= new ProblemHover(); + fCDocHover= new CDocHover(); + fCurrentHover= null; + } + + /* + * @see ICEditorTextHover#setEditor(IEditorPart) + */ + public void setEditor(IEditorPart editor) { + fProblemHover.setEditor(editor); + fCDocHover.setEditor(editor); + fCurrentHover= null; + } + + /* + * @see ITextHover#getHoverRegion(ITextViewer, int) + */ + public IRegion getHoverRegion(ITextViewer textViewer, int offset) { + return fCDocHover.getHoverRegion(textViewer, offset); + } + + /* + * @see ITextHover#getHoverInfo(ITextViewer, IRegion) + */ + public String getHoverInfo(ITextViewer textViewer, IRegion hoverRegion) { + return String.valueOf(getHoverInfo2(textViewer, hoverRegion)); + } + + /* + * @see org.eclipse.jface.text.ITextHoverExtension2#getHoverInfo2(org.eclipse.jface.text.ITextViewer, org.eclipse.jface.text.IRegion) + */ + public Object getHoverInfo2(ITextViewer textViewer, IRegion hoverRegion) { + Object hoverInfo= fProblemHover.getHoverInfo2(textViewer, hoverRegion); + if (hoverInfo != null) { + fCurrentHover= fProblemHover; + return hoverInfo; + } + + fCurrentHover= fCDocHover; + return fCDocHover.getHoverInfo2(textViewer, hoverRegion); + } + + /* + * @see org.eclipse.jface.text.ITextHoverExtension#getHoverControlCreator() + */ + public IInformationControlCreator getHoverControlCreator() { + return fCurrentHover == null ? null : fCurrentHover.getHoverControlCreator(); + } + + /* + * @see org.eclipse.jface.text.information.IInformationProviderExtension2#getInformationPresenterControlCreator() + */ + public IInformationControlCreator getInformationPresenterControlCreator() { + return fCurrentHover == null ? null : fCurrentHover.getInformationPresenterControlCreator(); + } +} diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/ProblemHover.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/ProblemHover.java new file mode 100644 index 00000000000..5f02f3b31ca --- /dev/null +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/ProblemHover.java @@ -0,0 +1,140 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 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 + * Sergey Prigogin (Google) + *******************************************************************************/ +package org.eclipse.cdt.internal.ui.text.c.hover; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.eclipse.core.resources.IMarker; +import org.eclipse.jface.text.ITextViewer; +import org.eclipse.jface.text.Position; +import org.eclipse.jface.text.contentassist.ICompletionProposal; +import org.eclipse.jface.text.source.Annotation; +import org.eclipse.jface.text.source.IAnnotationModel; +import org.eclipse.jface.text.source.ISourceViewer; +import org.eclipse.ui.IEditorInput; +import org.eclipse.ui.texteditor.MarkerAnnotation; +import org.eclipse.ui.texteditor.spelling.SpellingAnnotation; + +import org.eclipse.cdt.core.model.CModelException; +import org.eclipse.cdt.core.model.ITranslationUnit; +import org.eclipse.cdt.ui.CUIPlugin; +import org.eclipse.cdt.ui.text.ICCompletionProposal; +import org.eclipse.cdt.ui.text.IProblemLocation; + +import org.eclipse.cdt.internal.ui.editor.ICAnnotation; +import org.eclipse.cdt.internal.ui.text.contentassist.CCompletionProposalComparator; +import org.eclipse.cdt.internal.ui.text.correction.CCorrectionProcessor; +import org.eclipse.cdt.internal.ui.text.correction.CorrectionContext; +import org.eclipse.cdt.internal.ui.text.correction.ProblemLocation; +import org.eclipse.cdt.internal.ui.util.EditorUtility; + +/** + * This annotation hover shows the description of the + * selected java annotation. + * + * XXX: Currently this problem hover only works for spelling problems. + * see: https://bugs.eclipse.org/bugs/show_bug.cgi?id=62081 + * + * @since 5.0 + */ +public class ProblemHover extends AbstractAnnotationHover { + + protected static class ProblemInfo extends AnnotationInfo { + private static final ICompletionProposal[] NO_PROPOSALS= new ICompletionProposal[0]; + + public ProblemInfo(Annotation annotation, Position position, ITextViewer textViewer) { + super(annotation, position, textViewer); + } + + /* + * @see org.eclipse.cdt.internal.ui.text.java.hover.AbstractAnnotationHover.AnnotationInfo#getCompletionProposals() + */ + @Override + public ICompletionProposal[] getCompletionProposals() { + if (annotation instanceof ICAnnotation) { + return getCAnnotationFixes((ICAnnotation) annotation); + } else if (annotation instanceof MarkerAnnotation) { + return getMarkerAnnotationFixes((MarkerAnnotation) annotation); + } + + return NO_PROPOSALS; + } + + private ICompletionProposal[] getCAnnotationFixes(ICAnnotation cAnnotation) { + ProblemLocation location= new ProblemLocation(position.getOffset(), position.getLength(), cAnnotation); + ITranslationUnit tu= cAnnotation.getTranslationUnit(); + + ISourceViewer sourceViewer= null; + if (viewer instanceof ISourceViewer) + sourceViewer= (ISourceViewer) viewer; + + CorrectionContext context= new CorrectionContext(tu, sourceViewer, location.getOffset(), location.getLength()); + if (!SpellingAnnotation.TYPE.equals(cAnnotation.getType())) + return NO_PROPOSALS; + + List proposals= new ArrayList(); + CCorrectionProcessor.collectCorrections(context, new IProblemLocation[] { location }, proposals); + Collections.sort(proposals, new CCompletionProposalComparator()); + + return proposals.toArray(new ICompletionProposal[proposals.size()]); + } + + private ICompletionProposal[] getMarkerAnnotationFixes(MarkerAnnotation markerAnnotation) { + if (markerAnnotation.isQuickFixableStateSet() && !markerAnnotation.isQuickFixable()) + return NO_PROPOSALS; + + IMarker marker= markerAnnotation.getMarker(); + + IEditorInput input = null; + try { + input = EditorUtility.getEditorInput(marker.getResource()); + } catch (CModelException e) { + } + if (input == null) + return NO_PROPOSALS; + + ITranslationUnit tu= getTranslationUnit(input); + if (tu == null) + return NO_PROPOSALS; + + IAnnotationModel model= CUIPlugin.getDefault().getDocumentProvider().getAnnotationModel(input); + if (model == null) + return NO_PROPOSALS; + + ISourceViewer sourceViewer= null; + if (viewer instanceof ISourceViewer) + sourceViewer= (ISourceViewer) viewer; + + CorrectionContext context= new CorrectionContext(tu, sourceViewer, position.getOffset(), position.getLength()); + + List proposals= new ArrayList(); + CCorrectionProcessor.collectProposals(context, model, new Annotation[] { markerAnnotation }, true, false, proposals); + + return proposals.toArray(new ICompletionProposal[proposals.size()]); + } + + private static ITranslationUnit getTranslationUnit(IEditorInput input) { + return CUIPlugin.getDefault().getWorkingCopyManager().getWorkingCopy(input); + } + } + + public ProblemHover() { + super(false); + } + + @Override + protected AnnotationInfo createAnnotationInfo(Annotation annotation, Position position, ITextViewer textViewer) { + return new ProblemInfo(annotation, position, textViewer); + } +} diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/CUIPlugin.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/CUIPlugin.java index 371b7c4c8e1..d383be1ce2a 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/CUIPlugin.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/CUIPlugin.java @@ -11,6 +11,7 @@ * Markus Schorn (Wind River Systems) * Anton Leherbauer (Wind River Systems) * Jeff Johnston (Red Hat Inc.) + * Sergey Prigogin (Google) *******************************************************************************/ package org.eclipse.cdt.ui; @@ -760,7 +761,7 @@ public class CUIPlugin extends AbstractUIPlugin { fCEditorTextHoverDescriptors[first]= hoverDescriptor; // update annotation hover index if needed - if (annotationHoverIndex > first && annotationHoverIndex < problemHoverIndex) + if (annotationHoverIndex >= first && annotationHoverIndex < problemHoverIndex) annotationHoverIndex++; }