From 6124157befb7ba000503d85dbe91ed7edff63fcc Mon Sep 17 00:00:00 2001 From: Alain Magloire Date: Tue, 1 Jun 2004 05:13:07 +0000 Subject: [PATCH] 2004-05-31 Alain Magloire Putting a good chunk of code(Taken from JDT) to do proper hovering. --- core/org.eclipse.cdt.ui/ChangeLog | 6 + core/org.eclipse.cdt.ui/plugin.properties | 15 + core/org.eclipse.cdt.ui/plugin.xml | 34 + .../ui/codemanipulation/StubUtility.java | 33 +- .../ui/editor/CAnnotationIterator.java | 98 +++ .../internal/ui/editor/CEditorMessages.java | 35 +- .../ui/editor/CEditorMessages.properties | 2 + .../ui/editor/CEditorTextHoverDispatcher.java | 60 -- .../ui/editor/DefaultCEditorTextHover.java | 135 ---- .../CEditorHoverConfigurationBlock.java | 597 ++++++++++++++++++ .../ui/preferences/CEditorPreferencePage.java | 15 +- .../preferences/OverlayPreferenceStore.java | 34 +- .../PreferencesMessages.properties | 23 + .../ui/text/CSourceViewerConfiguration.java | 99 +-- .../internal/ui/text/PreferencesAdapter.java | 309 +++++++++ .../text/c/hover/AbstractAnnotationHover.java | 122 ++++ .../c/hover/AbstractCEditorTextHover.java | 176 ++++++ .../ui/text/c/hover/AnnotationHover.java | 25 + .../ui/text/c/hover/BestMatchHover.java | 132 ++++ .../internal/ui/text/c/hover/CDocHover.java | 84 +++ .../c/hover/CEditorTextHoverDescriptor.java | 294 +++++++++ .../text/c/hover/CEditorTextHoverProxy.java | 107 ++++ .../ui/text/c/hover/CHoverMessages.java | 91 +++ .../ui/text/c/hover/CHoverMessages.properties | 18 + .../ui/text/c/hover/CSourceHover.java | 130 ++++ .../cdt/internal/ui/util/EditorUtility.java | 67 +- .../src/org/eclipse/cdt/ui/CUIPlugin.java | 116 +++- .../eclipse/cdt/ui/PreferenceConstants.java | 30 + .../ui/text/c/hover/ICEditorTextHover.java | 35 + 29 files changed, 2661 insertions(+), 261 deletions(-) create mode 100644 core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CAnnotationIterator.java delete mode 100644 core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CEditorTextHoverDispatcher.java delete mode 100644 core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/DefaultCEditorTextHover.java create mode 100644 core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/CEditorHoverConfigurationBlock.java create mode 100644 core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/PreferencesAdapter.java create mode 100644 core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/AbstractAnnotationHover.java create mode 100644 core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/AbstractCEditorTextHover.java create mode 100644 core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/AnnotationHover.java create mode 100644 core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/BestMatchHover.java create mode 100644 core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CDocHover.java create mode 100644 core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CEditorTextHoverDescriptor.java create mode 100644 core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CEditorTextHoverProxy.java create mode 100644 core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CHoverMessages.java create mode 100644 core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CHoverMessages.properties create mode 100644 core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CSourceHover.java create mode 100644 core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/text/c/hover/ICEditorTextHover.java diff --git a/core/org.eclipse.cdt.ui/ChangeLog b/core/org.eclipse.cdt.ui/ChangeLog index 1bf2f438b9b..23f290120fa 100644 --- a/core/org.eclipse.cdt.ui/ChangeLog +++ b/core/org.eclipse.cdt.ui/ChangeLog @@ -1,3 +1,9 @@ +2004-05-31 Alain Magloire + + Putting a good chunk of code(Taken from JDT) + to do proper hovering. + To many files to enumerate. + 2004-05-31 Bogdan Gheorghe Added warning message to status line when C search page is invoked and not all diff --git a/core/org.eclipse.cdt.ui/plugin.properties b/core/org.eclipse.cdt.ui/plugin.properties index 89383c39f9a..daf4692cbc6 100644 --- a/core/org.eclipse.cdt.ui/plugin.properties +++ b/core/org.eclipse.cdt.ui/plugin.properties @@ -181,3 +181,18 @@ CBrowsing.namespacesViewName= Namespaces CBrowsing.typesViewName= Types CBrowsing.membersViewName= Members CBrowsing.preferencePageName= Browsing + +# hovering contribution +CEditorTextHoversName=C Editor Text Hovers +sourceHover= Source +sourceHoverDescription= Shows the source of the selected element. +cdocHover= Documentation +cdocHoverDescription= Shows the documentation of the selected element. +sequentialHover= Combined Hover +sequentialHoverDescription= Tries the hovers in the sequence listed below and uses the one which fits best for the selected element and the current context. +annotationHover= Annotation Description +annotationHoverDescription= Shows the description of the selected annotation. +problemHover= Problem Description +problemHoverDescription= Shows the description of the selected problem. + + diff --git a/core/org.eclipse.cdt.ui/plugin.xml b/core/org.eclipse.cdt.ui/plugin.xml index cf66b956836..fe612a91ff0 100644 --- a/core/org.eclipse.cdt.ui/plugin.xml +++ b/core/org.eclipse.cdt.ui/plugin.xml @@ -123,6 +123,40 @@ id="org.eclipse.cdt.internal.ui.CView.NonCElementFilter"> + + + + + + + + + + + + CAnnotationIterator(model, skipIrrelevants, false). + */ + 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 + */ + public CAnnotationIterator(IAnnotationModel model, boolean skipIrrelevants, boolean returnAllAnnotations) { + fReturnAllAnnotations= returnAllAnnotations; + if (model != null) + fIterator= model.getAnnotationIterator(); + else + fIterator= Collections.EMPTY_LIST.iterator(); + fSkipIrrelevants= skipIrrelevants; + skip(); + } + + private void skip() { + while (fIterator.hasNext()) { + Annotation next= (Annotation) fIterator.next(); + if (next instanceof ICAnnotation) { + if (fSkipIrrelevants) { + if (!next.isMarkedDeleted()) { + fNext= next; + return; + } + } else { + fNext= next; + return; + } + } else if (fReturnAllAnnotations) { + fNext= next; + return; + } + } + fNext= null; + } + + /* + * @see Iterator#hasNext() + */ + public boolean hasNext() { + return fNext != null; + } + + /* + * @see Iterator#next() + */ + public Object next() { + try { + return fNext; + } finally { + skip(); + } + } + + /* + * @see Iterator#remove() + */ + public void remove() { + throw new UnsupportedOperationException(); + } +} diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CEditorMessages.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CEditorMessages.java index 11eba97a1cf..e7c8fb67f8b 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CEditorMessages.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CEditorMessages.java @@ -5,12 +5,12 @@ package org.eclipse.cdt.internal.ui.editor; * All Rights Reserved. */ +import java.text.MessageFormat; import java.util.MissingResourceException; import java.util.ResourceBundle; -public class CEditorMessages -{ +public class CEditorMessages { private static final String RESOURCE_BUNDLE = "org.eclipse.cdt.internal.ui.editor.CEditorMessages"; //$NON-NLS-1$ @@ -24,29 +24,38 @@ public class CEditorMessages } - private CEditorMessages() - { + private CEditorMessages() { } - public static ResourceBundle getResourceBundle() - { + public static ResourceBundle getResourceBundle() { return fgResourceBundle; } - public static String getString( String key ) - { - try - { + public static String getString( String key ) { + try { return fgResourceBundle.getString( key ); - } - catch( MissingResourceException e ) - { + } catch(MissingResourceException e) { return "!" + key + "!"; //$NON-NLS-1$ //$NON-NLS-2$ } catch (NullPointerException e) { return "#" + key + "#"; //$NON-NLS-1$ //$NON-NLS-2$ } } + + /** + * Gets a string from the resource bundle and formats it with arguments + */ + public static String getFormattedString(String key, Object[] args) { + return MessageFormat.format(getString(key), args); + } + + /** + * Gets a string from the resource bundle and formats it with arguments + */ + public static String getFormattedString(String key, Object arg) { + return MessageFormat.format(getString(key), new Object[] { arg } ); + } + } diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CEditorMessages.properties b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CEditorMessages.properties index 03837fc1e4d..4231b169f0a 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CEditorMessages.properties +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CEditorMessages.properties @@ -146,3 +146,5 @@ CContentOutlinePage.menu.fileSearch=File Search CContentOutlinePage.error.noInput=no Editor Input CEditor.menu.fileSearch=File Search CEditor.menu.search=Search + +EditorUtility.concatModifierStrings= {0} + {1} diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CEditorTextHoverDispatcher.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CEditorTextHoverDispatcher.java deleted file mode 100644 index 9007d928e9e..00000000000 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CEditorTextHoverDispatcher.java +++ /dev/null @@ -1,60 +0,0 @@ -package org.eclipse.cdt.internal.ui.editor; - -/* - * (c) Copyright QNX Software Systems Ltd. 2002. - * All Rights Reserved. - */ - -import java.util.HashMap; - -import org.eclipse.jface.text.IRegion; -import org.eclipse.jface.text.ITextHover; -import org.eclipse.jface.text.ITextViewer; -import org.eclipse.ui.IEditorPart; -import org.eclipse.ui.IWorkbenchPage; - -public class CEditorTextHoverDispatcher implements ITextHover -{ - private IEditorPart fEditor = null; - private HashMap fTextHovers = null; - private DefaultCEditorTextHover fDefaultTextHover = null; - - /** - * Constructor for CEditorTextHover - */ - public CEditorTextHoverDispatcher( IEditorPart editor, HashMap textHovers ) - { - fEditor = editor; - fTextHovers = textHovers; - fDefaultTextHover = new DefaultCEditorTextHover( editor ); - } - - /** - * @see ITextHover#getHoverInfo(ITextViewer, IRegion) - */ - public String getHoverInfo( ITextViewer textViewer, IRegion region ) - { - return getCurrentTextHover().getHoverInfo( textViewer, region ); - } - - /** - * @see ITextHover#getHoverRegion(ITextViewer, int) - */ - public IRegion getHoverRegion( ITextViewer textViewer, int offset ) - { - return getCurrentTextHover().getHoverRegion( textViewer, offset ); - } - - private ITextHover getCurrentTextHover() - { - IWorkbenchPage page; - if(fEditor != null && fEditor.getSite() != null && - (page = fEditor.getSite().getPage()) != null) { - Object textHover = fTextHovers.get( page.getPerspective().getId() ); - if ( textHover != null && textHover instanceof ITextHover ) - return (ITextHover)textHover; - } - return fDefaultTextHover; - } -} - diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/DefaultCEditorTextHover.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/DefaultCEditorTextHover.java deleted file mode 100644 index 5837b4e4b5f..00000000000 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/DefaultCEditorTextHover.java +++ /dev/null @@ -1,135 +0,0 @@ -package org.eclipse.cdt.internal.ui.editor; - -/* - * (c) Copyright QNX Software Systems Ltd. 2002. - * All Rights Reserved. - */ - -import org.eclipse.cdt.internal.ui.CCompletionContributorManager; -import org.eclipse.cdt.internal.ui.text.CWordFinder; -import org.eclipse.cdt.internal.ui.text.HTMLPrinter; -import org.eclipse.cdt.ui.IFunctionSummary; -import org.eclipse.jface.text.IRegion; -import org.eclipse.jface.text.ITextHover; -import org.eclipse.jface.text.ITextViewer; -import org.eclipse.jface.text.Region; -import org.eclipse.swt.graphics.Point; -import org.eclipse.ui.IEditorPart; - -public class DefaultCEditorTextHover implements ITextHover -{ - protected IEditorPart fEditor; - - /** - * Constructor for DefaultCEditorTextHover - */ - public DefaultCEditorTextHover( IEditorPart editor ) - { - fEditor = editor; - } - - /** - * @see ITextHover#getHoverInfo(ITextViewer, IRegion) - */ - public String getHoverInfo( ITextViewer viewer, IRegion region ) - { - String expression = null; - - if(fEditor == null) - return null; - try - { - expression = viewer.getDocument().get( region.getOffset(), region.getLength() ); - expression = expression.trim(); - if ( expression.length() == 0 ) - return null; - - StringBuffer buffer = new StringBuffer(); - - // We are just doing some C, call the Help to get info - - IFunctionSummary fs = CCompletionContributorManager.getDefault().getFunctionInfo(expression); - if(fs != null) { - buffer.append(CEditorMessages.getString("DefaultCEditorTextHover.html.name")); //$NON-NLS-1$ - buffer.append(HTMLPrinter.convertToHTMLContent(fs.getName())); - buffer.append(CEditorMessages.getString("DefaultCEditorTextHover.html.prototype")); //$NON-NLS-1$ - buffer.append(HTMLPrinter.convertToHTMLContent(fs.getPrototype().getPrototypeString(false))); - if(fs.getDescription() != null) { - buffer.append(CEditorMessages.getString("DefaultCEditorTextHover.html.description")); //$NON-NLS-1$ - //Don't convert this description since it could already be formatted - buffer.append(fs.getDescription()); - } -// int i; -// for(i = 0; i < buffer.length(); i++) { -// if(buffer.charAt(i) == '\\') { -// if((i + 1 < buffer.length()) && buffer.charAt(i+1) == 'n') { -// buffer.replace(i, i + 2, "
"); -// } -// } -// } - } -// else { -// // Query the C model -// IndexModel model = IndexModel.getDefault(); -// IEditorInput input = fEditor.getEditorInput(); -// if(input instanceof IFileEditorInput) { -// IProject project = ((IFileEditorInput)input).getFile().getProject(); -// -// // Bail out quickly, if the project was deleted. -// if (!project.exists()) -// throw new CoreException(new Status(0, "", 0, "", null)); -// -// IProject[] refs = project.getReferencedProjects(); -// -// ITagEntry[] tags= model.query(project, expression, false, true); -// -// if(tags == null || tags.length == 0) { -// for ( int j= 0; j < refs.length; j++ ) { -// if (!refs[j].exists()) -// continue; -// tags= model.query(refs[j], expression, false, true); -// if(tags != null && tags.length > 0) -// break; -// } -// } -// -// if(tags != null && tags.length > 0) { -// ITagEntry selectedTag = selectTag(tags); -// // Show only the first element -// buffer.append(" " + TagFlags.value(selectedTag.getKind()) + " " + HTMLPrinter.convertToHTMLContent(expression) + -// " - " + selectedTag.getIFile().getFullPath().toString() + "[" + selectedTag.getLineNumber()+"]" ); -// // Now add the pattern -// buffer.append("

" + HTMLPrinter.convertToHTMLContent(selectedTag.getPattern())); -// } -// } -// } - if (buffer.length() > 0) { - HTMLPrinter.insertPageProlog(buffer, 0); - HTMLPrinter.addPageEpilog(buffer); - return buffer.toString(); - } - } catch(Exception ex) { - /* Ignore */ - } - - return null; - } - - /** - * @see ITextHover#getHoverRegion(ITextViewer, int) - */ - public IRegion getHoverRegion( ITextViewer viewer, int offset ) - { - Point selectedRange = viewer.getSelectedRange(); - if ( selectedRange.x >= 0 && - selectedRange.y > 0 && - offset >= selectedRange.x && - offset <= selectedRange.x + selectedRange.y ) - return new Region( selectedRange.x, selectedRange.y ); - if ( viewer != null ) - return CWordFinder.findWord( viewer.getDocument(), offset ); - return null; - } - -} - diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/CEditorHoverConfigurationBlock.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/CEditorHoverConfigurationBlock.java new file mode 100644 index 00000000000..6964a5b48ab --- /dev/null +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/CEditorHoverConfigurationBlock.java @@ -0,0 +1,597 @@ +/********************************************************************** + * Copyright (c) 2002,2003,2004 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + ***********************************************************************/ + +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.cdt.internal.ui.dialogs.StatusInfo; +import org.eclipse.cdt.internal.ui.dialogs.StatusUtil; +import org.eclipse.cdt.internal.ui.text.c.hover.CEditorTextHoverDescriptor; +import org.eclipse.cdt.internal.ui.util.PixelConverter; +import org.eclipse.cdt.internal.ui.util.SWTUtil; +import org.eclipse.cdt.internal.ui.util.TableLayoutComposite; +import org.eclipse.cdt.ui.CUIPlugin; +import org.eclipse.cdt.ui.PreferenceConstants; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.jface.action.Action; +import org.eclipse.jface.dialogs.Dialog; +import org.eclipse.jface.text.Assert; +import org.eclipse.jface.viewers.CheckStateChangedEvent; +import org.eclipse.jface.viewers.CheckboxTableViewer; +import org.eclipse.jface.viewers.ColumnWeightData; +import org.eclipse.jface.viewers.ICheckStateListener; +import org.eclipse.jface.viewers.ILabelProviderListener; +import org.eclipse.jface.viewers.IStructuredContentProvider; +import org.eclipse.jface.viewers.ITableLabelProvider; +import org.eclipse.jface.viewers.TableLayout; +import org.eclipse.jface.viewers.TableViewer; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.KeyEvent; +import org.eclipse.swt.events.KeyListener; +import org.eclipse.swt.events.ModifyEvent; +import org.eclipse.swt.events.ModifyListener; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +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; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.TableColumn; +import org.eclipse.swt.widgets.TableItem; +import org.eclipse.swt.widgets.Text; + +/** + * CEditorHoverConfigurationBlock + */ +public class CEditorHoverConfigurationBlock { + private static final String DELIMITER= PreferencesMessages.getString("JavaEditorHoverConfigurationBlock.delimiter"); //$NON-NLS-1$ + + private static final int ENABLED_PROP= 0; + private static final int MODIFIER_PROP= 1; + + // Data structure to hold the values which are edited by the user + private static class HoverConfig { + + private String fModifierString; + private boolean fIsEnabled; + private int fStateMask; + + private HoverConfig(String modifier, int stateMask, boolean enabled) { + fModifierString= modifier; + fIsEnabled= enabled; + fStateMask= stateMask; + } + } + + + private class JavaEditorTextHoverDescriptorLabelProvider implements ITableLabelProvider { + + public Image getColumnImage(Object element, int columnIndex) { + return null; + } + + public String getColumnText(Object element, int columnIndex) { + switch (columnIndex) { + case ENABLED_PROP: + return ((CEditorTextHoverDescriptor)element).getLabel(); + + case MODIFIER_PROP: + TableItem item= (TableItem)fHoverTableViewer.testFindItem(element); + int index= fHoverTable.indexOf(item); + return fHoverConfigs[index].fModifierString; + + default: + break; + } + + return null; + } + + public void addListener(ILabelProviderListener listener) { + } + + public void dispose() { + } + + public boolean isLabelProperty(Object element, String property) { + return false; + } + + public void removeListener(ILabelProviderListener listener) { + } + } + + + private class JavaEditorTextHoverDescriptorContentProvider implements IStructuredContentProvider { + + public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { + // Do nothing since the viewer listens to resource deltas + } + + public void dispose() { + } + + public boolean isDeleted(Object element) { + return false; + } + + public Object[] getElements(Object element) { + return (Object[])element; + } + } + + + private OverlayPreferenceStore fStore; + private HoverConfig[] fHoverConfigs; + private Text fModifierEditor; + private Table fHoverTable; + private TableViewer fHoverTableViewer; + private TableColumn fNameColumn; + private TableColumn fModifierColumn; + private Text fDescription; + //private Button fShowHoverAffordanceCheckbox; + + private CEditorPreferencePage fMainPreferencePage; + + private StatusInfo fStatus; + + private Map fCheckBoxes= new HashMap(); + private SelectionListener fCheckBoxListener= new SelectionListener() { + public void widgetDefaultSelected(SelectionEvent e) { + Button button= (Button) e.widget; + fStore.setValue((String) fCheckBoxes.get(button), button.getSelection()); + } + public void widgetSelected(SelectionEvent e) { + Button button= (Button) e.widget; + fStore.setValue((String) fCheckBoxes.get(button), button.getSelection()); + } + }; + + + public CEditorHoverConfigurationBlock(CEditorPreferencePage mainPreferencePage, OverlayPreferenceStore store) { + Assert.isNotNull(mainPreferencePage); + Assert.isNotNull(store); + fMainPreferencePage= mainPreferencePage; + fStore= store; + fStore.addKeys(createOverlayStoreKeys()); + } + + + private OverlayPreferenceStore.OverlayKey[] createOverlayStoreKeys() { + + ArrayList overlayKeys= new ArrayList(); + + //overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.BOOLEAN, PreferenceConstants.EDITOR_ANNOTATION_ROLL_OVER)); + + //overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.BOOLEAN, PreferenceConstants.EDITOR_SHOW_TEXT_HOVER_AFFORDANCE)); + 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)); + + OverlayPreferenceStore.OverlayKey[] keys= new OverlayPreferenceStore.OverlayKey[overlayKeys.size()]; + overlayKeys.toArray(keys); + return keys; + } + + /** + * Creates page for hover preferences. + * + * @param parent the parent composite + * @return the control for the preference page + */ + public Control createControl(Composite parent) { + + Composite hoverComposite= new Composite(parent, SWT.NONE); + GridLayout layout= new GridLayout(); + layout.numColumns= 2; + hoverComposite.setLayout(layout); + GridData gd= new GridData(GridData.FILL_BOTH); + hoverComposite.setLayoutData(gd); + + //String rollOverLabel= PreferencesMessages.getString("CEditorHoverConfigurationBlock.annotationRollover"); //$NON-NLS-1$ + //addCheckBox(hoverComposite, rollOverLabel, PreferenceConstants.EDITOR_ANNOTATION_ROLL_OVER, 0); //$NON-NLS-1$ + + // Affordance checkbox + //fShowHoverAffordanceCheckbox= new Button(hoverComposite, SWT.CHECK); + //fShowHoverAffordanceCheckbox.setText(PreferencesMessages.getString("CEditorHoverConfigurationBlock.showAffordance")); //$NON-NLS-1$ + gd= new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING); + gd.horizontalIndent= 0; + gd.horizontalSpan= 2; + //fShowHoverAffordanceCheckbox.setLayoutData(gd); + + addFiller(hoverComposite); + + Label label= new Label(hoverComposite, SWT.NONE); + label.setText(PreferencesMessages.getString("CEditorHoverConfigurationBlock.hoverPreferences")); //$NON-NLS-1$ + gd= new GridData(GridData.FILL_HORIZONTAL); + gd.horizontalAlignment= GridData.BEGINNING; + gd.horizontalSpan= 2; + label.setLayoutData(gd); + + TableLayoutComposite layouter= new TableLayoutComposite(hoverComposite, SWT.NONE); + addColumnLayoutData(layouter); + + // Hover table + fHoverTable= new Table(layouter, SWT.H_SCROLL | SWT.V_SCROLL | SWT.MULTI | SWT.BORDER | SWT.FULL_SELECTION | SWT.CHECK); + fHoverTable.setHeaderVisible(true); + fHoverTable.setLinesVisible(true); + + gd= new GridData(GridData.FILL_HORIZONTAL); + gd.heightHint= SWTUtil.getTableHeightHint(fHoverTable, 10); + gd.horizontalSpan= 2; + gd.widthHint= new PixelConverter(parent).convertWidthInCharsToPixels(30); + layouter.setLayoutData(gd); + + fHoverTable.addSelectionListener(new SelectionListener() { + public void widgetSelected(SelectionEvent e) { + handleHoverListSelection(); + } + public void widgetDefaultSelected(SelectionEvent e) { + } + }); + + TableLayout tableLayout= new TableLayout(); + fHoverTable.setLayout(tableLayout); + + fNameColumn= new TableColumn(fHoverTable, SWT.NONE); + fNameColumn.setText(PreferencesMessages.getString("CEditorHoverConfigurationBlock.nameColumnTitle")); //$NON-NLS-1$ + fNameColumn.setResizable(true); + + fModifierColumn= new TableColumn(fHoverTable, SWT.NONE); + fModifierColumn.setText(PreferencesMessages.getString("CEditorHoverConfigurationBlock.modifierColumnTitle")); //$NON-NLS-1$ + fModifierColumn.setResizable(true); + + fHoverTableViewer= new CheckboxTableViewer(fHoverTable); + fHoverTableViewer.setUseHashlookup(true); + fHoverTableViewer.setContentProvider(new JavaEditorTextHoverDescriptorContentProvider()); + fHoverTableViewer.setLabelProvider(new JavaEditorTextHoverDescriptorLabelProvider()); + + ((CheckboxTableViewer)fHoverTableViewer).addCheckStateListener(new ICheckStateListener() { + /* + * @see org.eclipse.jface.viewers.ICheckStateListener#checkStateChanged(org.eclipse.jface.viewers.CheckStateChangedEvent) + */ + public void checkStateChanged(CheckStateChangedEvent event) { + String id= ((CEditorTextHoverDescriptor)event.getElement()).getId(); + if (id == null) + return; + CEditorTextHoverDescriptor[] descriptors= getContributedHovers(); + int i= 0, length= fHoverConfigs.length; + while (i < length) { + if (id.equals(descriptors[i].getId())) { + fHoverConfigs[i].fIsEnabled= event.getChecked(); + fModifierEditor.setEnabled(event.getChecked()); + break; + } + i++; + } + updateStatus(); + } + }); + + // Text field for modifier string + label= new Label(hoverComposite, SWT.LEFT); + label.setText(PreferencesMessages.getString("CEditorHoverConfigurationBlock.keyModifier")); //$NON-NLS-1$ + fModifierEditor= new Text(hoverComposite, SWT.BORDER); + gd= new GridData(GridData.HORIZONTAL_ALIGN_FILL); + fModifierEditor.setLayoutData(gd); + + fModifierEditor.addKeyListener(new KeyListener() { + private boolean isModifierCandidate; + public void keyPressed(KeyEvent e) { + isModifierCandidate= e.keyCode > 0 && e.character == 0 && e.stateMask == 0; + } + + public void keyReleased(KeyEvent e) { + if (isModifierCandidate && e.stateMask > 0 && e.stateMask == e.stateMask && e.character == 0) {// && e.time -time < 1000) { + String text= fModifierEditor.getText(); + Point selection= fModifierEditor.getSelection(); + int i= selection.x - 1; + while (i > -1 && Character.isWhitespace(text.charAt(i))) { + i--; + } + boolean needsPrefixDelimiter= i > -1 && !String.valueOf(text.charAt(i)).equals(DELIMITER); + + i= selection.y; + while (i < text.length() && Character.isWhitespace(text.charAt(i))) { + i++; + } + boolean needsPostfixDelimiter= i < text.length() && !String.valueOf(text.charAt(i)).equals(DELIMITER); + + String insertString; + + if (needsPrefixDelimiter && needsPostfixDelimiter) + insertString= PreferencesMessages.getFormattedString("CEditorHoverConfigurationBlock.insertDelimiterAndModifierAndDelimiter", new String[] {Action.findModifierString(e.stateMask)}); //$NON-NLS-1$ + else if (needsPrefixDelimiter) + insertString= PreferencesMessages.getFormattedString("CEditorHoverConfigurationBlock.insertDelimiterAndModifier", new String[] {Action.findModifierString(e.stateMask)}); //$NON-NLS-1$ + else if (needsPostfixDelimiter) + insertString= PreferencesMessages.getFormattedString("CEditorHoverConfigurationBlock.insertModifierAndDelimiter", new String[] {Action.findModifierString(e.stateMask)}); //$NON-NLS-1$ + else + insertString= Action.findModifierString(e.stateMask); + + if (insertString != null) + fModifierEditor.insert(insertString); + } + } + }); + + fModifierEditor.addModifyListener(new ModifyListener() { + public void modifyText(ModifyEvent e) { + handleModifierModified(); + } + }); + + // Description + Label descriptionLabel= new Label(hoverComposite, SWT.LEFT); + descriptionLabel.setText(PreferencesMessages.getString("CEditorHoverConfigurationBlock.description")); //$NON-NLS-1$ + gd= new GridData(GridData.VERTICAL_ALIGN_BEGINNING); + gd.horizontalSpan= 2; + descriptionLabel.setLayoutData(gd); + fDescription= new Text(hoverComposite, SWT.LEFT | SWT.WRAP | SWT.MULTI | SWT.READ_ONLY | SWT.BORDER); + gd= new GridData(GridData.FILL_BOTH); + gd.horizontalSpan= 2; + fDescription.setLayoutData(gd); + + initialize(); + + Dialog.applyDialogFont(hoverComposite); + return hoverComposite; + } + + private void addColumnLayoutData(TableLayoutComposite layouter) { + layouter.addColumnData(new ColumnWeightData(40, true)); + layouter.addColumnData(new ColumnWeightData(60, true)); + } + + private CEditorTextHoverDescriptor[] getContributedHovers() { + CEditorTextHoverDescriptor[] hoverDescriptors= CUIPlugin.getDefault().getCEditorTextHoverDescriptors(); + + // Move Best Match hover to front + CEditorTextHoverDescriptor currentHover= hoverDescriptors[0]; + boolean done= false; + for (int i= 0; !done && i < hoverDescriptors.length; i++) { + if (PreferenceConstants.ID_BESTMATCH_HOVER.equals(hoverDescriptors[i].getId())) { + // Swap with first one + hoverDescriptors[0]= hoverDescriptors[i]; + hoverDescriptors[i]= currentHover; + return hoverDescriptors; + } + if (i > 0) { + currentHover= hoverDescriptors[i]; + hoverDescriptors[i]= hoverDescriptors[i-1]; + } + } + + // return unchanged array if best match hover can't be found + return CUIPlugin.getDefault().getCEditorTextHoverDescriptors(); + } + + void initialize() { + CEditorTextHoverDescriptor[] hoverDescs= getContributedHovers(); + fHoverConfigs= new HoverConfig[hoverDescs.length]; + for (int i= 0; i < hoverDescs.length; i++) + fHoverConfigs[i]= new HoverConfig(hoverDescs[i].getModifierString(), hoverDescs[i].getStateMask(), hoverDescs[i].isEnabled()); + + fHoverTableViewer.setInput(hoverDescs); + + initializeFields(); + } + + void initializeFields() { + //fShowHoverAffordanceCheckbox.setSelection(fStore.getBoolean(PreferenceConstants.EDITOR_SHOW_TEXT_HOVER_AFFORDANCE)); + + fModifierEditor.setEnabled(false); + + Iterator e= fCheckBoxes.keySet().iterator(); + while (e.hasNext()) { + Button b= (Button) e.next(); + String key= (String) 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()); + fHoverTableViewer.refresh(); + } + + void performOk() { + StringBuffer buf= new StringBuffer(); + StringBuffer maskBuf= new StringBuffer(); + for (int i= 0; i < fHoverConfigs.length; i++) { + buf.append(getContributedHovers()[i].getId()); + buf.append(CEditorTextHoverDescriptor.VALUE_SEPARATOR); + if (!fHoverConfigs[i].fIsEnabled) + buf.append(CEditorTextHoverDescriptor.DISABLED_TAG); + String modifier= fHoverConfigs[i].fModifierString; + if (modifier == null || modifier.length() == 0) + modifier= CEditorTextHoverDescriptor.NO_MODIFIER; + buf.append(modifier); + buf.append(CEditorTextHoverDescriptor.VALUE_SEPARATOR); + + maskBuf.append(getContributedHovers()[i].getId()); + maskBuf.append(CEditorTextHoverDescriptor.VALUE_SEPARATOR); + maskBuf.append(fHoverConfigs[i].fStateMask); + maskBuf.append(CEditorTextHoverDescriptor.VALUE_SEPARATOR); + } + fStore.setValue(PreferenceConstants.EDITOR_TEXT_HOVER_MODIFIERS, buf.toString()); + fStore.setValue(PreferenceConstants.EDITOR_TEXT_HOVER_MODIFIER_MASKS, maskBuf.toString()); + + //fStore.setValue(PreferenceConstants.EDITOR_SHOW_TEXT_HOVER_AFFORDANCE, fShowHoverAffordanceCheckbox.getSelection()); + + CUIPlugin.getDefault().resetCEditorTextHoverDescriptors(); + } + + void performDefaults() { + restoreFromPreferences(); + initializeFields(); + } + + private void restoreFromPreferences() { + + //fShowHoverAffordanceCheckbox.setSelection(fStore.getBoolean(PreferenceConstants.EDITOR_SHOW_TEXT_HOVER_AFFORDANCE)); + + String compiledTextHoverModifiers= fStore.getString(PreferenceConstants.EDITOR_TEXT_HOVER_MODIFIERS); + + StringTokenizer tokenizer= new StringTokenizer(compiledTextHoverModifiers, CEditorTextHoverDescriptor.VALUE_SEPARATOR); + HashMap idToModifier= new HashMap(tokenizer.countTokens() / 2); + + while (tokenizer.hasMoreTokens()) { + String id= tokenizer.nextToken(); + if (tokenizer.hasMoreTokens()) + idToModifier.put(id, tokenizer.nextToken()); + } + + String compiledTextHoverModifierMasks= CUIPlugin.getDefault().getPreferenceStore().getString(PreferenceConstants.EDITOR_TEXT_HOVER_MODIFIER_MASKS); + + tokenizer= new StringTokenizer(compiledTextHoverModifierMasks, CEditorTextHoverDescriptor.VALUE_SEPARATOR); + HashMap idToModifierMask= new HashMap(tokenizer.countTokens() / 2); + + while (tokenizer.hasMoreTokens()) { + String id= tokenizer.nextToken(); + if (tokenizer.hasMoreTokens()) + idToModifierMask.put(id, tokenizer.nextToken()); + } + + for (int i= 0; i < fHoverConfigs.length; i++) { + String modifierString= (String)idToModifier.get(getContributedHovers()[i].getId()); + boolean enabled= true; + if (modifierString == null) + modifierString= CEditorTextHoverDescriptor.DISABLED_TAG; + + if (modifierString.startsWith(CEditorTextHoverDescriptor.DISABLED_TAG)) { + enabled= false; + modifierString= modifierString.substring(1); + } + + if (modifierString.equals(CEditorTextHoverDescriptor.NO_MODIFIER)) + modifierString= ""; //$NON-NLS-1$ + + fHoverConfigs[i].fModifierString= modifierString; + fHoverConfigs[i].fIsEnabled= enabled; + fHoverConfigs[i].fStateMask= CEditorTextHoverDescriptor.computeStateMask(modifierString); + + if (fHoverConfigs[i].fStateMask == -1) { + try { + fHoverConfigs[i].fStateMask= Integer.parseInt((String)idToModifierMask.get(getContributedHovers()[i].getId())); + } catch (NumberFormatException ex) { + fHoverConfigs[i].fStateMask= -1; + } + } + } + } + + private void handleModifierModified() { + int i= fHoverTable.getSelectionIndex(); + String modifiers= fModifierEditor.getText(); + fHoverConfigs[i].fModifierString= modifiers; + fHoverConfigs[i].fStateMask= CEditorTextHoverDescriptor.computeStateMask(modifiers); + if (fHoverConfigs[i].fIsEnabled && fHoverConfigs[i].fStateMask == -1) + fStatus= new StatusInfo(IStatus.ERROR, PreferencesMessages.getFormattedString("CEditorHoverConfigurationBlock.modifierIsNotValid", fHoverConfigs[i].fModifierString)); //$NON-NLS-1$ + else + fStatus= new StatusInfo(); + + // update table + fHoverTableViewer.refresh(getContributedHovers()[i]); + + updateStatus(); + } + + private void handleHoverListSelection() { + int i= fHoverTable.getSelectionIndex(); + + if (i < 0) { + if (fHoverTable.getSelectionCount() == 0) + fModifierEditor.setEnabled(false); + return; + } + + boolean enabled= fHoverConfigs[i].fIsEnabled; + fModifierEditor.setEnabled(enabled); + fModifierEditor.setText(fHoverConfigs[i].fModifierString); + String description= getContributedHovers()[i].getDescription(); + if (description == null) + description= ""; //$NON-NLS-1$ + fDescription.setText(description); + } + + IStatus getStatus() { + if (fStatus == null) + fStatus= new StatusInfo(); + return fStatus; + } + + private void updateStatus() { + int i= 0; + HashMap stateMasks= new HashMap(fHoverConfigs.length); + while (fStatus.isOK() && i < fHoverConfigs.length) { + if (fHoverConfigs[i].fIsEnabled) { + String label= getContributedHovers()[i].getLabel(); + Integer stateMask= new Integer(fHoverConfigs[i].fStateMask); + if (fHoverConfigs[i].fStateMask == -1) + fStatus= new StatusInfo(IStatus.ERROR, PreferencesMessages.getFormattedString("CEditorHoverConfigurationBlock.modifierIsNotValidForHover", new String[] {fHoverConfigs[i].fModifierString, label})); //$NON-NLS-1$ + else if (stateMasks.containsKey(stateMask)) + fStatus= new StatusInfo(IStatus.ERROR, PreferencesMessages.getFormattedString("CEditorHoverConfigurationBlock.duplicateModifier", new String[] {label, (String)stateMasks.get(stateMask)})); //$NON-NLS-1$ + else + stateMasks.put(stateMask, label); + } + i++; + } + + if (fStatus.isOK()) + fMainPreferencePage.updateStatus(fStatus); + else { + fMainPreferencePage.setValid(false); + 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); + Label filler= new Label(composite, SWT.LEFT ); + GridData gd= new GridData(GridData.HORIZONTAL_ALIGN_FILL); + gd.horizontalSpan= 2; + gd.heightHint= pixelConverter.convertHeightInCharsToPixels(1) / 2; + filler.setLayoutData(gd); + } + + /* + * @see DialogPage#dispose() + */ + public void dispose() { + // nothing to dispose + } + +} diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/CEditorPreferencePage.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/CEditorPreferencePage.java index 8409d4ce555..d25f825219f 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/CEditorPreferencePage.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/CEditorPreferencePage.java @@ -128,6 +128,7 @@ public class CEditorPreferencePage extends PreferencePage implements IWorkbenchP protected List fAppearanceColorList; protected ColorEditor fAppearanceForegroundColorEditor; + private CEditorHoverConfigurationBlock fCEditorHoverConfigurationBlock; private Button fShowInOverviewRulerCheckBox; private Button fShowInVerticalRulerCheckBox; @@ -731,6 +732,8 @@ public class CEditorPreferencePage extends PreferencePage implements IWorkbenchP */ protected Control createContents(Composite parent) { + fCEditorHoverConfigurationBlock= new CEditorHoverConfigurationBlock(this, fOverlayStore); + fOverlayStore.load(); fOverlayStore.start(); @@ -753,6 +756,12 @@ public class CEditorPreferencePage extends PreferencePage implements IWorkbenchP item.setImage(CPluginImages.get(CPluginImages.IMG_OBJS_TUNIT)); item.setControl(createContentAssistPage(folder)); + item= new TabItem(folder, SWT.NONE); + item.setText(PreferencesMessages.getString("CEditorPreferencePage.hoverTab.title")); //$NON-NLS-1$ + item.setImage(CPluginImages.get(CPluginImages.IMG_OBJS_TUNIT)); + item.setControl(fCEditorHoverConfigurationBlock.createControl(folder)); + + item = new TabItem(folder, SWT.NONE); item.setText(PreferencesMessages.getString("CEditorPreferencePage.Navigation")); //$NON-NLS-1$ item.setImage(CPluginImages.get(CPluginImages.IMG_OBJS_TUNIT)); @@ -847,6 +856,7 @@ public class CEditorPreferencePage extends PreferencePage implements IWorkbenchP * @see PreferencePage#performOk() */ public boolean performOk() { + fCEditorHoverConfigurationBlock.performOk(); fOverlayStore.propagate(); return true; } @@ -861,6 +871,8 @@ public class CEditorPreferencePage extends PreferencePage implements IWorkbenchP handleListSelection(); handleAppearanceColorListSelection(); + fCEditorHoverConfigurationBlock.performDefaults(); + super.performDefaults(); fPreviewViewer.invalidateTextPresentation(); @@ -1043,7 +1055,7 @@ public class CEditorPreferencePage extends PreferencePage implements IWorkbenchP return status; } - private void updateStatus(IStatus status) { + void updateStatus(IStatus status) { if (!status.matches(IStatus.ERROR)) { for (int i = 0; i < fNumberFields.size(); i++) { Text text = (Text) fNumberFields.get(i); @@ -1051,6 +1063,7 @@ public class CEditorPreferencePage extends PreferencePage implements IWorkbenchP status = StatusUtil.getMoreSevere(s, status); } } + status= StatusUtil.getMoreSevere(fCEditorHoverConfigurationBlock.getStatus(), status); setValid(!status.matches(IStatus.ERROR)); StatusUtil.applyToStatusLine(this, status); } diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/OverlayPreferenceStore.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/OverlayPreferenceStore.java index 247e1421ad4..29d9761e325 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/OverlayPreferenceStore.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/OverlayPreferenceStore.java @@ -7,6 +7,7 @@ package org.eclipse.cdt.internal.ui.preferences; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.preference.PreferenceStore; +import org.eclipse.jface.text.Assert; import org.eclipse.jface.util.IPropertyChangeListener; import org.eclipse.jface.util.PropertyChangeEvent; @@ -55,7 +56,7 @@ public class OverlayPreferenceStore implements IPreferenceStore { protected IPreferenceStore fParent; protected IPreferenceStore fStore; private OverlayKey[] fOverlayKeys; - + private boolean fLoaded; private PropertyListener fPropertyListener; @@ -186,6 +187,8 @@ public class OverlayPreferenceStore implements IPreferenceStore { public void load() { for (int i= 0; i < fOverlayKeys.length; i++) loadProperty(fParent, fOverlayKeys[i], fStore, true); + + fLoaded= true; } public void loadDefaults() { @@ -443,5 +446,34 @@ public class OverlayPreferenceStore implements IPreferenceStore { if (covers(name)) fStore.setValue(name, value); } + + /** + * The keys to add to the list of overlay keys. + *

+ * Note: This method must be called before {@link #load()} is called. + *

+ * + * @param keys + * @since 3.0 + */ + public void addKeys(OverlayKey[] keys) { + Assert.isTrue(!fLoaded); + Assert.isNotNull(keys); + + int overlayKeysLength= fOverlayKeys.length; + OverlayKey[] result= new OverlayKey[keys.length + overlayKeysLength]; + + for (int i= 0, length= overlayKeysLength; i < length; i++) + result[i]= fOverlayKeys[i]; + + for (int i= 0, length= keys.length; i < length; i++) + result[overlayKeysLength + i]= keys[i]; + + fOverlayKeys= result; + + if (fLoaded) + load(); + } + } diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/PreferencesMessages.properties b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/PreferencesMessages.properties index d41c42a7c66..bc8dc04e6ba 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/PreferencesMessages.properties +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/PreferencesMessages.properties @@ -136,3 +136,26 @@ CFileTypesPropertyPage.useProjectSettings=Use project settings CFileTypeDialog.patternLabel=Pattern: CFileTypeDialog.typeLabel=Type: + +# Hover tab +CEditorPreferencePage.hoverTab.title= Ho&vers +CEditorHoverConfigurationBlock.annotationRollover= &Enable annotation roll-over (on new editors) +CEditorHoverConfigurationBlock.hoverPreferences= Text &Hover key modifier preferences: +CEditorHoverConfigurationBlock.enabled= &Enabled +CEditorHoverConfigurationBlock.keyModifier= Pressed key &modifier while hovering: +CEditorHoverConfigurationBlock.description= Description: +CEditorHoverConfigurationBlock.modifierIsNotValid= Modifier ''{0}'' is not valid. +CEditorHoverConfigurationBlock.modifierIsNotValidForHover= Modifier ''{0}'' for ''{1}'' hover is not valid. +CEditorHoverConfigurationBlock.duplicateModifier= ''{0}'' hover uses the same modifier as ''{1}'' hover. +CEditorHoverConfigurationBlock.nameColumnTitle= Text Hover Name +CEditorHoverConfigurationBlock.modifierColumnTitle= Pressed Key Modifier While Hovering + +CEditorHoverConfigurationBlock.delimiter= + +CEditorHoverConfigurationBlock.insertDelimiterAndModifierAndDelimiter= \ + {0} + +CEditorHoverConfigurationBlock.insertModifierAndDelimiter= \ {0} + +CEditorHoverConfigurationBlock.insertDelimiterAndModifier= \ + {0} + +CEditorHoverConfigurationBlock.showAffordance= &Show affordance in hover on how to make it sticky + + + diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/CSourceViewerConfiguration.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/CSourceViewerConfiguration.java index c6d7a7b66ae..8a440fab129 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/CSourceViewerConfiguration.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/CSourceViewerConfiguration.java @@ -4,20 +4,14 @@ package org.eclipse.cdt.internal.ui.text; * All Rights Reserved. */ -import java.util.HashMap; import java.util.Vector; import org.eclipse.cdt.internal.ui.editor.CEditor; -import org.eclipse.cdt.internal.ui.editor.CEditorTextHoverDispatcher; -import org.eclipse.cdt.internal.ui.text.contentassist.*; +import org.eclipse.cdt.internal.ui.text.c.hover.CEditorTextHoverDescriptor; +import org.eclipse.cdt.internal.ui.text.c.hover.CEditorTextHoverProxy; +import org.eclipse.cdt.internal.ui.text.contentassist.CCompletionProcessor; +import org.eclipse.cdt.internal.ui.text.contentassist.ContentAssistPreference; import org.eclipse.cdt.ui.CUIPlugin; -import org.eclipse.cdt.ui.ICDTConstants; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IConfigurationElement; -import org.eclipse.core.runtime.IExtension; -import org.eclipse.core.runtime.IExtensionPoint; -import org.eclipse.core.runtime.IPluginRegistry; -import org.eclipse.core.runtime.Platform; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.text.DefaultInformationControl; import org.eclipse.jface.text.IAutoIndentStrategy; @@ -26,6 +20,7 @@ import org.eclipse.jface.text.IInformationControl; import org.eclipse.jface.text.IInformationControlCreator; import org.eclipse.jface.text.ITextDoubleClickStrategy; import org.eclipse.jface.text.ITextHover; +import org.eclipse.jface.text.ITextViewerExtension2; import org.eclipse.jface.text.contentassist.ContentAssistant; import org.eclipse.jface.text.contentassist.IContentAssistProcessor; import org.eclipse.jface.text.contentassist.IContentAssistant; @@ -302,45 +297,57 @@ public class CSourceViewerConfiguration extends SourceViewerConfiguration { } - /** + + /* + * @see SourceViewerConfiguration#getConfiguredTextHoverStateMasks(ISourceViewer, String) + * @since 2.1 + */ + public int[] getConfiguredTextHoverStateMasks(ISourceViewer sourceViewer, String contentType) { + CEditorTextHoverDescriptor[] hoverDescs= CUIPlugin.getDefault().getCEditorTextHoverDescriptors(); + int stateMasks[]= new int[hoverDescs.length]; + int stateMasksLength= 0; + for (int i= 0; i < hoverDescs.length; i++) { + if (hoverDescs[i].isEnabled()) { + int j= 0; + int stateMask= hoverDescs[i].getStateMask(); + while (j < stateMasksLength) { + if (stateMasks[j] == stateMask) + break; + j++; + } + if (j == stateMasksLength) + stateMasks[stateMasksLength++]= stateMask; + } + } + if (stateMasksLength == hoverDescs.length) + return stateMasks; + + int[] shortenedStateMasks= new int[stateMasksLength]; + System.arraycopy(stateMasks, 0, shortenedStateMasks, 0, stateMasksLength); + return shortenedStateMasks; + } + + /* + * @see SourceViewerConfiguration#getTextHover(ISourceViewer, String, int) + * @since 2.1 + */ + public ITextHover getTextHover(ISourceViewer sourceViewer, String contentType, int stateMask) { + CEditorTextHoverDescriptor[] hoverDescs= CUIPlugin.getDefault().getCEditorTextHoverDescriptors(); + int i= 0; + while (i < hoverDescs.length) { + if (hoverDescs[i].isEnabled() && hoverDescs[i].getStateMask() == stateMask) + return new CEditorTextHoverProxy(hoverDescs[i], getEditor()); + i++; + } + + return null; + } + + /* * @see SourceViewerConfiguration#getTextHover(ISourceViewer, String) */ public ITextHover getTextHover(ISourceViewer sourceViewer, String contentType) { - HashMap textHovers = new HashMap( 3 ); - IPluginRegistry pluginRegistry = Platform.getPluginRegistry(); - IExtensionPoint point = pluginRegistry.getExtensionPoint( CUIPlugin.getDefault().getDescriptor().getUniqueIdentifier(), - ICDTConstants.EP_TEXT_HOVERS ); - if ( point != null ) - { - IExtension[] extensions = point.getExtensions(); - for ( int i = 0; i < extensions.length; i++ ) - { - IExtension currentExtension = extensions[i]; - IConfigurationElement[] configElements = currentExtension.getConfigurationElements(); - for ( int j = 0; j < configElements.length; j++ ) - { - IConfigurationElement config = configElements[j]; - if ( config.getName().equals( ICDTConstants.TAG_TEXT_HOVER ) ) - { - processTextHoverElement( textHovers, config ); - } - } - } - } - - return new CEditorTextHoverDispatcher( fEditor, textHovers ); - } - - private void processTextHoverElement( HashMap textHovers, IConfigurationElement element ) { - String perspId = element.getAttribute( ICDTConstants.ATT_PERSPECTIVE ); - ITextHover textHover = null; - try { - textHover = (ITextHover)element.createExecutableExtension( ICDTConstants.ATT_CLASS ); - } catch (CoreException e) { - } - if ( perspId != null ) { - textHovers.put( perspId, textHover ); - } + return getTextHover(sourceViewer, contentType, ITextViewerExtension2.DEFAULT_HOVER_STATE_MASK); } /** diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/PreferencesAdapter.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/PreferencesAdapter.java new file mode 100644 index 00000000000..709e2b86fa1 --- /dev/null +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/PreferencesAdapter.java @@ -0,0 +1,309 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.cdt.internal.ui.text; + +import org.eclipse.core.runtime.Preferences; + +import org.eclipse.jface.preference.IPreferenceStore; +import org.eclipse.jface.util.IPropertyChangeListener; +import org.eclipse.jface.util.ListenerList; +import org.eclipse.jface.util.PropertyChangeEvent; + +/** + * Adapts {@link org.eclipse.core.runtime.Preferences} to + * {@link org.eclipse.jface.preference.IPreferenceStore} + * + * @since 3.0 + */ +public class PreferencesAdapter implements IPreferenceStore { + + /** + * Property change listener. Listens for events of type + * {@link org.eclipse.core.runtime.Preferences.PropertyChangeEvent} and fires + * a {@link org.eclipse.jface.util.PropertyChangeEvent} on the + * adapter with arguments from the received event. + */ + private class PropertyChangeListener implements Preferences.IPropertyChangeListener { + + /* + * @see org.eclipse.core.runtime.Preferences.IPropertyChangeListener#propertyChange(org.eclipse.core.runtime.Preferences.PropertyChangeEvent) + */ + public void propertyChange(Preferences.PropertyChangeEvent event) { + firePropertyChangeEvent(event.getProperty(), event.getOldValue(), event.getNewValue()); + } + } + + /** Listeners on the adapter */ + private ListenerList fListeners= new ListenerList(); + + /** Listener on the adapted Preferences */ + private PropertyChangeListener fListener= new PropertyChangeListener(); + + /** Adapted Preferences */ + private Preferences fPreferences; + + /** True iff no events should be forwarded */ + private boolean fSilent; + + /** + * Initialize with empty Preferences. + */ + public PreferencesAdapter() { + this(new Preferences()); + } + /** + * Initialize with the given Preferences. + * + * @param preferences The preferences to wrap. + */ + public PreferencesAdapter(Preferences preferences) { + fPreferences= preferences; + } + + /** + * {@inheritDoc} + */ + public void addPropertyChangeListener(IPropertyChangeListener listener) { + if (fListeners.size() == 0) + fPreferences.addPropertyChangeListener(fListener); + fListeners.add(listener); + } + + /** + * {@inheritDoc} + */ + public void removePropertyChangeListener(IPropertyChangeListener listener) { + fListeners.remove(listener); + if (fListeners.size() == 0) + fPreferences.removePropertyChangeListener(fListener); + } + + /** + * {@inheritDoc} + */ + public boolean contains(String name) { + return fPreferences.contains(name); + } + + /** + * {@inheritDoc} + */ + public void firePropertyChangeEvent(String name, Object oldValue, Object newValue) { + if (!fSilent) { + PropertyChangeEvent event= new PropertyChangeEvent(this, name, oldValue, newValue); + Object[] listeners= fListeners.getListeners(); + for (int i= 0; i < listeners.length; i++) + ((IPropertyChangeListener) listeners[i]).propertyChange(event); + } + } + + /** + * {@inheritDoc} + */ + public boolean getBoolean(String name) { + return fPreferences.getBoolean(name); + } + + /** + * {@inheritDoc} + */ + public boolean getDefaultBoolean(String name) { + return fPreferences.getDefaultBoolean(name); + } + + /** + * {@inheritDoc} + */ + public double getDefaultDouble(String name) { + return fPreferences.getDefaultDouble(name); + } + + /** + * {@inheritDoc} + */ + public float getDefaultFloat(String name) { + return fPreferences.getDefaultFloat(name); + } + + /** + * {@inheritDoc} + */ + public int getDefaultInt(String name) { + return fPreferences.getDefaultInt(name); + } + + /** + * {@inheritDoc} + */ + public long getDefaultLong(String name) { + return fPreferences.getDefaultLong(name); + } + + /** + * {@inheritDoc} + */ + public String getDefaultString(String name) { + return fPreferences.getDefaultString(name); + } + + /** + * {@inheritDoc} + */ + public double getDouble(String name) { + return fPreferences.getDouble(name); + } + + /** + * {@inheritDoc} + */ + public float getFloat(String name) { + return fPreferences.getFloat(name); + } + + /** + * {@inheritDoc} + */ + public int getInt(String name) { + return fPreferences.getInt(name); + } + + /** + * {@inheritDoc} + */ + public long getLong(String name) { + return fPreferences.getLong(name); + } + + /** + * {@inheritDoc} + */ + public String getString(String name) { + return fPreferences.getString(name); + } + + /** + * {@inheritDoc} + */ + public boolean isDefault(String name) { + return fPreferences.isDefault(name); + } + + /** + * {@inheritDoc} + */ + public boolean needsSaving() { + return fPreferences.needsSaving(); + } + + /** + * {@inheritDoc} + */ + public void putValue(String name, String value) { + try { + fSilent= true; + fPreferences.setValue(name, value); + } finally { + fSilent= false; + } + } + + /** + * {@inheritDoc} + */ + public void setDefault(String name, double value) { + fPreferences.setDefault(name, value); + } + + /** + * {@inheritDoc} + */ + public void setDefault(String name, float value) { + fPreferences.setDefault(name, value); + } + + /** + * {@inheritDoc} + */ + public void setDefault(String name, int value) { + fPreferences.setDefault(name, value); + } + + /** + * {@inheritDoc} + */ + public void setDefault(String name, long value) { + fPreferences.setDefault(name, value); + } + + /** + * {@inheritDoc} + */ + public void setDefault(String name, String defaultObject) { + fPreferences.setDefault(name, defaultObject); + } + + /** + * {@inheritDoc} + */ + public void setDefault(String name, boolean value) { + fPreferences.setDefault(name, value); + } + + /** + * {@inheritDoc} + */ + public void setToDefault(String name) { + fPreferences.setToDefault(name); + } + + /** + * {@inheritDoc} + */ + public void setValue(String name, double value) { + fPreferences.setValue(name, value); + } + + /** + * {@inheritDoc} + */ + public void setValue(String name, float value) { + fPreferences.setValue(name, value); + } + + /** + * {@inheritDoc} + */ + public void setValue(String name, int value) { + fPreferences.setValue(name, value); + } + + /** + * {@inheritDoc} + */ + public void setValue(String name, long value) { + fPreferences.setValue(name, value); + } + + /** + * {@inheritDoc} + */ + public void setValue(String name, String value) { + fPreferences.setValue(name, value); + } + + /** + * {@inheritDoc} + */ + public void setValue(String name, boolean value) { + fPreferences.setValue(name, value); + } +} 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 new file mode 100644 index 00000000000..0307175a27e --- /dev/null +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/AbstractAnnotationHover.java @@ -0,0 +1,122 @@ +/********************************************************************** + * Copyright (c) 2002,2003,2004 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + ***********************************************************************/ + +package org.eclipse.cdt.internal.ui.text.c.hover; + +import java.util.Iterator; + +import org.eclipse.cdt.internal.ui.editor.CAnnotationIterator; +import org.eclipse.cdt.internal.ui.editor.CEditor; +import org.eclipse.cdt.internal.ui.text.HTMLPrinter; +import org.eclipse.cdt.ui.CUIPlugin; +import org.eclipse.jface.preference.IPreferenceStore; +import org.eclipse.jface.text.IRegion; +import org.eclipse.jface.text.ITextViewer; +import org.eclipse.jface.text.Position; +import org.eclipse.jface.text.source.Annotation; +import org.eclipse.jface.text.source.IAnnotationModel; +import org.eclipse.ui.IEditorPart; +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; + +/** + * AbstractAnnotationHover + * Abstract super class for annotation hovers. + */ +public class AbstractAnnotationHover extends AbstractCEditorTextHover { + + private IPreferenceStore fStore= CUIPlugin.getDefault().getCombinedPreferenceStore(); + private DefaultMarkerAnnotationAccess fAnnotationAccess= new DefaultMarkerAnnotationAccess(); + private boolean fAllAnnotations; + + + 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) + */ + public String getHoverInfo(ITextViewer textViewer, IRegion hoverRegion) { + + if (getEditor() == null) + return null; + + IDocumentProvider provider= CUIPlugin.getDefault().getDocumentProvider(); + IAnnotationModel model= provider.getAnnotationModel(getEditor().getEditorInput()); + + if (model != null) { + Iterator e= new CAnnotationIterator(model, true, fAllAnnotations); + int layer= -1; + String message= null; + while (e.hasNext()) { + Annotation a= (Annotation) e.next(); + + AnnotationPreference preference= getAnnotationPreference(a); + if (preference == null || !(preference.getTextPreferenceKey() != null && fStore.getBoolean(preference.getTextPreferenceKey()) || (preference.getHighlightPreferenceKey() != null && fStore.getBoolean(preference.getHighlightPreferenceKey())))) + 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; + } + } + } + if (layer > -1) + return formatMessage(message); + } + + return null; + } + + /* + * @see IJavaEditorTextHover#setEditor(IEditorPart) + */ + public void setEditor(IEditorPart editor) { + if (editor instanceof CEditor) + super.setEditor(editor); + else + super.setEditor(null); + } + + /** + * Returns the annotation preference for the given annotation. + * + * @param annotation the annotation + * @return the annotation preference or null if none + */ + private 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/AbstractCEditorTextHover.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/AbstractCEditorTextHover.java new file mode 100644 index 00000000000..0f0b5d029eb --- /dev/null +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/AbstractCEditorTextHover.java @@ -0,0 +1,176 @@ +/********************************************************************** + * Copyright (c) 2002,2003,2004 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + ***********************************************************************/ + +package org.eclipse.cdt.internal.ui.text.c.hover; + +import java.util.List; + +import org.eclipse.cdt.core.model.ICElement; +import org.eclipse.cdt.internal.ui.text.CWordFinder; +import org.eclipse.cdt.internal.ui.text.HTMLTextPresenter; +import org.eclipse.cdt.ui.text.c.hover.ICEditorTextHover; +import org.eclipse.jface.text.DefaultInformationControl; +import org.eclipse.jface.text.IInformationControl; +import org.eclipse.jface.text.IInformationControlCreator; +import org.eclipse.jface.text.IRegion; +import org.eclipse.jface.text.ITextHoverExtension; +import org.eclipse.jface.text.ITextViewer; +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.commands.ICommand; +import org.eclipse.ui.commands.IKeySequenceBinding; +import org.eclipse.ui.keys.KeySequence; + +/** + * AbstractCEditorTextHover + * Abstract class for providing hover information for C elements. + * + */ +public class AbstractCEditorTextHover implements ICEditorTextHover, ITextHoverExtension { + + private IEditorPart fEditor; + private ICommand fCommand; +// { +// ICommandManager commandManager= PlatformUI.getWorkbench().getCommandSupport().getCommandManager(); +// fCommand= commandManager.getCommand(ICEditorActionDefinitionIds.SHOW_JAVADOC); +// if (!fCommand.isDefined()) +// fCommand= null; +// } + + /* + * @see IJavaEditorTextHover#setEditor(IEditorPart) + */ + public void setEditor(IEditorPart editor) { + fEditor= editor; + } + + protected IEditorPart getEditor() { + return fEditor; + } + + /* + * @see ITextHover#getHoverRegion(ITextViewer, int) + */ + public IRegion getHoverRegion(ITextViewer textViewer, int offset) { + return CWordFinder.findWord(textViewer.getDocument(), offset); + } + +// protected ICodeAssist getCodeAssist() { +// if (fEditor != null) { +// IEditorInput input= fEditor.getEditorInput(); +// if (input instanceof IClassFileEditorInput) { +// IClassFileEditorInput cfeInput= (IClassFileEditorInput) input; +// return cfeInput.getClassFile(); +// } +// +// IWorkingCopyManager manager= CUIPlugin.getDefault().getWorkingCopyManager(); +// return manager.getWorkingCopy(input); +// } +// +// return null; +// } + + + /* + * @see ITextHover#getHoverInfo(ITextViewer, IRegion) + */ + public String getHoverInfo(ITextViewer textViewer, IRegion hoverRegion) { + +// ICodeAssist resolve= getCodeAssist(); +// if (resolve != null) { +// try { +// ICElement[] result= null; +// +// synchronized (resolve) { +// result= resolve.codeSelect(hoverRegion.getOffset(), hoverRegion.getLength()); +// } +// +// if (result == null) +// return null; +// +// int nResults= result.length; +// if (nResults == 0) +// return null; +// +// return getHoverInfo(result); +// +// } catch (CModelException x) { +// CUIPlugin.log(x.getStatus()); +// } +// } + return null; + } + + /** + * Provides hover information for the given C elements. + * + * @param cElements the C elements for which to provide hover information + * @return the hover information string + */ + protected String getHoverInfo(ICElement[] cElements) { + return null; + } + + /* + * @see ITextHoverExtension#getHoverControlCreator() + * @since 3.0 + */ + public IInformationControlCreator getHoverControlCreator() { + return new IInformationControlCreator() { + public IInformationControl createInformationControl(Shell parent) { + return new DefaultInformationControl(parent, SWT.NONE, new HTMLTextPresenter(true), getTooltipAffordanceString()); + } + }; + } + + /** + * Returns the tool tip affordance string. + * + * @return the affordance string or null if disabled or no key binding is defined + * @since 3.0 + */ + protected String getTooltipAffordanceString() { +// if (!CUIPlugin.getDefault().getPreferenceStore().getBoolean(PreferenceConstants.EDITOR_SHOW_TEXT_HOVER_AFFORDANCE)) +// return null; +// +// KeySequence[] sequences= getKeySequences(); +// if (sequences == null) +// return null; +// +// String keySequence= sequences[0].format(); +// return CHoverMessages.getFormattedString("JavaTextHover.makeStickyHint", keySequence); //$NON-NLS-1$ + return null; + } + + /** + * Returns the array of valid key sequence bindings for the + * show tool tip description command. + * + * @return the array with the {@link KeySequence}s + * + * @since 3.0 + */ + private KeySequence[] getKeySequences() { + if (fCommand != null) { + List list= fCommand.getKeySequenceBindings(); + if (!list.isEmpty()) { + KeySequence[] keySequences= new KeySequence[list.size()]; + for (int i= 0; i < keySequences.length; i++) { + keySequences[i]= ((IKeySequenceBinding) list.get(i)).getKeySequence(); + } + return keySequences; + } + } + return null; + } + +} diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/AnnotationHover.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/AnnotationHover.java new file mode 100644 index 00000000000..9650173ffd5 --- /dev/null +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/AnnotationHover.java @@ -0,0 +1,25 @@ +/********************************************************************** + * Copyright (c) 2002,2003,2004 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + ***********************************************************************/ + +package org.eclipse.cdt.internal.ui.text.c.hover; + +/** + * AnnotationHover + * This annotation hover shows the description of the + * selected annotation. + */ +public class AnnotationHover extends AbstractAnnotationHover { + + public AnnotationHover() { + super(true); + } + +} diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/BestMatchHover.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/BestMatchHover.java new file mode 100644 index 00000000000..46a29e1ec70 --- /dev/null +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/BestMatchHover.java @@ -0,0 +1,132 @@ +/********************************************************************** + * Copyright (c) 2002,2003,2004 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + ***********************************************************************/ + +package org.eclipse.cdt.internal.ui.text.c.hover; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.eclipse.cdt.ui.CUIPlugin; +import org.eclipse.cdt.ui.PreferenceConstants; +import org.eclipse.cdt.ui.text.c.hover.ICEditorTextHover; +import org.eclipse.jface.text.IInformationControlCreator; +import org.eclipse.jface.text.IRegion; +import org.eclipse.jface.text.ITextHover; +import org.eclipse.jface.text.ITextHoverExtension; +import org.eclipse.jface.text.ITextViewer; +import org.eclipse.jface.text.information.IInformationProviderExtension2; +import org.eclipse.ui.IEditorPart; + +/** + * BestMatchHover + */ +public class BestMatchHover extends AbstractCEditorTextHover implements ITextHoverExtension, IInformationProviderExtension2 { + + private List fTextHoverSpecifications; + private List fInstantiatedTextHovers; + private ITextHover fBestHover; + + public BestMatchHover() { + installTextHovers(); + } + + public BestMatchHover(IEditorPart editor) { + this(); + setEditor(editor); + } + + /** + * Installs all text hovers. + */ + private void installTextHovers() { + + // initialize lists - indicates that the initialization happened + fTextHoverSpecifications= new ArrayList(2); + fInstantiatedTextHovers= new ArrayList(2); + + // populate list + CEditorTextHoverDescriptor[] hoverDescs= CUIPlugin.getDefault().getCEditorTextHoverDescriptors(); + for (int i= 0; i < hoverDescs.length; i++) { + // ensure that we don't add ourselves to the list + if (!PreferenceConstants.ID_BESTMATCH_HOVER.equals(hoverDescs[i].getId())) + fTextHoverSpecifications.add(hoverDescs[i]); + } + } + + private void checkTextHovers() { + if (fTextHoverSpecifications.size() == 0) + return; + + for (Iterator iterator= new ArrayList(fTextHoverSpecifications).iterator(); iterator.hasNext(); ) { + CEditorTextHoverDescriptor spec= (CEditorTextHoverDescriptor) iterator.next(); + + ICEditorTextHover hover= spec.createTextHover(); + if (hover != null) { + hover.setEditor(getEditor()); + addTextHover(hover); + fTextHoverSpecifications.remove(spec); + } + } + } + + protected void addTextHover(ITextHover hover) { + if (!fInstantiatedTextHovers.contains(hover)) + fInstantiatedTextHovers.add(hover); + } + + /* + * @see ITextHover#getHoverInfo(ITextViewer, IRegion) + */ + public String getHoverInfo(ITextViewer textViewer, IRegion hoverRegion) { + + checkTextHovers(); + fBestHover= null; + + if (fInstantiatedTextHovers == null) + return null; + + for (Iterator iterator= fInstantiatedTextHovers.iterator(); iterator.hasNext(); ) { + ITextHover hover= (ITextHover)iterator.next(); + + String s= hover.getHoverInfo(textViewer, hoverRegion); + if (s != null && s.trim().length() > 0) { + fBestHover= hover; + return s; + } + } + + return null; + } + + /* + * @see org.eclipse.jface.text.ITextHoverExtension#getHoverControlCreator() + * @since 3.0 + */ + public IInformationControlCreator getHoverControlCreator() { + if (fBestHover instanceof ITextHoverExtension) + return ((ITextHoverExtension)fBestHover).getHoverControlCreator(); + + return null; + } + + /* + * @see org.eclipse.jface.text.information.IInformationProviderExtension2#getInformationPresenterControlCreator() + * @since 3.0 + */ + public IInformationControlCreator getInformationPresenterControlCreator() { + if (fBestHover instanceof IInformationProviderExtension2) + return ((IInformationProviderExtension2)fBestHover).getInformationPresenterControlCreator(); + + return null; + } + +} diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CDocHover.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CDocHover.java new file mode 100644 index 00000000000..8e2e4a5e641 --- /dev/null +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CDocHover.java @@ -0,0 +1,84 @@ +package org.eclipse.cdt.internal.ui.text.c.hover; + +/* + * (c) Copyright QNX Software Systems Ltd. 2002. + * All Rights Reserved. + */ + +import org.eclipse.cdt.internal.ui.CCompletionContributorManager; +import org.eclipse.cdt.internal.ui.editor.CEditorMessages; +import org.eclipse.cdt.internal.ui.text.CWordFinder; +import org.eclipse.cdt.internal.ui.text.HTMLPrinter; +import org.eclipse.cdt.ui.IFunctionSummary; +import org.eclipse.jface.text.IRegion; +import org.eclipse.jface.text.ITextHover; +import org.eclipse.jface.text.ITextViewer; +import org.eclipse.jface.text.Region; +import org.eclipse.swt.graphics.Point; + +public class CDocHover extends AbstractCEditorTextHover { + + /** + * Constructor for DefaultCEditorTextHover + */ + public CDocHover() { + } + + /** + * @see ITextHover#getHoverInfo(ITextViewer, IRegion) + */ + public String getHoverInfo(ITextViewer viewer, IRegion region) { + String expression = null; + + if(getEditor() == null) + return null; + try { + expression = viewer.getDocument().get(region.getOffset(), region.getLength()); + expression = expression.trim(); + if (expression.length() == 0) + return null; + + StringBuffer buffer = new StringBuffer(); + + // We are just doing some C, call the Help to get info + + IFunctionSummary fs = CCompletionContributorManager.getDefault().getFunctionInfo(expression); + if (fs != null) { + buffer.append(CEditorMessages.getString("DefaultCEditorTextHover.html.name")); //$NON-NLS-1$ + buffer.append(HTMLPrinter.convertToHTMLContent(fs.getName())); + buffer.append(CEditorMessages.getString("DefaultCEditorTextHover.html.prototype")); //$NON-NLS-1$ + buffer.append(HTMLPrinter.convertToHTMLContent(fs.getPrototype().getPrototypeString(false))); + if(fs.getDescription() != null) { + buffer.append(CEditorMessages.getString("DefaultCEditorTextHover.html.description")); //$NON-NLS-1$ + //Don't convert this description since it could already be formatted + buffer.append(fs.getDescription()); + } + } + if (buffer.length() > 0) { + HTMLPrinter.insertPageProlog(buffer, 0); + HTMLPrinter.addPageEpilog(buffer); + return buffer.toString(); + } + } catch(Exception ex) { + /* Ignore */ + } + + return null; + } + + /** + * @see ITextHover#getHoverRegion(ITextViewer, int) + */ + public IRegion getHoverRegion(ITextViewer viewer, int offset) { + Point selectedRange = viewer.getSelectedRange(); + if (selectedRange.x >= 0 && + selectedRange.y > 0 && + offset >= selectedRange.x && + offset <= selectedRange.x + selectedRange.y) + return new Region( selectedRange.x, selectedRange.y ); + if (viewer != null) + return CWordFinder.findWord(viewer.getDocument(), offset); + return null; + } + +} diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CEditorTextHoverDescriptor.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CEditorTextHoverDescriptor.java new file mode 100644 index 00000000000..099c3172535 --- /dev/null +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CEditorTextHoverDescriptor.java @@ -0,0 +1,294 @@ +/********************************************************************** + * Copyright (c) 2002,2003,2004 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + ***********************************************************************/ + +package org.eclipse.cdt.internal.ui.text.c.hover; + +import java.text.Collator; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.StringTokenizer; + +import org.eclipse.cdt.internal.ui.util.EditorUtility; +import org.eclipse.cdt.ui.CUIPlugin; +import org.eclipse.cdt.ui.PreferenceConstants; +import org.eclipse.cdt.ui.text.c.hover.ICEditorTextHover; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IConfigurationElement; +import org.eclipse.core.runtime.IExtensionRegistry; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.Status; +import org.eclipse.jface.text.Assert; +import org.eclipse.swt.SWT; +import org.osgi.framework.Bundle; + +/** + * CEditorTexHoverDescriptor + */ +public class CEditorTextHoverDescriptor implements Comparable { + + private static final String C_EDITOR_TEXT_HOVER_EXTENSION_POINT= "org.eclipse.cdt.ui.textHovers"; //$NON-NLS-1$ + private static final String HOVER_TAG= "hover"; //$NON-NLS-1$ + private static final String ID_ATTRIBUTE= "id"; //$NON-NLS-1$ + private static final String CLASS_ATTRIBUTE= "class"; //$NON-NLS-1$ + private static final String LABEL_ATTRIBUTE= "label"; //$NON-NLS-1$ + private static final String ACTIVATE_PLUG_IN_ATTRIBUTE= "activate"; //$NON-NLS-1$ + private static final String DESCRIPTION_ATTRIBUTE= "description"; //$NON-NLS-1$ + private static final String PERSPECTIVE= "perspective"; //$NON-NLS-1$ + + public static final String NO_MODIFIER= "0"; //$NON-NLS-1$ + public static final String DISABLED_TAG= "!"; //$NON-NLS-1$ + public static final String VALUE_SEPARATOR= ";"; //$NON-NLS-1$ + + private int fStateMask; + private String fModifierString; + private boolean fIsEnabled; + + private IConfigurationElement fElement; + + + /** + * Returns all C editor text hovers contributed to the workbench. + */ + public static CEditorTextHoverDescriptor[] getContributedHovers() { + IExtensionRegistry registry= Platform.getExtensionRegistry(); + IConfigurationElement[] elements= registry.getConfigurationElementsFor(C_EDITOR_TEXT_HOVER_EXTENSION_POINT); + CEditorTextHoverDescriptor[] hoverDescs= createDescriptors(elements); + initializeFromPreferences(hoverDescs); + return hoverDescs; + } + + /** + * Computes the state mask for the given modifier string. + * + * @param modifiers the string with the modifiers, separated by '+', '-', ';', ',' or '.' + * @return the state mask or -1 if the input is invalid + */ + public static int computeStateMask(String modifiers) { + if (modifiers == null) + return -1; + + if (modifiers.length() == 0) + return SWT.NONE; + + int stateMask= 0; + StringTokenizer modifierTokenizer= new StringTokenizer(modifiers, ",;.:+-* "); //$NON-NLS-1$ + while (modifierTokenizer.hasMoreTokens()) { + int modifier= EditorUtility.findLocalizedModifier(modifierTokenizer.nextToken()); + if (modifier == 0 || (stateMask & modifier) == modifier) + return -1; + stateMask= stateMask | modifier; + } + return stateMask; + } + + /** + * Creates a new Java Editor text hover descriptor from the given configuration element. + */ + private CEditorTextHoverDescriptor(IConfigurationElement element) { + Assert.isNotNull(element); + fElement= element; + } + + /** + * Creates the Java editor text hover. + */ + public ICEditorTextHover createTextHover() { + String pluginId = fElement.getDeclaringExtension().getNamespace(); + boolean isHoversPlugInActivated= Platform.getBundle(pluginId).getState() == Bundle.ACTIVE; + if (isHoversPlugInActivated || canActivatePlugIn()) { + try { + return (ICEditorTextHover)fElement.createExecutableExtension(CLASS_ATTRIBUTE); + } catch (CoreException x) { + CUIPlugin.getDefault().log(new Status(IStatus.ERROR, CUIPlugin.getPluginId(), 0, "CEditorTextHover.createTextHover", null)); //$NON-NLS-1$ + } + } + + return null; + } + + //---- XML Attribute accessors --------------------------------------------- + + /** + * Returns the hover's id. + */ + public String getId() { + return fElement.getAttribute(ID_ATTRIBUTE); + } + + /** + * Returns the hover's class name. + */ + public String getHoverClassName() { + return fElement.getAttribute(CLASS_ATTRIBUTE); + } + + /** + * Returns the hover's label. + */ + public String getLabel() { + String label= fElement.getAttribute(LABEL_ATTRIBUTE); + if (label != null) + return label; + + // Return simple class name + label= getHoverClassName(); + int lastDot= label.lastIndexOf('.'); + if (lastDot >= 0 && lastDot < label.length() - 1) { + return label.substring(lastDot + 1); + } else { + return label; + } + } + + /** + * Returns the hover's description. + * + * @return the hover's description or null if not provided + */ + public String getDescription() { + return fElement.getAttribute(DESCRIPTION_ATTRIBUTE); + } + + public String getPerspective() { + return fElement.getAttribute(PERSPECTIVE); + } + + public boolean canActivatePlugIn() { + return Boolean.valueOf(fElement.getAttribute(ACTIVATE_PLUG_IN_ATTRIBUTE)).booleanValue(); + } + + public boolean equals(Object obj) { + if (obj == null || !obj.getClass().equals(this.getClass()) || getId() == null) + return false; + return getId().equals(((CEditorTextHoverDescriptor)obj).getId()); + } + + public int hashCode() { + return getId().hashCode(); + } + + /** + * {@inheritDoc} + */ + public int compareTo(Object o) { + return Collator.getInstance().compare(getLabel(), ((CEditorTextHoverDescriptor)o).getLabel()); + } + + private static CEditorTextHoverDescriptor[] createDescriptors(IConfigurationElement[] elements) { + List result= new ArrayList(elements.length); + for (int i= 0; i < elements.length; i++) { + IConfigurationElement element= elements[i]; + if (HOVER_TAG.equals(element.getName())) { + CEditorTextHoverDescriptor desc= new CEditorTextHoverDescriptor(element); + result.add(desc); + } + } + Collections.sort(result); + return (CEditorTextHoverDescriptor[])result.toArray(new CEditorTextHoverDescriptor[result.size()]); + } + + private static void initializeFromPreferences(CEditorTextHoverDescriptor[] hovers) { + String compiledTextHoverModifiers= CUIPlugin.getDefault().getPreferenceStore().getString(PreferenceConstants.EDITOR_TEXT_HOVER_MODIFIERS); + + StringTokenizer tokenizer= new StringTokenizer(compiledTextHoverModifiers, VALUE_SEPARATOR); + HashMap idToModifier= new HashMap(tokenizer.countTokens() / 2); + + while (tokenizer.hasMoreTokens()) { + String id= tokenizer.nextToken(); + if (tokenizer.hasMoreTokens()) + idToModifier.put(id, tokenizer.nextToken()); + } + + String compiledTextHoverModifierMasks= CUIPlugin.getDefault().getPreferenceStore().getString(PreferenceConstants.EDITOR_TEXT_HOVER_MODIFIER_MASKS); + + tokenizer= new StringTokenizer(compiledTextHoverModifierMasks, VALUE_SEPARATOR); + HashMap idToModifierMask= new HashMap(tokenizer.countTokens() / 2); + + while (tokenizer.hasMoreTokens()) { + String id= tokenizer.nextToken(); + if (tokenizer.hasMoreTokens()) + idToModifierMask.put(id, tokenizer.nextToken()); + } + + for (int i= 0; i < hovers.length; i++) { + String modifierString= (String)idToModifier.get(hovers[i].getId()); + boolean enabled= true; + if (modifierString == null) + modifierString= DISABLED_TAG; + + if (modifierString.startsWith(DISABLED_TAG)) { + enabled= false; + modifierString= modifierString.substring(1); + } + + if (modifierString.equals(NO_MODIFIER)) + modifierString= ""; //$NON-NLS-1$ + + hovers[i].fModifierString= modifierString; + hovers[i].fIsEnabled= enabled; + hovers[i].fStateMask= computeStateMask(modifierString); + if (hovers[i].fStateMask == -1) { + // Fallback: use stored modifier masks + try { + hovers[i].fStateMask= Integer.parseInt((String)idToModifierMask.get(hovers[i].getId())); + } catch (NumberFormatException ex) { + hovers[i].fStateMask= -1; + } + // Fix modifier string + int stateMask= hovers[i].fStateMask; + if (stateMask == -1) + hovers[i].fModifierString= ""; //$NON-NLS-1$ + else + hovers[i].fModifierString= EditorUtility.getModifierString(stateMask); + } + } + } + + /** + * Returns the configured modifier getStateMask for this hover. + * + * @return the hover modifier stateMask or -1 if no hover is configured + */ + public int getStateMask() { + return fStateMask; + } + + /** + * Returns the modifier String as set in the preference store. + * + * @return the modifier string + */ + public String getModifierString() { + return fModifierString; + } + + /** + * Returns whether this hover is enabled or not. + * + * @return true if enabled + */ + public boolean isEnabled() { + return fIsEnabled; + } + + /** + * Returns this hover descriptors configuration element. + * + * @return the configuration element + */ + public IConfigurationElement getConfigurationElement() { + return fElement; + } + +} diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CEditorTextHoverProxy.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CEditorTextHoverProxy.java new file mode 100644 index 00000000000..1ea5a366545 --- /dev/null +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CEditorTextHoverProxy.java @@ -0,0 +1,107 @@ +/********************************************************************** + * Copyright (c) 2002,2003,2004 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + ***********************************************************************/ + +package org.eclipse.cdt.internal.ui.text.c.hover; + +import org.eclipse.cdt.ui.text.c.hover.ICEditorTextHover; +import org.eclipse.jface.text.IInformationControlCreator; +import org.eclipse.jface.text.IRegion; +import org.eclipse.jface.text.ITextHoverExtension; +import org.eclipse.jface.text.ITextViewer; +import org.eclipse.jface.text.information.IInformationProviderExtension2; +import org.eclipse.ui.IEditorPart; + +/** + * CEditorTexHoverProxy + */ +public class CEditorTextHoverProxy extends AbstractCEditorTextHover implements ITextHoverExtension, IInformationProviderExtension2 { + + private CEditorTextHoverDescriptor fHoverDescriptor; + private ICEditorTextHover fHover; + + public CEditorTextHoverProxy(CEditorTextHoverDescriptor descriptor, IEditorPart editor) { + fHoverDescriptor= descriptor; + setEditor(editor); + } + + /* + * @see ICEditorTextHover#setEditor(IEditorPart) + */ + public void setEditor(IEditorPart editor) { + super.setEditor(editor); + + if (fHover != null) + fHover.setEditor(getEditor()); + } + + public boolean isEnabled() { + return true; + } + + /* + * @see ITextHover#getHoverRegion(ITextViewer, int) + */ + public IRegion getHoverRegion(ITextViewer textViewer, int offset) { + if (ensureHoverCreated()) + return fHover.getHoverRegion(textViewer, offset); + + return null; + } + + /* + * @see ITextHover#getHoverInfo(ITextViewer, IRegion) + */ + public String getHoverInfo(ITextViewer textViewer, IRegion hoverRegion) { + if (ensureHoverCreated()) + return fHover.getHoverInfo(textViewer, hoverRegion); + + return null; + } + + private boolean ensureHoverCreated() { + if (!isEnabled() || fHoverDescriptor == null) + return false; + return isCreated() || createHover(); + } + + private boolean isCreated() { + return fHover != null; + } + + private boolean createHover() { + fHover= fHoverDescriptor.createTextHover(); + if (fHover != null) + fHover.setEditor(getEditor()); + return isCreated(); + } + + /* + * @see org.eclipse.jface.text.ITextHoverExtension#getHoverControlCreator() + * @since 3.0 + */ + public IInformationControlCreator getHoverControlCreator() { + if (ensureHoverCreated() && (fHover instanceof ITextHoverExtension)) + return ((ITextHoverExtension)fHover).getHoverControlCreator(); + + return null; + } + + /* + * @see org.eclipse.jface.text.information.IInformationProviderExtension2#getInformationPresenterControlCreator() + */ + public IInformationControlCreator getInformationPresenterControlCreator() { + if (ensureHoverCreated() && (fHover instanceof IInformationProviderExtension2)) + return ((IInformationProviderExtension2)fHover).getInformationPresenterControlCreator(); + + return null; + } + +} 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 new file mode 100644 index 00000000000..313b71c0f62 --- /dev/null +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CHoverMessages.java @@ -0,0 +1,91 @@ +/********************************************************************** + * Copyright (c) 2002,2003,2004 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + ***********************************************************************/ + +package org.eclipse.cdt.internal.ui.text.c.hover; + +import java.text.MessageFormat; +import java.util.MissingResourceException; +import java.util.ResourceBundle; + + +/** + * CHoverMessages + */ +public class CHoverMessages { + + private static final String RESOURCE_BUNDLE= CHoverMessages.class.getName(); + + private static ResourceBundle fgResourceBundle= ResourceBundle.getBundle(RESOURCE_BUNDLE); + + private CHoverMessages() { + } + + public static String getString(String key) { + try { + return fgResourceBundle.getString(key); + } catch (MissingResourceException e) { + return "!" + key + "!";//$NON-NLS-2$ //$NON-NLS-1$ + } + } + /** + * Gets a string from the resource bundle and formats it with the argument + * + * @param key the string used to get the bundle value, must not be null + * @since 3.0 + */ + public static String getFormattedString(String key, Object arg) { + String format= null; + try { + format= fgResourceBundle.getString(key); + } catch (MissingResourceException e) { + return "!" + key + "!";//$NON-NLS-2$ //$NON-NLS-1$ + } + if (arg == null) + arg= ""; //$NON-NLS-1$ + return MessageFormat.format(format, new Object[] { arg }); + } + /** + * Gets a string from the resource bundle and formats it with the arguments + * + * @param key the string used to get the bundle value, must not be null + * @since 3.0 + */ + public static String getFormattedString(String key, Object arg1, Object arg2) { + String format= null; + try { + format= fgResourceBundle.getString(key); + } catch (MissingResourceException e) { + return "!" + key + "!";//$NON-NLS-2$ //$NON-NLS-1$ + } + if (arg1 == null) + arg1= ""; //$NON-NLS-1$ + if (arg2 == null) + arg2= ""; //$NON-NLS-1$ + return MessageFormat.format(format, new Object[] { arg1, arg2 }); + } + + /** + * Gets a string from the resource bundle and formats it with the argument + * + * @param key the string used to get the bundle value, must not be null + * @since 3.0 + */ + public static String getFormattedString(String key, boolean arg) { + String format= null; + try { + format= fgResourceBundle.getString(key); + } catch (MissingResourceException e) { + return "!" + key + "!";//$NON-NLS-2$ //$NON-NLS-1$ + } + return MessageFormat.format(format, new Object[] { new Boolean(arg) }); + } + +} 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 new file mode 100644 index 00000000000..49a021523c9 --- /dev/null +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CHoverMessages.properties @@ -0,0 +1,18 @@ +############################################################################### +# Copyright (c) 2000, 2003 IBM Corporation and others. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Common Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/cpl-v10.html +# +# Contributors: +# IBM Corporation - initial API and implementation +############################################################################### + +TypeHover.more_to_come=\ ... + +CTextHover.createTextHover= Could not create c text hover + +CTextHover.makeStickyHint= Press ''{0}'' for focus. + +NoBreakpointAnnotation.addBreakpoint= Add a breakpoint diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CSourceHover.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CSourceHover.java new file mode 100644 index 00000000000..372264cbeda --- /dev/null +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CSourceHover.java @@ -0,0 +1,130 @@ +/********************************************************************** + * Copyright (c) 2002,2003,2004 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + ***********************************************************************/ + +package org.eclipse.cdt.internal.ui.text.c.hover; + +import java.io.IOException; + +import org.eclipse.cdt.core.model.CModelException; +import org.eclipse.cdt.core.model.ICElement; +import org.eclipse.cdt.core.model.ISourceReference; +import org.eclipse.cdt.core.model.IWorkingCopy; +import org.eclipse.cdt.internal.ui.codemanipulation.StubUtility; +import org.eclipse.cdt.internal.ui.text.CCodeReader; +import org.eclipse.cdt.internal.ui.util.Strings; +import org.eclipse.cdt.ui.CUIPlugin; +import org.eclipse.cdt.ui.IWorkingCopyManager; +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.jface.text.Document; +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.IRegion; +import org.eclipse.jface.text.ITextViewer; +import org.eclipse.ui.IEditorInput; +import org.eclipse.ui.IEditorPart; + +/** + * CSourceHover + */ +public class CSourceHover extends AbstractCEditorTextHover { + + /** + * + */ + public CSourceHover() { + super(); + } + + /* + * @see ITextHover#getHoverInfo(ITextViewer, IRegion) + */ + public String getHoverInfo(ITextViewer textViewer, IRegion hoverRegion) { + IEditorPart editor = getEditor(); + if (editor != null) { + IEditorInput input= editor.getEditorInput(); + IWorkingCopyManager manager= CUIPlugin.getDefault().getWorkingCopyManager(); + IWorkingCopy copy = manager.getWorkingCopy(input); + + String expression; + try { + expression = textViewer.getDocument().get(hoverRegion.getOffset(), hoverRegion.getLength()); + expression = expression.trim(); + if (expression.length() == 0) + return null; + ICElement curr = copy.getElement(expression); + if (curr == null) { + return null; + } + String source= ((ISourceReference) curr).getSource(); + if (source == null) + return null; + + source= removeLeadingComments(source); + String delim= null; + + try { + delim= StubUtility.getLineDelimiterUsed(curr); + } catch (CModelException e) { + delim= System.getProperty("line.separator", "\n"); //$NON-NLS-1$ //$NON-NLS-2$ + } + + String[] sourceLines= Strings.convertIntoLines(source); + String firstLine= sourceLines[0]; + if (!Character.isWhitespace(firstLine.charAt(0))) + sourceLines[0]= ""; //$NON-NLS-1$ + Strings.trimIndentation(sourceLines, getTabWidth()); + + if (!Character.isWhitespace(firstLine.charAt(0))) + sourceLines[0]= firstLine; + + source = Strings.concatenate(sourceLines, delim); + return source; + + } catch (BadLocationException e) { + } catch (CModelException e) { + } + } + return null; + } + + private static int getTabWidth() { + return 4; + } + + + private String removeLeadingComments(String source) { + CCodeReader reader= new CCodeReader(); + IDocument document= new Document(source); + int i; + try { + reader.configureForwardReader(document, 0, document.getLength(), true, false); + int c= reader.read(); + while (c != -1 && (c == '\r' || c == '\n')) { + c= reader.read(); + } + i= reader.getOffset(); + reader.close(); + } catch (IOException ex) { + i= 0; + } finally { + try { + if (reader != null) + reader.close(); + } catch (IOException ex) { + CUIPlugin.getDefault().log(ex); + } + } + + if (i < 0) + return source; + return source.substring(i); + } + +} diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/util/EditorUtility.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/util/EditorUtility.java index 2c6174d9c93..ea0ce325239 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/util/EditorUtility.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/util/EditorUtility.java @@ -15,10 +15,13 @@ import org.eclipse.cdt.core.model.ITranslationUnit; import org.eclipse.cdt.core.model.IWorkingCopy; import org.eclipse.cdt.core.resources.FileStorage; import org.eclipse.cdt.internal.ui.editor.CEditor; +import org.eclipse.cdt.internal.ui.editor.CEditorMessages; import org.eclipse.cdt.ui.CUIPlugin; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IStorage; +import org.eclipse.jface.action.Action; +import org.eclipse.swt.SWT; import org.eclipse.ui.IEditorDescriptor; import org.eclipse.ui.IEditorInput; import org.eclipse.ui.IEditorPart; @@ -296,7 +299,69 @@ public class EditorUtility { public static String getEditorID(IEditorInput input, Object inputObject) { return getEditorID(input.getName()); } - + + /** + * Maps the localized modifier name to a code in the same + * manner as #findModifier. + * + * @return the SWT modifier bit, or 0 if no match was found + */ + public static int findLocalizedModifier(String token) { + if (token == null) + return 0; + + if (token.equalsIgnoreCase(Action.findModifierString(SWT.CTRL))) + return SWT.CTRL; + if (token.equalsIgnoreCase(Action.findModifierString(SWT.SHIFT))) + return SWT.SHIFT; + if (token.equalsIgnoreCase(Action.findModifierString(SWT.ALT))) + return SWT.ALT; + if (token.equalsIgnoreCase(Action.findModifierString(SWT.COMMAND))) + return SWT.COMMAND; + + return 0; + } + + /** + * Returns the modifier string for the given SWT modifier + * modifier bits. + * + * @param stateMask the SWT modifier bits + * @return the modifier string + * @since 2.1.1 + */ + public static String getModifierString(int stateMask) { + String modifierString= ""; //$NON-NLS-1$ + if ((stateMask & SWT.CTRL) == SWT.CTRL) + modifierString= appendModifierString(modifierString, SWT.CTRL); + if ((stateMask & SWT.ALT) == SWT.ALT) + modifierString= appendModifierString(modifierString, SWT.ALT); + if ((stateMask & SWT.SHIFT) == SWT.SHIFT) + modifierString= appendModifierString(modifierString, SWT.SHIFT); + if ((stateMask & SWT.COMMAND) == SWT.COMMAND) + modifierString= appendModifierString(modifierString, SWT.COMMAND); + + return modifierString; + } + + /** + * Appends to modifier string of the given SWT modifier bit + * to the given modifierString. + * + * @param modifierString the modifier string + * @param modifier an int with SWT modifier bit + * @return the concatenated modifier string + * @since 2.1.1 + */ + private static String appendModifierString(String modifierString, int modifier) { + if (modifierString == null) + modifierString= ""; //$NON-NLS-1$ + String newModifierString= Action.findModifierString(modifier); + if (modifierString.length() == 0) + return newModifierString; + return CEditorMessages.getFormattedString("EditorUtility.concatModifierStrings", new String[] {modifierString, newModifierString}); //$NON-NLS-1$ + } + public static IStorage getStorage(IBinary bin) { IStorage store = null; try { 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 262a1c74b51..03083f01514 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 @@ -44,6 +44,8 @@ import org.eclipse.cdt.internal.ui.preferences.CEditorPreferencePage; import org.eclipse.cdt.internal.ui.preferences.CPluginPreferencePage; import org.eclipse.cdt.internal.ui.preferences.WorkInProgressPreferencePage; import org.eclipse.cdt.internal.ui.text.CTextTools; +import org.eclipse.cdt.internal.ui.text.PreferencesAdapter; +import org.eclipse.cdt.internal.ui.text.c.hover.CEditorTextHoverDescriptor; import org.eclipse.cdt.internal.ui.util.ImageDescriptorRegistry; import org.eclipse.cdt.internal.ui.util.ProblemMarkerManager; import org.eclipse.cdt.internal.ui.util.Util; @@ -52,6 +54,7 @@ import org.eclipse.core.resources.IWorkspace; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IAdapterManager; +import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.core.runtime.IPluginDescriptor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Platform; @@ -72,6 +75,8 @@ import org.eclipse.ui.IWorkbenchPage; import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.editors.text.EditorsUI; import org.eclipse.ui.plugin.AbstractUIPlugin; +import org.eclipse.ui.texteditor.ChainedPreferenceStore; +import org.eclipse.ui.texteditor.ConfigurationElementSorter; import org.eclipse.ui.texteditor.MarkerAnnotationPreferences; public class CUIPlugin extends AbstractUIPlugin { @@ -97,7 +102,14 @@ public class CUIPlugin extends AbstractUIPlugin { private static CUIPlugin fgCPlugin; private static ResourceBundle fgResourceBundle; private ImageDescriptorRegistry fImageDescriptorRegistry; - + private CEditorTextHoverDescriptor[] fCEditorTextHoverDescriptors; + + /** + * The combined preference store. + * @since 3.0 + */ + private IPreferenceStore fCombinedPreferenceStore; + static String SEPARATOR = System.getProperty("file.separator"); //$NON-NLS-1$ private static final String CONTENTASSIST = CUIPlugin.PLUGIN_ID + "/debug/contentassist" ; //$NON-NLS-1$ @@ -480,13 +492,29 @@ public class CUIPlugin extends AbstractUIPlugin { if(option != null) Util.VERBOSE_CONTENTASSIST = option.equalsIgnoreCase("true") ; //$NON-NLS-1$ } } + + /** + * Returns a combined preference store, this store is read-only. + * + * @return the combined preference store + * + * @since 3.0 + */ + public IPreferenceStore getCombinedPreferenceStore() { + if (fCombinedPreferenceStore == null) { + IPreferenceStore generalTextStore= EditorsUI.getPreferenceStore(); + fCombinedPreferenceStore= new ChainedPreferenceStore(new IPreferenceStore[] { getPreferenceStore(), new PreferencesAdapter(CCorePlugin.getDefault().getPluginPreferences()), generalTextStore }); + } + return fCombinedPreferenceStore; + } + + /** * Returns an array of all editors that have an unsaved content. If the identical content is * presented in more than one editor, only one of those editor parts is part of the result. * * @return an array of all dirty editor parts. - */ - + */ public static IEditorPart[] getDirtyEditors() { Set inputs= new HashSet(); List result= new ArrayList(0); @@ -562,5 +590,87 @@ public class CUIPlugin extends AbstractUIPlugin { menu.add(new Separator(IContextMenuConstants.GROUP_PROPERTIES)); } + /** + * Returns all C editor text hovers contributed to the workbench. + * + * @return an array of CEditorTextHoverDescriptor + */ + public CEditorTextHoverDescriptor[] getCEditorTextHoverDescriptors() { + if (fCEditorTextHoverDescriptors == null) { + fCEditorTextHoverDescriptors= CEditorTextHoverDescriptor.getContributedHovers(); + ConfigurationElementSorter sorter= new ConfigurationElementSorter() { + /** + * {@inheritDoc} + */ + public IConfigurationElement getConfigurationElement(Object object) { + return ((CEditorTextHoverDescriptor)object).getConfigurationElement(); + } + }; + sorter.sort(fCEditorTextHoverDescriptors); + + // The Problem hover has to be the first and the Annotation hover has to be the last one in the CDT UI's hover list + int length= fCEditorTextHoverDescriptors.length; + int first= -1; + int last= length - 1; + int problemHoverIndex= -1; + int annotationHoverIndex= -1; + for (int i= 0; i < length; i++) { + if (!fCEditorTextHoverDescriptors[i].getId().startsWith(PLUGIN_ID)) { + if (problemHoverIndex == -1 || annotationHoverIndex == -1) + continue; + else { + last= i - 1; + break; + } + } + if (first == -1) + first= i; + + if (fCEditorTextHoverDescriptors[i].getId().equals("org.eclipse.cdt.ui.AnnotationHover")) { //$NON-NLS-1$ + annotationHoverIndex= i; + continue; + } + if (fCEditorTextHoverDescriptors[i].getId().equals("org.eclipse.cdt.ui.ProblemHover")) { //$NON-NLS-1$ + problemHoverIndex= i; + continue; + } + } + + CEditorTextHoverDescriptor hoverDescriptor= null; + + if (first > -1 && problemHoverIndex > -1 && problemHoverIndex != first) { + // move problem hover to beginning + hoverDescriptor= fCEditorTextHoverDescriptors[first]; + fCEditorTextHoverDescriptors[first]= fCEditorTextHoverDescriptors[problemHoverIndex]; + fCEditorTextHoverDescriptors[problemHoverIndex]= hoverDescriptor; + + // update annotation hover index if needed + if (annotationHoverIndex == first) + annotationHoverIndex= problemHoverIndex; + } + + if (annotationHoverIndex > -1 && annotationHoverIndex != last) { + // move annotation hover to end + hoverDescriptor= fCEditorTextHoverDescriptors[last]; + fCEditorTextHoverDescriptors[last]= fCEditorTextHoverDescriptors[annotationHoverIndex]; + fCEditorTextHoverDescriptors[annotationHoverIndex]= hoverDescriptor; + } + } + + return fCEditorTextHoverDescriptors; + } + + /** + * Resets the C editor text hovers contributed to the workbench. + *

+ * This will force a rebuild of the descriptors the next time + * a client asks for them. + *

+ * + */ + public void resetCEditorTextHoverDescriptors() { + fCEditorTextHoverDescriptors= null; + } + } diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/PreferenceConstants.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/PreferenceConstants.java index 60fd15f01dc..26a507ec7d5 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/PreferenceConstants.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/PreferenceConstants.java @@ -4,8 +4,10 @@ */ package org.eclipse.cdt.ui; +import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.RGB; +import org.eclipse.jface.action.Action; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.preference.PreferenceConverter; @@ -138,6 +140,29 @@ public class PreferenceConstants { */ public final static String EDITOR_EVALUATE_TEMPORARY_PROBLEMS= "handleTemporaryProblems"; //$NON-NLS-1$ + /** + * A named preference that defines the key for the hover modifiers. + * + */ + public static final String EDITOR_TEXT_HOVER_MODIFIERS= "hoverModifiers"; //$NON-NLS-1$ + + /** + * A named preference that defines the key for the hover modifier state masks. + * The value is only used if the value of EDITOR_TEXT_HOVER_MODIFIERS + * cannot be resolved to valid SWT modifier bits. + * + * @see #EDITOR_TEXT_HOVER_MODIFIERS + */ + public static final String EDITOR_TEXT_HOVER_MODIFIER_MASKS= "hoverModifierMasks"; //$NON-NLS-1$ + + /** + * The id of the best match hover contributed for extension point + * javaEditorTextHovers. + * + * @since 2.1 + */ + public static final String ID_BESTMATCH_HOVER= "org.eclipse.cdt.ui.BestMatchHover"; //$NON-NLS-1$ + public static final String REFACTOR_ERROR_PAGE_SEVERITY_THRESHOLD= "Refactoring.ErrorPage.severityThreshold"; //$NON-NLS-1$ public static final String REFACTOR_FATAL_SEVERITY= "4"; //$NON-NLS-1$ @@ -240,5 +265,10 @@ public class PreferenceConstants { store.setDefault(PreferenceConstants.EDITOR_CORRECTION_INDICATION, false); store.setDefault(PreferenceConstants.EDITOR_EVALUATE_TEMPORARY_PROBLEMS, false); + String mod1Name= Action.findModifierString(SWT.MOD1); // SWT.COMMAND on Mac; SWT.CONTROL elsewhere + store.setDefault(PreferenceConstants.EDITOR_TEXT_HOVER_MODIFIERS, "org.eclipse.cdt.ui.BestMatchHover;0;org.eclipse.cdt.ui.CSourceHover;" + mod1Name); //$NON-NLS-1$ + store.setDefault(PreferenceConstants.EDITOR_TEXT_HOVER_MODIFIER_MASKS, "org.eclipse.cdt.ui.BestMatchHover;0;org.eclipse.cdt.ui.CSourceHover;" + SWT.MOD1); //$NON-NLS-1$ + //store.setDefault(PreferenceConstants.EDITOR_SHOW_TEXT_HOVER_AFFORDANCE, true); + } } \ No newline at end of file diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/text/c/hover/ICEditorTextHover.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/text/c/hover/ICEditorTextHover.java new file mode 100644 index 00000000000..0600c65621f --- /dev/null +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/text/c/hover/ICEditorTextHover.java @@ -0,0 +1,35 @@ +/********************************************************************** + * Copyright (c) 2002,2003,2004 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * QNX Software Systems - Initial API and implementation + ***********************************************************************/ + +package org.eclipse.cdt.ui.text.c.hover; + +import org.eclipse.jface.text.ITextHover; +import org.eclipse.ui.IEditorPart; + +/** + * ICEditorTextHover + * Provides a hover popup which appears on top of an editor with relevant + * display information. If the text hover does not provide information no + * hover popup is shown. + *

+ * Clients may implement this interface.

+ * + */ +public interface ICEditorTextHover extends ITextHover { + + /** + * Sets the editor on which the hover is shown. + * + * @param editor the editor on which the hover popup should be shown + */ + void setEditor(IEditorPart editor); + +}