mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-04-23 22:52:11 +02:00
Bug 476797 - Port Expand annotation hover from JDT
Ported the JDT expand annotation hover code into CDT & adapted. Added preference to control in equivalent location to JDT. Default is disabled for now. Changed behaviour from JDT version - * Breakpoint annotations & add breakpoint option displayed last * Tooltips displayed with no delay after expanded hover is displayed * Reverted fix for bug 165533 due to issue where single click on 1st item in expanded hover also triggers single click on top item in ruler if mouse within ruler area (Same as JDT) Known issues - * Double click on ruler column sometimes triggers single click on 1st item in expanded hover if user is too slow (Same as JDT) Change-Id: I87c2f8efd04ea5084b056241a04758a368e2ca55 Signed-off-by: William Riley <william.riley@renesas.com>
This commit is contained in:
parent
739281bec7
commit
c297330c9c
14 changed files with 1765 additions and 16 deletions
|
@ -2,7 +2,7 @@ Manifest-Version: 1.0
|
|||
Bundle-ManifestVersion: 2
|
||||
Bundle-Name: %pluginName
|
||||
Bundle-SymbolicName: org.eclipse.cdt.ui; singleton:=true
|
||||
Bundle-Version: 6.0.0.qualifier
|
||||
Bundle-Version: 6.1.0.qualifier
|
||||
Bundle-Activator: org.eclipse.cdt.ui.CUIPlugin
|
||||
Bundle-Vendor: %providerName
|
||||
Bundle-Localization: plugin
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<version>6.0.0-SNAPSHOT</version>
|
||||
<version>6.1.0-SNAPSHOT</version>
|
||||
<artifactId>org.eclipse.cdt.ui</artifactId>
|
||||
<packaging>eclipse-plugin</packaging>
|
||||
</project>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2002, 2015 QNX Software Systems and others.
|
||||
* Copyright (c) 2002, 2016 QNX Software Systems 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
|
||||
|
@ -107,7 +107,7 @@ public class CDocumentProvider extends TextFileDocumentProvider {
|
|||
/**
|
||||
* Annotation representing an {@code IProblem}.
|
||||
*/
|
||||
static protected class ProblemAnnotation extends Annotation implements ICAnnotation {
|
||||
public static class ProblemAnnotation extends Annotation implements ICAnnotation {
|
||||
private static final String INDEXER_ANNOTATION_TYPE= "org.eclipse.cdt.ui.indexmarker"; //$NON-NLS-1$
|
||||
|
||||
private final ITranslationUnit fTranslationUnit;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2005, 2015 IBM Corporation and others.
|
||||
* Copyright (c) 2005, 2016 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
|
||||
|
@ -97,6 +97,8 @@ import org.eclipse.jface.text.link.LinkedModeUI.IExitPolicy;
|
|||
import org.eclipse.jface.text.link.LinkedPosition;
|
||||
import org.eclipse.jface.text.link.LinkedPositionGroup;
|
||||
import org.eclipse.jface.text.source.Annotation;
|
||||
import org.eclipse.jface.text.source.AnnotationRulerColumn;
|
||||
import org.eclipse.jface.text.source.CompositeRuler;
|
||||
import org.eclipse.jface.text.source.IAnnotationModel;
|
||||
import org.eclipse.jface.text.source.IAnnotationModelExtension;
|
||||
import org.eclipse.jface.text.source.IAnnotationModelExtension2;
|
||||
|
@ -105,11 +107,14 @@ import org.eclipse.jface.text.source.IOverviewRuler;
|
|||
import org.eclipse.jface.text.source.ISourceViewer;
|
||||
import org.eclipse.jface.text.source.ISourceViewerExtension2;
|
||||
import org.eclipse.jface.text.source.IVerticalRuler;
|
||||
import org.eclipse.jface.text.source.IVerticalRulerColumn;
|
||||
import org.eclipse.jface.text.source.SourceViewerConfiguration;
|
||||
import org.eclipse.jface.text.source.projection.ProjectionAnnotationModel;
|
||||
import org.eclipse.jface.text.source.projection.ProjectionSupport;
|
||||
import org.eclipse.jface.text.source.projection.ProjectionViewer;
|
||||
import org.eclipse.jface.util.PropertyChangeEvent;
|
||||
import org.eclipse.jface.viewers.DoubleClickEvent;
|
||||
import org.eclipse.jface.viewers.IDoubleClickListener;
|
||||
import org.eclipse.jface.viewers.ISelection;
|
||||
import org.eclipse.jface.viewers.ISelectionChangedListener;
|
||||
import org.eclipse.jface.viewers.IStructuredSelection;
|
||||
|
@ -136,6 +141,7 @@ import org.eclipse.ui.IEditorPart;
|
|||
import org.eclipse.ui.IFileEditorInput;
|
||||
import org.eclipse.ui.IPageLayout;
|
||||
import org.eclipse.ui.IPartService;
|
||||
import org.eclipse.ui.ISelectionListener;
|
||||
import org.eclipse.ui.IWorkbenchWindow;
|
||||
import org.eclipse.ui.PlatformUI;
|
||||
import org.eclipse.ui.actions.ActionContext;
|
||||
|
@ -232,6 +238,7 @@ import org.eclipse.cdt.internal.ui.text.DocumentCharacterIterator;
|
|||
import org.eclipse.cdt.internal.ui.text.ICReconcilingListener;
|
||||
import org.eclipse.cdt.internal.ui.text.Symbols;
|
||||
import org.eclipse.cdt.internal.ui.text.TabsToSpacesConverter;
|
||||
import org.eclipse.cdt.internal.ui.text.c.hover.CExpandHover;
|
||||
import org.eclipse.cdt.internal.ui.text.c.hover.SourceViewerInformationControl;
|
||||
import org.eclipse.cdt.internal.ui.text.contentassist.ContentAssistPreference;
|
||||
import org.eclipse.cdt.internal.ui.util.CUIHelp;
|
||||
|
@ -2347,6 +2354,10 @@ public class CEditor extends TextEditor implements ICEditor, ISelectionChangedLi
|
|||
action.setActionDefinitionId(ICEditorActionDefinitionIds.SELECT_LAST);
|
||||
setAction(StructureSelectionAction.HISTORY, action);
|
||||
|
||||
// add annotation actions for roll-over expand hover
|
||||
action= new CSelectMarkerRulerAction(bundle, "Editor.RulerAnnotationSelection.", this); //$NON-NLS-1$
|
||||
setAction("AnnotationAction", action); //$NON-NLS-1$
|
||||
|
||||
|
||||
// Assorted action groupings
|
||||
fSelectionSearchGroup = createSelectionSearchGroup();
|
||||
|
@ -3651,4 +3662,39 @@ public class CEditor extends TextEditor implements ICEditor, ISelectionChangedLi
|
|||
public void removePostSaveListener(IPostSaveListener listener) {
|
||||
fPostSaveListeners.remove(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected IVerticalRulerColumn createAnnotationRulerColumn(CompositeRuler ruler) {
|
||||
if (!getPreferenceStore().getBoolean(PreferenceConstants.EDITOR_ANNOTATION_ROLL_OVER)) {
|
||||
return super.createAnnotationRulerColumn(ruler);
|
||||
}
|
||||
|
||||
AnnotationRulerColumn column= new AnnotationRulerColumn(VERTICAL_RULER_WIDTH, getAnnotationAccess());
|
||||
column.setHover(new CExpandHover(ruler, getAnnotationAccess(), new IDoubleClickListener() {
|
||||
|
||||
@Override
|
||||
public void doubleClick(DoubleClickEvent event) {
|
||||
// for now: just invoke ruler double click action
|
||||
triggerAction(ITextEditorActionConstants.RULER_DOUBLE_CLICK);
|
||||
}
|
||||
|
||||
private void triggerAction(String actionID) {
|
||||
IAction action= getAction(actionID);
|
||||
if (action != null) {
|
||||
if (action instanceof IUpdate)
|
||||
((IUpdate) action).update();
|
||||
// hack to propagate line change
|
||||
if (action instanceof ISelectionListener) {
|
||||
((ISelectionListener)action).selectionChanged(null, null);
|
||||
}
|
||||
if (action.isEnabled()) {
|
||||
action.run();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}));
|
||||
|
||||
return column;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,130 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2000, 2016 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
|
||||
* William Riley (Renesas) - Adapted for CDT
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.internal.ui.editor;
|
||||
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.widgets.Event;
|
||||
|
||||
import org.eclipse.jface.action.IAction;
|
||||
|
||||
import org.eclipse.jface.text.ITextOperationTarget;
|
||||
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.ISourceViewer;
|
||||
import org.eclipse.jface.text.source.VerticalRulerEvent;
|
||||
|
||||
import org.eclipse.ui.ISelectionListener;
|
||||
|
||||
import org.eclipse.ui.texteditor.ITextEditor;
|
||||
import org.eclipse.ui.texteditor.ITextEditorActionConstants;
|
||||
import org.eclipse.ui.texteditor.IUpdate;
|
||||
import org.eclipse.ui.texteditor.SelectAnnotationRulerAction;
|
||||
|
||||
import org.eclipse.cdt.internal.ui.text.correction.CCorrectionProcessor;
|
||||
import org.eclipse.cdt.internal.ui.text.correction.QuickAssistLightBulbUpdater.AssistAnnotation;
|
||||
import org.eclipse.cdt.internal.ui.text.c.hover.CExpandHover;
|
||||
|
||||
/**
|
||||
* A special select marker ruler action which activates quick fix if clicked on a quick fixable problem.
|
||||
* <p>
|
||||
* Originally copied from org.eclipse.jdt.internal.ui.javaeditor.JavaSelectMarkerRulerAction
|
||||
*/
|
||||
public class CSelectMarkerRulerAction extends SelectAnnotationRulerAction {
|
||||
|
||||
public CSelectMarkerRulerAction(ResourceBundle bundle, String prefix, ITextEditor editor) {
|
||||
super(bundle, prefix, editor);
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.eclipse.ui.texteditor.IVerticalRulerListener#annotationDefaultSelected(org.eclipse.ui.texteditor.VerticalRulerEvent)
|
||||
*/
|
||||
@Override
|
||||
public void annotationDefaultSelected(VerticalRulerEvent event) {
|
||||
Annotation annotation= event.getSelectedAnnotation();
|
||||
IAnnotationModel model= getAnnotationModel();
|
||||
|
||||
if (isOverrideIndicator(annotation)) {
|
||||
((OverrideIndicatorManager.OverrideIndicator)annotation).open();
|
||||
return;
|
||||
}
|
||||
|
||||
if (isBreakpoint(annotation))
|
||||
triggerAction(ITextEditorActionConstants.RULER_DOUBLE_CLICK, event.getEvent());
|
||||
|
||||
Position position= model.getPosition(annotation);
|
||||
if (position == null)
|
||||
return;
|
||||
|
||||
if (isQuickFixTarget(annotation)) {
|
||||
ITextOperationTarget operation= getTextEditor().getAdapter(ITextOperationTarget.class);
|
||||
final int opCode= ISourceViewer.QUICK_ASSIST;
|
||||
if (operation != null && operation.canDoOperation(opCode)) {
|
||||
getTextEditor().selectAndReveal(position.getOffset(), position.getLength());
|
||||
operation.doOperation(opCode);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// default:
|
||||
super.annotationDefaultSelected(event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells whether the given annotation is an override annotation.
|
||||
*
|
||||
* @param annotation the annotation
|
||||
* @return <code>true</code> iff the annotation is an override annotation
|
||||
*/
|
||||
private boolean isOverrideIndicator(Annotation annotation) {
|
||||
return annotation instanceof OverrideIndicatorManager.OverrideIndicator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the given annotation is a breakpoint annotation.
|
||||
*
|
||||
* @param annotation the annotation
|
||||
* @return <code>true</code> if the annotation is a breakpoint annotation
|
||||
*/
|
||||
private boolean isBreakpoint(Annotation annotation) {
|
||||
return annotation.getType().equals("org.eclipse.cdt.debug.core.breakpoint") || annotation.getType().equals(CExpandHover.NO_BREAKPOINT_ANNOTATION); //$NON-NLS-1$
|
||||
}
|
||||
|
||||
private boolean isQuickFixTarget(Annotation a) {
|
||||
return CCorrectionProcessor.hasCorrections(a) || a instanceof AssistAnnotation;
|
||||
}
|
||||
|
||||
private void triggerAction(String actionID, Event event) {
|
||||
IAction action= getTextEditor().getAction(actionID);
|
||||
if (action != null) {
|
||||
if (action instanceof IUpdate)
|
||||
((IUpdate) action).update();
|
||||
// hack to propagate line change
|
||||
if (action instanceof ISelectionListener) {
|
||||
((ISelectionListener)action).selectionChanged(null, null);
|
||||
}
|
||||
if (action.isEnabled()) {
|
||||
if (event == null) {
|
||||
action.run();
|
||||
} else {
|
||||
event.type= SWT.MouseDoubleClick;
|
||||
event.count= 2;
|
||||
action.runWithEvent(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -14,6 +14,8 @@ package org.eclipse.cdt.internal.ui.preferences;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import org.eclipse.core.runtime.Assert;
|
||||
|
@ -44,6 +46,7 @@ import org.eclipse.swt.graphics.Image;
|
|||
import org.eclipse.swt.graphics.Point;
|
||||
import org.eclipse.swt.layout.GridData;
|
||||
import org.eclipse.swt.layout.GridLayout;
|
||||
import org.eclipse.swt.widgets.Button;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.eclipse.swt.widgets.Control;
|
||||
import org.eclipse.swt.widgets.Label;
|
||||
|
@ -155,6 +158,19 @@ public class CEditorHoverConfigurationBlock implements IPreferenceConfigurationB
|
|||
private TableColumn fNameColumn;
|
||||
private TableColumn fModifierColumn;
|
||||
private Text fDescription;
|
||||
private Map<Button, String> fCheckBoxes= new HashMap<>();
|
||||
private SelectionListener fCheckBoxListener= new SelectionListener() {
|
||||
@Override
|
||||
public void widgetDefaultSelected(SelectionEvent e) {
|
||||
Button button= (Button) e.widget;
|
||||
fStore.setValue(fCheckBoxes.get(button), button.getSelection());
|
||||
}
|
||||
@Override
|
||||
public void widgetSelected(SelectionEvent e) {
|
||||
Button button= (Button) e.widget;
|
||||
fStore.setValue(fCheckBoxes.get(button), button.getSelection());
|
||||
}
|
||||
};
|
||||
|
||||
private PreferencePage fMainPreferencePage;
|
||||
|
||||
|
@ -173,7 +189,7 @@ public class CEditorHoverConfigurationBlock implements IPreferenceConfigurationB
|
|||
|
||||
ArrayList<OverlayKey> overlayKeys= new ArrayList<OverlayKey>();
|
||||
|
||||
//overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.BOOLEAN, PreferenceConstants.EDITOR_ANNOTATION_ROLL_OVER));
|
||||
overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.BOOLEAN, PreferenceConstants.EDITOR_ANNOTATION_ROLL_OVER));
|
||||
overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.STRING, PreferenceConstants.EDITOR_TEXT_HOVER_MODIFIERS));
|
||||
overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.STRING, PreferenceConstants.EDITOR_TEXT_HOVER_MODIFIER_MASKS));
|
||||
|
||||
|
@ -204,9 +220,8 @@ public class CEditorHoverConfigurationBlock implements IPreferenceConfigurationB
|
|||
hoverComposite.setLayout(layout);
|
||||
hoverComposite.setLayoutData(new GridData(GridData.FILL_BOTH));
|
||||
|
||||
//String rollOverLabel= PreferencesMessages.getString("CEditorHoverConfigurationBlock.annotationRollover"); //$NON-NLS-1$
|
||||
//addCheckBox(hoverComposite, rollOverLabel, PreferenceConstants.EDITOR_ANNOTATION_ROLL_OVER, 0); //$NON-NLS-1$
|
||||
|
||||
String rollOverLabel= PreferencesMessages.CEditorHoverConfigurationBlock_annotationRollover;
|
||||
addCheckBox(hoverComposite, rollOverLabel, PreferenceConstants.EDITOR_ANNOTATION_ROLL_OVER, 0); //$NON-NLS-1$
|
||||
//addFiller(hoverComposite);
|
||||
|
||||
Label label= new Label(hoverComposite, SWT.NONE);
|
||||
|
@ -384,7 +399,14 @@ public class CEditorHoverConfigurationBlock implements IPreferenceConfigurationB
|
|||
|
||||
void initializeFields() {
|
||||
fModifierEditor.setEnabled(false);
|
||||
|
||||
|
||||
Iterator<Button> e= fCheckBoxes.keySet().iterator();
|
||||
while (e.hasNext()) {
|
||||
Button b= e.next();
|
||||
String key= fCheckBoxes.get(b);
|
||||
b.setSelection(fStore.getBoolean(key));
|
||||
}
|
||||
|
||||
CEditorTextHoverDescriptor[] hoverDescs= getContributedHovers();
|
||||
for (int i= 0; i < hoverDescs.length; i++)
|
||||
fHoverTable.getItem(i).setChecked(hoverDescs[i].isEnabled());
|
||||
|
@ -546,7 +568,21 @@ public class CEditorHoverConfigurationBlock implements IPreferenceConfigurationB
|
|||
fMainPreferencePage.setValid(fStatus.isOK());
|
||||
StatusUtil.applyToStatusLine(fMainPreferencePage, fStatus);
|
||||
}
|
||||
|
||||
|
||||
private Button addCheckBox(Composite parent, String label, String key, int indentation) {
|
||||
Button checkBox= new Button(parent, SWT.CHECK);
|
||||
checkBox.setText(label);
|
||||
|
||||
GridData gd= new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING);
|
||||
gd.horizontalIndent= indentation;
|
||||
gd.horizontalSpan= 2;
|
||||
checkBox.setLayoutData(gd);
|
||||
checkBox.addSelectionListener(fCheckBoxListener);
|
||||
|
||||
fCheckBoxes.put(checkBox, key);
|
||||
|
||||
return checkBox;
|
||||
}
|
||||
|
||||
// private void addFiller(Composite composite) {
|
||||
// PixelConverter pixelConverter= new PixelConverter(composite);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2000, 2015 IBM Corporation and others.
|
||||
* Copyright (c) 2000, 2016 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
|
||||
|
@ -126,6 +126,7 @@ public final class PreferencesMessages extends NLS {
|
|||
public static String CFileTypeDialog_patternLabel;
|
||||
public static String CFileTypeDialog_typeLabel;
|
||||
public static String CEditorPreferencePage_hover_title;
|
||||
public static String CEditorHoverConfigurationBlock_annotationRollover;
|
||||
public static String CEditorHoverConfigurationBlock_hoverPreferences;
|
||||
public static String CEditorHoverConfigurationBlock_keyModifier;
|
||||
public static String CEditorHoverConfigurationBlock_description;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
###############################################################################
|
||||
# Copyright (c) 2000, 2015 IBM Corporation and others.
|
||||
# Copyright (c) 2000, 2016 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
|
||||
|
@ -143,6 +143,7 @@ CFileTypeDialog_typeLabel=Type:
|
|||
|
||||
# Hover page
|
||||
CEditorPreferencePage_hover_title= Ho&vers
|
||||
CEditorHoverConfigurationBlock_annotationRollover=&Expand vertical ruler icons upon hovering (does not affect open editors)
|
||||
CEditorHoverConfigurationBlock_hoverPreferences= Text &Hover key modifier preferences:
|
||||
CEditorHoverConfigurationBlock_keyModifier= Pressed key &modifier while hovering:
|
||||
CEditorHoverConfigurationBlock_description= Description:
|
||||
|
|
|
@ -0,0 +1,331 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2000, 2016 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
|
||||
* William Riley (Renesas) - Adapted for CDT
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.internal.ui.text.c.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 org.eclipse.cdt.internal.ui.text.c.hover.AnnotationExpansionControl.AnnotationHoverInput;
|
||||
|
||||
|
||||
/**
|
||||
* This class was copied from org.eclipse.jdt.internal.ui.text.java.hover.AnnotationExpansionControl
|
||||
*
|
||||
* @since 6.1
|
||||
*/
|
||||
public class AnnotationExpandHover implements IAnnotationHover, IAnnotationHoverExtension {
|
||||
|
||||
private class InformationControlCreator implements IInformationControlCreator, IInformationControlCreatorExtension {
|
||||
|
||||
/*
|
||||
* @see org.eclipse.jface.text.IInformationControlCreator#createInformationControl(org.eclipse.swt.widgets.Shell)
|
||||
*/
|
||||
@Override
|
||||
public IInformationControl createInformationControl(Shell parent) {
|
||||
return new AnnotationExpansionControl(parent, SWT.NONE, fAnnotationAccess);
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.eclipse.jface.text.IInformationControlCreatorExtension#canReuse(org.eclipse.jface.text.IInformationControl)
|
||||
*/
|
||||
@Override
|
||||
public boolean canReuse(IInformationControl control) {
|
||||
return control instanceof AnnotationExpansionControl;
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.eclipse.jface.text.IInformationControlCreatorExtension#canReplace(org.eclipse.jface.text.IInformationControlCreator)
|
||||
*/
|
||||
@Override
|
||||
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)
|
||||
*/
|
||||
@Override
|
||||
public void annotationSelected(VerticalRulerEvent event) {
|
||||
fCompositeRuler.fireAnnotationSelected(event);
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.eclipse.jface.text.source.IVerticalRulerListener#annotationDefaultSelected(org.eclipse.jface.text.source.VerticalRulerEvent)
|
||||
*/
|
||||
@Override
|
||||
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)
|
||||
*/
|
||||
@Override
|
||||
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)
|
||||
*/
|
||||
@Override
|
||||
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<Annotation> exact= new ArrayList<>();
|
||||
HashMap<Position, Object> messagesAtPosition= new HashMap<>();
|
||||
|
||||
Iterator<Annotation> e= model.getAnnotationIterator();
|
||||
while (e.hasNext()) {
|
||||
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= 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<Annotation> exact, final IAnnotationModel model) {
|
||||
class AnnotationComparator implements Comparator<Annotation> {
|
||||
|
||||
/*
|
||||
* @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public int compare(Annotation a1, Annotation a2) {
|
||||
int a1Offset = getAnnotationOffsetForSort(model, a1);
|
||||
int a2Offset = getAnnotationOffsetForSort(model, a2);
|
||||
// annotation order:
|
||||
// primary order: by position in line
|
||||
// secondary: annotation importance
|
||||
if (a1Offset == a2Offset)
|
||||
return getOrder(a2) - getOrder(a1);
|
||||
return a1Offset - a2Offset;
|
||||
}
|
||||
}
|
||||
|
||||
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<Position, Object> messagesAtPosition, Position position, String message) {
|
||||
if (message == null)
|
||||
return false;
|
||||
|
||||
if (messagesAtPosition.containsKey(position)) {
|
||||
Object value= messagesAtPosition.get(position);
|
||||
if (message.equals(value))
|
||||
return true;
|
||||
|
||||
if (value instanceof List) {
|
||||
@SuppressWarnings("unchecked")
|
||||
List<String> messages= ((List<String>)value);
|
||||
if (messages.contains(message))
|
||||
return true;
|
||||
messages.add(message);
|
||||
} else {
|
||||
ArrayList<Object> 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()
|
||||
*/
|
||||
@Override
|
||||
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)
|
||||
*/
|
||||
@Override
|
||||
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)
|
||||
*/
|
||||
@Override
|
||||
public ILineRange getHoverLineRange(ISourceViewer viewer, int lineNumber) {
|
||||
return new LineRange(lineNumber, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.eclipse.jface.text.source.IAnnotationHoverExtension#canHandleMouseCursor()
|
||||
*/
|
||||
@Override
|
||||
public boolean canHandleMouseCursor() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the offset of an annotation in the model.
|
||||
* <p>
|
||||
* Allows extenders to override ordering of annotations
|
||||
* @param model Annotation model
|
||||
* @param a Annotation to get offset of
|
||||
* @return Offset. Larger values are displayed later in the hover
|
||||
*/
|
||||
protected int getAnnotationOffsetForSort(IAnnotationModel model, Annotation a) {
|
||||
return model.getPosition(a).offset;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,955 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2000, 2016 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
|
||||
* William Riley (Renesas) - Adapted for CDT
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.internal.ui.text.c.hover;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.custom.StyleRange;
|
||||
import org.eclipse.swt.custom.StyledText;
|
||||
import org.eclipse.swt.events.DisposeEvent;
|
||||
import org.eclipse.swt.events.DisposeListener;
|
||||
import org.eclipse.swt.events.FocusListener;
|
||||
import org.eclipse.swt.events.MenuEvent;
|
||||
import org.eclipse.swt.events.MenuListener;
|
||||
import org.eclipse.swt.events.MouseAdapter;
|
||||
import org.eclipse.swt.events.MouseEvent;
|
||||
import org.eclipse.swt.events.MouseTrackAdapter;
|
||||
import org.eclipse.swt.events.MouseTrackListener;
|
||||
import org.eclipse.swt.events.PaintEvent;
|
||||
import org.eclipse.swt.events.PaintListener;
|
||||
import org.eclipse.swt.graphics.Color;
|
||||
import org.eclipse.swt.graphics.Cursor;
|
||||
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.Display;
|
||||
import org.eclipse.swt.widgets.Event;
|
||||
import org.eclipse.swt.widgets.Layout;
|
||||
import org.eclipse.swt.widgets.Listener;
|
||||
import org.eclipse.swt.widgets.Menu;
|
||||
import org.eclipse.swt.widgets.Shell;
|
||||
import org.eclipse.swt.widgets.Widget;
|
||||
|
||||
import org.eclipse.jface.viewers.IDoubleClickListener;
|
||||
|
||||
import org.eclipse.jface.text.AbstractInformationControlManager;
|
||||
import org.eclipse.jface.text.DefaultInformationControl;
|
||||
import org.eclipse.jface.text.IInformationControl;
|
||||
import org.eclipse.jface.text.IInformationControlCreator;
|
||||
import org.eclipse.jface.text.IInformationControlExtension;
|
||||
import org.eclipse.jface.text.IInformationControlExtension2;
|
||||
import org.eclipse.jface.text.IInformationControlExtension5;
|
||||
import org.eclipse.jface.text.IRegion;
|
||||
import org.eclipse.jface.text.IViewportListener;
|
||||
import org.eclipse.jface.text.Position;
|
||||
import org.eclipse.jface.text.Region;
|
||||
import org.eclipse.jface.text.TextViewer;
|
||||
import org.eclipse.jface.text.source.Annotation;
|
||||
import org.eclipse.jface.text.source.IAnnotationAccess;
|
||||
import org.eclipse.jface.text.source.IAnnotationAccessExtension;
|
||||
import org.eclipse.jface.text.source.IAnnotationModel;
|
||||
import org.eclipse.jface.text.source.ISourceViewer;
|
||||
import org.eclipse.jface.text.source.IVerticalRulerInfo;
|
||||
import org.eclipse.jface.text.source.IVerticalRulerListener;
|
||||
import org.eclipse.jface.text.source.VerticalRulerEvent;
|
||||
|
||||
|
||||
/**
|
||||
* A control that can display a number of annotations. The control can decide how it layouts the
|
||||
* annotations to present them to the user.
|
||||
* <p>
|
||||
* This class was copied from org.eclipse.jdt.internal.ui.text.java.hover.AnnotationExpansionControl
|
||||
* </p>
|
||||
* <p>Each annotation can have its custom context menu and hover.</p>
|
||||
*
|
||||
* @since 6.1
|
||||
*/
|
||||
public class AnnotationExpansionControl implements IInformationControl, IInformationControlExtension, IInformationControlExtension2, IInformationControlExtension5 {
|
||||
|
||||
|
||||
public interface ICallback {
|
||||
void run(IInformationControlExtension2 control);
|
||||
}
|
||||
|
||||
/**
|
||||
* Input used by the control to display the annotations.
|
||||
* TODO move to top-level class
|
||||
* TODO encapsulate fields
|
||||
*
|
||||
* @since 6.1
|
||||
*/
|
||||
public static class AnnotationHoverInput {
|
||||
public Annotation[] fAnnotations;
|
||||
public ISourceViewer fViewer;
|
||||
public IVerticalRulerInfo fRulerInfo;
|
||||
public IVerticalRulerListener fAnnotationListener;
|
||||
public IDoubleClickListener fDoubleClickListener;
|
||||
public ICallback redoAction;
|
||||
public IAnnotationModel model;
|
||||
}
|
||||
|
||||
private final class Item {
|
||||
Annotation fAnnotation;
|
||||
Canvas canvas;
|
||||
StyleRange[] oldStyles;
|
||||
|
||||
public void selected() {
|
||||
Display disp= fShell.getDisplay();
|
||||
canvas.setCursor(getHandCursor(disp));
|
||||
// TODO: shade - for now: set grey background
|
||||
canvas.setBackground(getSelectionColor(disp));
|
||||
|
||||
// highlight the viewer background at its position
|
||||
oldStyles= setViewerBackground(fAnnotation);
|
||||
|
||||
// set the selection
|
||||
fSelection= this;
|
||||
|
||||
if (fHoverManager == null) {
|
||||
fHoverManager= createHoverManager(fComposite, true);
|
||||
} else {
|
||||
fHoverManager.showInformation();
|
||||
}
|
||||
|
||||
if (fInput.fAnnotationListener != null) {
|
||||
VerticalRulerEvent event= new VerticalRulerEvent(fAnnotation);
|
||||
fInput.fAnnotationListener.annotationSelected(event);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void defaultSelected(MouseEvent e) {
|
||||
if (fInput.fAnnotationListener != null) {
|
||||
Event swtEvent= new Event();
|
||||
swtEvent.type= SWT.MouseDown;
|
||||
swtEvent.display= e.display;
|
||||
swtEvent.widget= e.widget;
|
||||
swtEvent.time= e.time;
|
||||
swtEvent.data= e.data;
|
||||
swtEvent.x= e.x;
|
||||
swtEvent.y= e.y;
|
||||
swtEvent.button= e.button;
|
||||
swtEvent.stateMask= e.stateMask;
|
||||
swtEvent.count= e.count;
|
||||
VerticalRulerEvent event= new VerticalRulerEvent(fAnnotation, swtEvent);
|
||||
fInput.fAnnotationListener.annotationDefaultSelected(event);
|
||||
}
|
||||
|
||||
dispose();
|
||||
}
|
||||
|
||||
public void deselect() {
|
||||
// hide the popup
|
||||
// fHoverManager.disposeInformationControl();
|
||||
|
||||
// deselect
|
||||
fSelection= null;
|
||||
|
||||
resetViewerBackground(oldStyles);
|
||||
oldStyles= null;
|
||||
|
||||
Display disp= fShell.getDisplay();
|
||||
canvas.setCursor(null);
|
||||
// TODO: remove shading - for now: set standard background
|
||||
canvas.setBackground(disp.getSystemColor(SWT.COLOR_INFO_BACKGROUND));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Disposes of an item
|
||||
*/
|
||||
private final static class MyDisposeListener implements DisposeListener {
|
||||
/*
|
||||
* @see org.eclipse.swt.events.DisposeListener#widgetDisposed(org.eclipse.swt.events.DisposeEvent)
|
||||
*/
|
||||
@Override
|
||||
public void widgetDisposed(DisposeEvent e) {
|
||||
Item item= (Item) ((Widget) e.getSource()).getData();
|
||||
item.deselect();
|
||||
item.canvas= null;
|
||||
item.fAnnotation= null;
|
||||
item.oldStyles= null;
|
||||
|
||||
((Widget) e.getSource()).setData(null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Listener on context menu invocation on the items
|
||||
*/
|
||||
private final class MyMenuDetectListener implements Listener {
|
||||
/*
|
||||
* @see org.eclipse.swt.widgets.Listener#handleEvent(org.eclipse.swt.widgets.Event)
|
||||
*/
|
||||
@Override
|
||||
public void handleEvent(Event event) {
|
||||
if (event.type == SWT.MenuDetect) {
|
||||
// TODO: show per-item menu
|
||||
// for now: show ruler context menu
|
||||
if (fInput != null) {
|
||||
Control ruler= fInput.fRulerInfo.getControl();
|
||||
if (ruler != null && !ruler.isDisposed()) {
|
||||
Menu menu= ruler.getMenu();
|
||||
if (menu != null && !menu.isDisposed()) {
|
||||
menu.setLocation(event.x, event.y);
|
||||
menu.addMenuListener(new MenuListener() {
|
||||
|
||||
@Override
|
||||
public void menuHidden(MenuEvent e) {
|
||||
dispose();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void menuShown(MenuEvent e) {
|
||||
}
|
||||
|
||||
});
|
||||
menu.setVisible(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Listener on mouse events on the items.
|
||||
*/
|
||||
private final class MyMouseListener extends MouseAdapter {
|
||||
/*
|
||||
* @see org.eclipse.swt.events.MouseListener#mouseDoubleClick(org.eclipse.swt.events.MouseEvent)
|
||||
*/
|
||||
@Override
|
||||
public void mouseDoubleClick(MouseEvent e) {
|
||||
Item item= (Item) ((Widget) e.getSource()).getData();
|
||||
if (e.button == 1 && item.fAnnotation == fInput.fAnnotations[0] && fInput.fDoubleClickListener != null) {
|
||||
fInput.fDoubleClickListener.doubleClick(null);
|
||||
// special code for JDT to renew the annotation set.
|
||||
if (fInput.redoAction != null)
|
||||
fInput.redoAction.run(AnnotationExpansionControl.this);
|
||||
}
|
||||
// dispose();
|
||||
// TODO special action to invoke double-click action on the vertical ruler
|
||||
// how about
|
||||
// Canvas can= (Canvas) e.getSource();
|
||||
// Annotation a= (Annotation) can.getData();
|
||||
// if (a != null) {
|
||||
// a.getDoubleClickAction().run();
|
||||
// }
|
||||
}
|
||||
|
||||
/*
|
||||
* JDT uses mouseDown here rather than mouseUp to fix a bug
|
||||
* (details see https://bugs.eclipse.org/bugs/show_bug.cgi?id=165533)
|
||||
*
|
||||
* However this causes an issue where the top annotation is fired if the user
|
||||
* click the 1st item in the expansion control. Due to mouseUp going to the ruler
|
||||
* after the expansion is close.
|
||||
*
|
||||
* Bug as described in JDT does not seems to affect CDT so reverting to mouseUp.
|
||||
*
|
||||
* @see org.eclipse.swt.events.MouseListener#mouseUp(org.eclipse.swt.events.MouseEvent)
|
||||
*/
|
||||
@Override
|
||||
public void mouseUp(MouseEvent e) {
|
||||
Item item= (Item) ((Widget) e.getSource()).getData();
|
||||
// TODO for now, to make double click work: disable single click on the first item
|
||||
// disable later when the annotationlistener selectively handles input
|
||||
if (item != null && e.button == 1) // && item.fAnnotation != fInput.fAnnotations[0])
|
||||
item.defaultSelected(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Listener on mouse track events on the items.
|
||||
*/
|
||||
private final class MyMouseTrackListener implements MouseTrackListener {
|
||||
/*
|
||||
* @see org.eclipse.swt.events.MouseTrackListener#mouseEnter(org.eclipse.swt.events.MouseEvent)
|
||||
*/
|
||||
@Override
|
||||
public void mouseEnter(MouseEvent e) {
|
||||
Item item= (Item) ((Widget) e.getSource()).getData();
|
||||
if (item != null)
|
||||
item.selected();
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.eclipse.swt.events.MouseTrackListener#mouseExit(org.eclipse.swt.events.MouseEvent)
|
||||
*/
|
||||
@Override
|
||||
public void mouseExit(MouseEvent e) {
|
||||
|
||||
Item item= (Item) ((Widget) e.getSource()).getData();
|
||||
if (item != null)
|
||||
item.deselect();
|
||||
|
||||
// if the event lies outside the entire popup, dispose
|
||||
org.eclipse.swt.graphics.Region region= fShell.getRegion();
|
||||
Canvas can= (Canvas) e.getSource();
|
||||
Point p= can.toDisplay(e.x, e.y);
|
||||
if (region == null) {
|
||||
Rectangle bounds= fShell.getBounds();
|
||||
// p= fShell.toControl(p);
|
||||
if (!bounds.contains(p))
|
||||
dispose();
|
||||
} else {
|
||||
p= fShell.toControl(p);
|
||||
if (!region.contains(p))
|
||||
dispose();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.eclipse.swt.events.MouseTrackListener#mouseHover(org.eclipse.swt.events.MouseEvent)
|
||||
*/
|
||||
@Override
|
||||
public void mouseHover(MouseEvent e) {
|
||||
if (fHoverManager == null) {
|
||||
fHoverManager= createHoverManager(fComposite, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private HoverManager createHoverManager(Composite target, boolean show) {
|
||||
HoverManager hoverManager = new HoverManager();
|
||||
hoverManager.takesFocusWhenVisible(false);
|
||||
hoverManager.install(target);
|
||||
if(show) {
|
||||
hoverManager.showInformation();
|
||||
}
|
||||
return hoverManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 6.1
|
||||
*/
|
||||
public class LinearLayouter {
|
||||
|
||||
private static final int ANNOTATION_SIZE= 14;
|
||||
private static final int BORDER_WIDTH= 2;
|
||||
|
||||
public Layout getLayout(int itemCount) {
|
||||
// simple layout: a row of items
|
||||
GridLayout layout= new GridLayout(itemCount, true);
|
||||
layout.horizontalSpacing= 1;
|
||||
layout.verticalSpacing= 0;
|
||||
layout.marginHeight= 1;
|
||||
layout.marginWidth= 1;
|
||||
return layout;
|
||||
}
|
||||
|
||||
public Object getLayoutData() {
|
||||
GridData gridData= new GridData(ANNOTATION_SIZE + 2 * BORDER_WIDTH, ANNOTATION_SIZE + 2 * BORDER_WIDTH);
|
||||
gridData.horizontalAlignment= GridData.CENTER;
|
||||
gridData.verticalAlignment= GridData.CENTER;
|
||||
return gridData;
|
||||
}
|
||||
|
||||
public int getAnnotationSize() {
|
||||
return ANNOTATION_SIZE;
|
||||
}
|
||||
|
||||
public int getBorderWidth() {
|
||||
return BORDER_WIDTH;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the shell region for the given number of items.
|
||||
*
|
||||
* @param itemCount the item count
|
||||
* @return the shell region
|
||||
*/
|
||||
public org.eclipse.swt.graphics.Region getShellRegion(int itemCount) {
|
||||
// no special region - set to null for default shell size
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Listener on paint events on the items. Paints the annotation image on the given <code>GC</code>.
|
||||
*/
|
||||
private final class MyPaintListener implements PaintListener {
|
||||
/*
|
||||
* @see org.eclipse.swt.events.PaintListener#paintControl(org.eclipse.swt.events.PaintEvent)
|
||||
*/
|
||||
@Override
|
||||
public void paintControl(PaintEvent e) {
|
||||
Canvas can= (Canvas) e.getSource();
|
||||
Annotation a= ((Item) can.getData()).fAnnotation;
|
||||
if (a != null) {
|
||||
Rectangle rect= new Rectangle(fLayouter.getBorderWidth(), fLayouter.getBorderWidth(), fLayouter.getAnnotationSize(), fLayouter.getAnnotationSize());
|
||||
if (fAnnotationAccessExtension != null)
|
||||
fAnnotationAccessExtension.paint(a, e.gc, can, rect);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Our own private hover manager used to shop per-item pop-ups.
|
||||
*/
|
||||
private final class HoverManager extends AbstractInformationControlManager {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public HoverManager() {
|
||||
super(new IInformationControlCreator() {
|
||||
@Override
|
||||
public IInformationControl createInformationControl(Shell parent) {
|
||||
return new DefaultInformationControl(parent);
|
||||
}
|
||||
});
|
||||
|
||||
setMargins(5, 10);
|
||||
setAnchor(ANCHOR_BOTTOM);
|
||||
setFallbackAnchors(new Anchor[] {ANCHOR_BOTTOM, ANCHOR_LEFT, ANCHOR_RIGHT} );
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.eclipse.jface.text.AbstractInformationControlManager#computeInformation()
|
||||
*/
|
||||
@Override
|
||||
protected void computeInformation() {
|
||||
if (fSelection != null) {
|
||||
Rectangle subjectArea= fSelection.canvas.getBounds();
|
||||
Annotation annotation= fSelection.fAnnotation;
|
||||
String msg;
|
||||
if (annotation != null)
|
||||
msg= annotation.getText();
|
||||
else
|
||||
msg= null;
|
||||
|
||||
setInformation(msg, subjectArea);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/** Model data. */
|
||||
protected AnnotationHoverInput fInput;
|
||||
/** The control's shell */
|
||||
private Shell fShell;
|
||||
/** The composite combining all the items. */
|
||||
protected Composite fComposite;
|
||||
/** The currently selected item, or <code>null</code> if none is selected. */
|
||||
private Item fSelection;
|
||||
/** The hover manager for the per-item hovers. */
|
||||
private HoverManager fHoverManager;
|
||||
/** The annotation access extension. */
|
||||
private IAnnotationAccessExtension fAnnotationAccessExtension;
|
||||
|
||||
|
||||
/* listener legion */
|
||||
private final MyPaintListener fPaintListener;
|
||||
private final MyMouseTrackListener fMouseTrackListener;
|
||||
private final MyMouseListener fMouseListener;
|
||||
private final MyMenuDetectListener fMenuDetectListener;
|
||||
private final DisposeListener fDisposeListener;
|
||||
private final IViewportListener fViewportListener;
|
||||
|
||||
private LinearLayouter fLayouter;
|
||||
|
||||
/**
|
||||
* Creates a new control.
|
||||
*
|
||||
* @param parent parent shell
|
||||
* @param shellStyle additional style flags
|
||||
* @param access the annotation access
|
||||
*/
|
||||
public AnnotationExpansionControl(Shell parent, int shellStyle, IAnnotationAccess access) {
|
||||
fPaintListener= new MyPaintListener();
|
||||
fMouseTrackListener= new MyMouseTrackListener();
|
||||
fMouseListener= new MyMouseListener();
|
||||
fMenuDetectListener= new MyMenuDetectListener();
|
||||
fDisposeListener= new MyDisposeListener();
|
||||
fViewportListener= new IViewportListener() {
|
||||
|
||||
@Override
|
||||
public void viewportChanged(int verticalOffset) {
|
||||
dispose();
|
||||
}
|
||||
|
||||
};
|
||||
fLayouter= new LinearLayouter();
|
||||
|
||||
if (access instanceof IAnnotationAccessExtension)
|
||||
fAnnotationAccessExtension= (IAnnotationAccessExtension) access;
|
||||
|
||||
fShell= new Shell(parent, shellStyle | SWT.NO_FOCUS | SWT.ON_TOP);
|
||||
Display display= fShell.getDisplay();
|
||||
fShell.setBackground(display.getSystemColor(SWT.COLOR_BLACK));
|
||||
fComposite= new Composite(fShell, SWT.NO_FOCUS | SWT.NO_REDRAW_RESIZE | SWT.NO_TRIM);
|
||||
// fComposite= new Composite(fShell, SWT.NO_FOCUS | SWT.NO_REDRAW_RESIZE | SWT.NO_TRIM | SWT.V_SCROLL);
|
||||
|
||||
GridLayout layout= new GridLayout(1, true);
|
||||
layout.marginHeight= 0;
|
||||
layout.marginWidth= 0;
|
||||
fShell.setLayout(layout);
|
||||
|
||||
GridData data= new GridData(GridData.FILL_BOTH);
|
||||
data.heightHint= fLayouter.getAnnotationSize() + 2 * fLayouter.getBorderWidth() + 4;
|
||||
fComposite.setLayoutData(data);
|
||||
fComposite.addMouseTrackListener(new MouseTrackAdapter() {
|
||||
|
||||
@Override
|
||||
public void mouseExit(MouseEvent e) {
|
||||
if (fComposite == null)
|
||||
return;
|
||||
Control[] children= fComposite.getChildren();
|
||||
Rectangle bounds= null;
|
||||
for (int i= 0; i < children.length; i++) {
|
||||
if (bounds == null)
|
||||
bounds= children[i].getBounds();
|
||||
else
|
||||
bounds.add(children[i].getBounds());
|
||||
if (bounds.contains(e.x, e.y))
|
||||
return;
|
||||
}
|
||||
|
||||
// if none of the children contains the event, we leave the popup
|
||||
dispose();
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
// fComposite.getVerticalBar().addListener(SWT.Selection, new Listener() {
|
||||
//
|
||||
// public void handleEvent(Event event) {
|
||||
// Rectangle bounds= fShell.getBounds();
|
||||
// int x= bounds.x - fLayouter.getAnnotationSize() - fLayouter.getBorderWidth();
|
||||
// int y= bounds.y;
|
||||
// fShell.setBounds(x, y, bounds.width, bounds.height);
|
||||
// }
|
||||
//
|
||||
// });
|
||||
|
||||
Cursor handCursor= getHandCursor(display);
|
||||
fShell.setCursor(handCursor);
|
||||
fComposite.setCursor(handCursor);
|
||||
|
||||
setInfoSystemColor();
|
||||
}
|
||||
|
||||
private void setInfoSystemColor() {
|
||||
Display display= fShell.getDisplay();
|
||||
setForegroundColor(display.getSystemColor(SWT.COLOR_INFO_FOREGROUND));
|
||||
setBackgroundColor(display.getSystemColor(SWT.COLOR_INFO_BACKGROUND));
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.eclipse.jface.text.IInformationControl#setInformation(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public void setInformation(String information) {
|
||||
setInput(null);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* @see org.eclipse.jface.text.IInformationControlExtension2#setInput(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public void setInput(Object input) {
|
||||
if (fInput != null && fInput.fViewer != null)
|
||||
fInput.fViewer.removeViewportListener(fViewportListener);
|
||||
|
||||
if (input instanceof AnnotationHoverInput)
|
||||
fInput= (AnnotationHoverInput) input;
|
||||
else
|
||||
fInput= null;
|
||||
|
||||
inputChanged(fInput, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal hook method called when the input is
|
||||
* initially set or subsequently changed.
|
||||
*
|
||||
* @param newInput the new input
|
||||
* @param newSelection the new selection
|
||||
*/
|
||||
protected void inputChanged(Object newInput, Object newSelection) {
|
||||
refresh();
|
||||
}
|
||||
|
||||
protected void refresh() {
|
||||
adjustItemNumber();
|
||||
|
||||
if (fInput == null)
|
||||
return;
|
||||
|
||||
if (fInput.fAnnotations == null)
|
||||
return;
|
||||
|
||||
if (fInput.fViewer != null)
|
||||
fInput.fViewer.addViewportListener(fViewportListener);
|
||||
|
||||
fShell.setRegion(fLayouter.getShellRegion(fInput.fAnnotations.length));
|
||||
|
||||
Layout layout= fLayouter.getLayout(fInput.fAnnotations.length);
|
||||
fComposite.setLayout(layout);
|
||||
|
||||
Control[] children= fComposite.getChildren();
|
||||
for (int i= 0; i < fInput.fAnnotations.length; i++) {
|
||||
Canvas canvas= (Canvas) children[i];
|
||||
Item item= new Item();
|
||||
item.canvas= canvas;
|
||||
item.fAnnotation= fInput.fAnnotations[i];
|
||||
canvas.setData(item);
|
||||
canvas.redraw();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected void adjustItemNumber() {
|
||||
if (fComposite == null)
|
||||
return;
|
||||
|
||||
Control[] children= fComposite.getChildren();
|
||||
int oldSize= children.length;
|
||||
int newSize= fInput == null ? 0 : fInput.fAnnotations.length;
|
||||
|
||||
Display display= fShell.getDisplay();
|
||||
|
||||
// add missing items
|
||||
for (int i= oldSize; i < newSize; i++) {
|
||||
Canvas canvas= new Canvas(fComposite, SWT.NONE);
|
||||
Object gridData= fLayouter.getLayoutData();
|
||||
canvas.setLayoutData(gridData);
|
||||
canvas.setBackground(display.getSystemColor(SWT.COLOR_INFO_BACKGROUND));
|
||||
|
||||
canvas.addPaintListener(fPaintListener);
|
||||
|
||||
canvas.addMouseTrackListener(fMouseTrackListener);
|
||||
|
||||
canvas.addMouseListener(fMouseListener);
|
||||
|
||||
canvas.addListener(SWT.MenuDetect, fMenuDetectListener);
|
||||
|
||||
canvas.addDisposeListener(fDisposeListener);
|
||||
}
|
||||
|
||||
// dispose of exceeding resources
|
||||
for (int i= oldSize; i > newSize; i--) {
|
||||
Item item= (Item) children[i - 1].getData();
|
||||
item.deselect();
|
||||
children[i - 1].dispose();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* @see IInformationControl#setVisible(boolean)
|
||||
*/
|
||||
@Override
|
||||
public void setVisible(boolean visible) {
|
||||
fShell.setVisible(visible);
|
||||
if(visible) {
|
||||
/*
|
||||
* Force 1st item to be selected when made visible
|
||||
*
|
||||
* This causes the tooltip to be displayed without additional
|
||||
* delay.
|
||||
*/
|
||||
Control[] children= fComposite.getChildren();
|
||||
if(fHoverManager == null && children.length > 0) {
|
||||
Object data = children[0].getData();
|
||||
if(data instanceof Item) {
|
||||
((Item)data).selected();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* @see IInformationControl#dispose()
|
||||
*/
|
||||
@Override
|
||||
public void dispose() {
|
||||
if (fShell != null) {
|
||||
if (!fShell.isDisposed())
|
||||
fShell.dispose();
|
||||
fShell= null;
|
||||
fComposite= null;
|
||||
if (fHoverManager != null)
|
||||
fHoverManager.dispose();
|
||||
fHoverManager= null;
|
||||
fSelection= null;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.eclipse.jface.text.IInformationControlExtension#hasContents()
|
||||
*/
|
||||
@Override
|
||||
public boolean hasContents() {
|
||||
return fInput.fAnnotations != null && fInput.fAnnotations.length > 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.eclipse.jface.text.IInformationControl#setSizeConstraints(int, int)
|
||||
*/
|
||||
@Override
|
||||
public void setSizeConstraints(int maxWidth, int maxHeight) {
|
||||
//fMaxWidth= maxWidth;
|
||||
//fMaxHeight= maxHeight;
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.eclipse.jface.text.IInformationControl#computeSizeHint()
|
||||
*/
|
||||
@Override
|
||||
public Point computeSizeHint() {
|
||||
return fShell.computeSize(SWT.DEFAULT, SWT.DEFAULT);
|
||||
}
|
||||
|
||||
/*
|
||||
* @see IInformationControl#setLocation(Point)
|
||||
*/
|
||||
@Override
|
||||
public void setLocation(Point location) {
|
||||
fShell.setLocation(location);
|
||||
}
|
||||
|
||||
/*
|
||||
* @see IInformationControl#setSize(int, int)
|
||||
*/
|
||||
@Override
|
||||
public void setSize(int width, int height) {
|
||||
fShell.setSize(width, height);
|
||||
}
|
||||
|
||||
/*
|
||||
* @see IInformationControl#addDisposeListener(DisposeListener)
|
||||
*/
|
||||
@Override
|
||||
public void addDisposeListener(DisposeListener listener) {
|
||||
fShell.addDisposeListener(listener);
|
||||
}
|
||||
|
||||
/*
|
||||
* @see IInformationControl#removeDisposeListener(DisposeListener)
|
||||
*/
|
||||
@Override
|
||||
public void removeDisposeListener(DisposeListener listener) {
|
||||
fShell.removeDisposeListener(listener);
|
||||
}
|
||||
|
||||
/*
|
||||
* @see IInformationControl#setForegroundColor(Color)
|
||||
*/
|
||||
@Override
|
||||
public void setForegroundColor(Color foreground) {
|
||||
fComposite.setForeground(foreground);
|
||||
}
|
||||
|
||||
/*
|
||||
* @see IInformationControl#setBackgroundColor(Color)
|
||||
*/
|
||||
@Override
|
||||
public void setBackgroundColor(Color background) {
|
||||
fComposite.setBackground(background);
|
||||
}
|
||||
|
||||
/*
|
||||
* @see IInformationControl#isFocusControl()
|
||||
*/
|
||||
@Override
|
||||
public boolean isFocusControl() {
|
||||
return fShell.getDisplay().getActiveShell() == fShell;
|
||||
}
|
||||
|
||||
/*
|
||||
* @see IInformationControl#setFocus()
|
||||
*/
|
||||
@Override
|
||||
public void setFocus() {
|
||||
fShell.forceFocus();
|
||||
}
|
||||
|
||||
/*
|
||||
* @see IInformationControl#addFocusListener(FocusListener)
|
||||
*/
|
||||
@Override
|
||||
public void addFocusListener(FocusListener listener) {
|
||||
fShell.addFocusListener(listener);
|
||||
}
|
||||
|
||||
/*
|
||||
* @see IInformationControl#removeFocusListener(FocusListener)
|
||||
*/
|
||||
@Override
|
||||
public void removeFocusListener(FocusListener listener) {
|
||||
fShell.removeFocusListener(listener);
|
||||
}
|
||||
|
||||
private StyleRange[] setViewerBackground(Annotation annotation) {
|
||||
StyledText text= fInput.fViewer.getTextWidget();
|
||||
if (text == null || text.isDisposed())
|
||||
return null;
|
||||
|
||||
Display disp= text.getDisplay();
|
||||
|
||||
Position pos= fInput.model.getPosition(annotation);
|
||||
if (pos == null)
|
||||
return null;
|
||||
|
||||
IRegion region= ((TextViewer)fInput.fViewer).modelRange2WidgetRange(new Region(pos.offset, pos.length));
|
||||
if (region == null)
|
||||
return null;
|
||||
|
||||
StyleRange[] ranges= text.getStyleRanges(region.getOffset(), region.getLength());
|
||||
|
||||
List<StyleRange> undoRanges= new ArrayList<>(ranges.length);
|
||||
for (int i= 0; i < ranges.length; i++) {
|
||||
undoRanges.add((StyleRange)ranges[i].clone());
|
||||
}
|
||||
|
||||
int offset= region.getOffset();
|
||||
StyleRange current= undoRanges.size() > 0 ? undoRanges.get(0) : null;
|
||||
int curStart= current != null ? current.start : region.getOffset() + region.getLength();
|
||||
int curEnd= current != null ? current.start + current.length : -1;
|
||||
int index= 0;
|
||||
|
||||
// fill no-style regions
|
||||
while (curEnd < region.getOffset() + region.getLength()) {
|
||||
// add empty range
|
||||
if (curStart > offset) {
|
||||
StyleRange undoRange= new StyleRange(offset, curStart - offset, null, null);
|
||||
undoRanges.add(index, undoRange);
|
||||
index++;
|
||||
}
|
||||
|
||||
// step
|
||||
index++;
|
||||
if (index < undoRanges.size()) {
|
||||
offset= curEnd;
|
||||
current= undoRanges.get(index);
|
||||
curStart= current.start;
|
||||
curEnd= current.start + current.length;
|
||||
} else if (index == undoRanges.size()) {
|
||||
// last one
|
||||
offset= curEnd;
|
||||
current= null;
|
||||
curStart= region.getOffset() + region.getLength();
|
||||
curEnd= -1;
|
||||
} else
|
||||
curEnd= region.getOffset() + region.getLength();
|
||||
}
|
||||
|
||||
// create modified styles (with background)
|
||||
List<StyleRange> shadedRanges= new ArrayList<>(undoRanges.size());
|
||||
for (Iterator<StyleRange> it= undoRanges.iterator(); it.hasNext(); ) {
|
||||
StyleRange range= (StyleRange) it.next().clone();
|
||||
shadedRanges.add(range);
|
||||
range.background= getHighlightColor(disp);
|
||||
}
|
||||
|
||||
// set the ranges one by one
|
||||
for (Iterator<StyleRange> iter= shadedRanges.iterator(); iter.hasNext(); ) {
|
||||
text.setStyleRange(iter.next());
|
||||
|
||||
}
|
||||
|
||||
return undoRanges.toArray(undoRanges.toArray(new StyleRange[0]));
|
||||
}
|
||||
|
||||
private void resetViewerBackground(StyleRange[] oldRanges) {
|
||||
|
||||
if (oldRanges == null)
|
||||
return;
|
||||
|
||||
if (fInput == null)
|
||||
return;
|
||||
|
||||
StyledText text= fInput.fViewer.getTextWidget();
|
||||
if (text == null || text.isDisposed())
|
||||
return;
|
||||
|
||||
// set the ranges one by one
|
||||
for (int i= 0; i < oldRanges.length; i++) {
|
||||
text.setStyleRange(oldRanges[i]);
|
||||
}
|
||||
}
|
||||
|
||||
private Color getHighlightColor(Display disp) {
|
||||
return disp.getSystemColor(SWT.COLOR_GRAY);
|
||||
}
|
||||
|
||||
private Color getSelectionColor(Display disp) {
|
||||
return disp.getSystemColor(SWT.COLOR_GRAY);
|
||||
}
|
||||
|
||||
private Cursor getHandCursor(Display disp) {
|
||||
return disp.getSystemCursor(SWT.CURSOR_HAND);
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.eclipse.jface.text.IInformationControlExtension5#computeSizeConstraints(int, int)
|
||||
* @since 3.4
|
||||
*/
|
||||
@Override
|
||||
public Point computeSizeConstraints(int widthInChars, int heightInChars) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.eclipse.jface.text.IInformationControlExtension5#containsControl(org.eclipse.swt.widgets.Control)
|
||||
* @since 3.4
|
||||
*/
|
||||
@Override
|
||||
public boolean containsControl(Control control) {
|
||||
do {
|
||||
if (control == fShell)
|
||||
return true;
|
||||
if (control instanceof Shell)
|
||||
return false;
|
||||
control= control.getParent();
|
||||
} while (control != null);
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.eclipse.jface.text.IInformationControlExtension5#getInformationPresenterControlCreator()
|
||||
* @since 3.4
|
||||
*/
|
||||
@Override
|
||||
public IInformationControlCreator getInformationPresenterControlCreator() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.eclipse.jface.text.IInformationControlExtension5#isVisible()
|
||||
*/
|
||||
@Override
|
||||
public boolean isVisible() {
|
||||
return fShell != null && !fShell.isDisposed() && fShell.isVisible();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,234 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2000, 2016 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
|
||||
* William Riley (Renesas) - Adapted for CDT
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.internal.ui.text.c.hover;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.graphics.GC;
|
||||
import org.eclipse.swt.graphics.Image;
|
||||
import org.eclipse.swt.graphics.Rectangle;
|
||||
import org.eclipse.swt.widgets.Canvas;
|
||||
|
||||
import org.eclipse.jface.preference.IPreferenceStore;
|
||||
import org.eclipse.jface.viewers.IDoubleClickListener;
|
||||
|
||||
import org.eclipse.jface.text.IDocument;
|
||||
import org.eclipse.jface.text.IInformationControlExtension2;
|
||||
import org.eclipse.jface.text.Position;
|
||||
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.IAnnotationModel;
|
||||
import org.eclipse.jface.text.source.IAnnotationPresentation;
|
||||
import org.eclipse.jface.text.source.ISourceViewer;
|
||||
import org.eclipse.jface.text.source.ImageUtilities;
|
||||
|
||||
import org.eclipse.ui.texteditor.AnnotationPreference;
|
||||
import org.eclipse.ui.texteditor.AnnotationPreferenceLookup;
|
||||
|
||||
import org.eclipse.cdt.ui.PreferenceConstants;
|
||||
|
||||
import org.eclipse.cdt.ui.CUIPlugin;
|
||||
import org.eclipse.cdt.ui.CDTSharedImages;
|
||||
import org.eclipse.cdt.internal.ui.editor.CDocumentProvider.ProblemAnnotation;
|
||||
import org.eclipse.cdt.internal.ui.editor.ICAnnotation;
|
||||
import org.eclipse.cdt.internal.ui.editor.CMarkerAnnotation;
|
||||
import org.eclipse.cdt.internal.ui.text.c.hover.AnnotationExpansionControl.AnnotationHoverInput;
|
||||
|
||||
|
||||
/**
|
||||
* Originally copied from org.eclipse.jdt.internal.ui.text.java.hover.JavaExpandHover
|
||||
* @since 6.1
|
||||
*/
|
||||
public class CExpandHover extends AnnotationExpandHover {
|
||||
|
||||
/** Id of CDT Breakpoint annotation type */
|
||||
private static final String ANNOTATION_TYPE_BREAKPOINT = "org.eclipse.cdt.debug.core.breakpoint"; //$NON-NLS-1$
|
||||
|
||||
/** Id of the no breakpoint fake annotation */
|
||||
public static final String NO_BREAKPOINT_ANNOTATION= "org.eclipse.cdt.internal.ui.NoBreakpointAnnotation"; //$NON-NLS-1$
|
||||
|
||||
private static class NoBreakpointAnnotation extends Annotation implements IAnnotationPresentation {
|
||||
|
||||
public NoBreakpointAnnotation() {
|
||||
super(NO_BREAKPOINT_ANNOTATION, false, CHoverMessages.CExpandHover_tooltip_noBreakpoint);
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.eclipse.jface.text.source.IAnnotationPresentation#paint(org.eclipse.swt.graphics.GC, org.eclipse.swt.widgets.Canvas, org.eclipse.swt.graphics.Rectangle)
|
||||
*/
|
||||
@Override
|
||||
public void paint(GC gc, Canvas canvas, Rectangle bounds) {
|
||||
// draw affordance so the user know she can click here to get a breakpoint
|
||||
Image fImage= CDTSharedImages.getImage(CDTSharedImages.IMG_OBJS_PUBLIC_FIELD);
|
||||
ImageUtilities.drawImage(fImage, gc, canvas, bounds, SWT.CENTER);
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.eclipse.jface.text.source.IAnnotationPresentation#getLayer()
|
||||
*/
|
||||
@Override
|
||||
public int getLayer() {
|
||||
return IAnnotationPresentation.DEFAULT_LAYER;
|
||||
}
|
||||
}
|
||||
|
||||
private AnnotationPreferenceLookup fLookup= new AnnotationPreferenceLookup();
|
||||
private IPreferenceStore fStore= CUIPlugin.getDefault().getCombinedPreferenceStore();
|
||||
|
||||
public CExpandHover(CompositeRuler ruler, IAnnotationAccess access, IDoubleClickListener doubleClickListener) {
|
||||
super(ruler, access, doubleClickListener);
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.eclipse.ui.internal.texteditor.AnnotationExpandHover#getHoverInfoForLine(org.eclipse.jface.text.source.ISourceViewer, int)
|
||||
*/
|
||||
@Override
|
||||
protected Object getHoverInfoForLine(final ISourceViewer viewer, final int line) {
|
||||
//Use EDITOR_EVALUATE_TEMPORARY_PROBLEMS rather than EDITOR_CORRECTION_INDICATION as EDITOR_CORRECTION_INDICATION is not used in CDT
|
||||
final boolean showTemporaryProblems= PreferenceConstants.getPreferenceStore().getBoolean(PreferenceConstants.EDITOR_EVALUATE_TEMPORARY_PROBLEMS);
|
||||
IAnnotationModel model= viewer.getAnnotationModel();
|
||||
IDocument document= viewer.getDocument();
|
||||
|
||||
if (model == null)
|
||||
return null;
|
||||
|
||||
List<Annotation> exact= new ArrayList<>();
|
||||
HashMap<Position, Object> messagesAtPosition= new HashMap<>();
|
||||
|
||||
Iterator<Annotation> e= model.getAnnotationIterator();
|
||||
while (e.hasNext()) {
|
||||
Annotation annotation= e.next();
|
||||
|
||||
if (fAnnotationAccess instanceof IAnnotationAccessExtension)
|
||||
if (!((IAnnotationAccessExtension)fAnnotationAccess).isPaintable(annotation))
|
||||
continue;
|
||||
|
||||
if (annotation instanceof ICAnnotation && !isIncluded((ICAnnotation)annotation, showTemporaryProblems))
|
||||
continue;
|
||||
|
||||
AnnotationPreference pref= fLookup.getAnnotationPreference(annotation);
|
||||
if (pref != null) {
|
||||
String key= pref.getVerticalRulerPreferenceKey();
|
||||
if (key != null && !fStore.getBoolean(key))
|
||||
continue;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
sort(exact, model);
|
||||
|
||||
if (exact.size() > 0)
|
||||
setLastRulerMouseLocation(viewer, line);
|
||||
|
||||
if (exact.size() > 0) {
|
||||
if (!containsBreakpointAnnotation(exact)) {
|
||||
//Add dummy annotation last if no breakpoint present
|
||||
exact.add(new NoBreakpointAnnotation());
|
||||
}
|
||||
}
|
||||
|
||||
if (exact.size() <= 1)
|
||||
return null;
|
||||
|
||||
AnnotationHoverInput input= new AnnotationHoverInput();
|
||||
input.fAnnotations= exact.toArray(new Annotation[0]);
|
||||
input.fViewer= viewer;
|
||||
input.fRulerInfo= fCompositeRuler;
|
||||
input.fAnnotationListener= fgListener;
|
||||
input.fDoubleClickListener= fDblClickListener;
|
||||
input.redoAction= new AnnotationExpansionControl.ICallback() {
|
||||
|
||||
@Override
|
||||
public void run(IInformationControlExtension2 control) {
|
||||
control.setInput(getHoverInfoForLine(viewer, line));
|
||||
}
|
||||
|
||||
};
|
||||
input.model= model;
|
||||
|
||||
return input;
|
||||
}
|
||||
|
||||
private boolean isIncluded(ICAnnotation annotation, boolean showTemporaryProblems) {
|
||||
|
||||
// XXX: see https://bugs.eclipse.org/bugs/show_bug.cgi?id=138601
|
||||
if (annotation instanceof ProblemAnnotation && CMarkerAnnotation.TASK_ANNOTATION_TYPE.equals(annotation.getType()))
|
||||
return false;
|
||||
|
||||
if (!annotation.isProblem())
|
||||
return true;
|
||||
|
||||
if (annotation.isMarkedDeleted() && !annotation.hasOverlay())
|
||||
return true;
|
||||
|
||||
if (annotation.hasOverlay() && !annotation.isMarkedDeleted())
|
||||
return true;
|
||||
|
||||
|
||||
if (annotation.hasOverlay())
|
||||
return (!isIncluded(annotation.getOverlay(), showTemporaryProblems));
|
||||
|
||||
//JDT only shows annotations problems corrections, for CDT show all.
|
||||
return showTemporaryProblems;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getAnnotationOffsetForSort(IAnnotationModel model, Annotation a) {
|
||||
if(this.isBreakpointAnnotation(a)) {
|
||||
return Integer.MAX_VALUE; //Force breakpoints to end
|
||||
} else {
|
||||
return model.getPosition(a).offset;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.eclipse.ui.internal.texteditor.AnnotationExpandHover#getOrder(org.eclipse.jface.text.source.Annotation)
|
||||
*/
|
||||
@Override
|
||||
protected int getOrder(Annotation annotation) {
|
||||
if (isBreakpointAnnotation(annotation))
|
||||
return 0;//Force breakpoints to end. Usability improvement over JDT based on feedback
|
||||
else
|
||||
return super.getOrder(annotation);
|
||||
}
|
||||
|
||||
private boolean isBreakpointAnnotation(Annotation a) {
|
||||
return a.getType().equals(ANNOTATION_TYPE_BREAKPOINT);
|
||||
}
|
||||
|
||||
private boolean containsBreakpointAnnotation(List<Annotation> annotations) {
|
||||
for(Annotation a : annotations) {
|
||||
if(isBreakpointAnnotation(a)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2002, 2010 QNX Software Systems and others.
|
||||
* Copyright (c) 2002, 2016 QNX Software Systems 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
|
||||
|
@ -20,6 +20,7 @@ public final class CHoverMessages extends NLS {
|
|||
public static String AbstractAnnotationHover_message_singleQuickFix;
|
||||
public static String AbstractAnnotationHover_message_multipleQuickFix;
|
||||
|
||||
public static String CExpandHover_tooltip_noBreakpoint;
|
||||
public static String CMacroExpansionControl_exploreMacroExpansion;
|
||||
public static String CMacroExpansionControl_statusText;
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
###############################################################################
|
||||
# Copyright (c) 2000, 2009 IBM Corporation and others.
|
||||
# Copyright (c) 2000, 2016 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
|
||||
|
@ -14,6 +14,7 @@ AbstractAnnotationHover_action_configureAnnotationPreferences= Configure Annotat
|
|||
AbstractAnnotationHover_message_singleQuickFix= 1 quick fix available:
|
||||
AbstractAnnotationHover_message_multipleQuickFix= {0} quick fixes available:
|
||||
|
||||
CExpandHover_tooltip_noBreakpoint=Add a breakpoint
|
||||
CMacroExpansionControl_exploreMacroExpansion=Press "{0}" for macro expansion steps
|
||||
CMacroExpansionControl_statusText=Press {0} or {1} to step through macro expansion
|
||||
CMacroExpansionControl_title_expansion=Expansion \#{0} of {1}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2005, 2015 IBM Corporation and others.
|
||||
* Copyright (c) 2005, 2016 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
|
||||
|
@ -2113,6 +2113,17 @@ public class PreferenceConstants {
|
|||
*/
|
||||
public static final String INCLUDE_STYLE_MATCHING_PATTERN = "includeStyle.matchingPattern"; //$NON-NLS-1$
|
||||
|
||||
/**
|
||||
* A named preference that controls whether annotation roll over is used or not.
|
||||
* <p>
|
||||
* Value is of type <code>Boolean</code>. If <code>true</code> the annotation ruler column
|
||||
* uses a roll over to display multiple annotations
|
||||
* </p>
|
||||
*
|
||||
* @since 6.1
|
||||
*/
|
||||
public static final String EDITOR_ANNOTATION_ROLL_OVER= "editor_annotation_roll_over"; //$NON-NLS-1$
|
||||
|
||||
/**
|
||||
* Returns the CDT-UI preference store.
|
||||
*
|
||||
|
@ -2142,6 +2153,8 @@ public class PreferenceConstants {
|
|||
|
||||
store.setDefault(EDITOR_SOURCE_HOVER_BACKGROUND_COLOR_SYSTEM_DEFAULT, true);
|
||||
|
||||
store.setDefault(EDITOR_ANNOTATION_ROLL_OVER, false);
|
||||
|
||||
// Syntax highlighting
|
||||
store.setDefault(EDITOR_MULTI_LINE_COMMENT_BOLD, false);
|
||||
store.setDefault(EDITOR_MULTI_LINE_COMMENT_ITALIC, false);
|
||||
|
|
Loading…
Add table
Reference in a new issue