diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/AbstractCompareViewerInformationControl.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/AbstractCompareViewerInformationControl.java new file mode 100644 index 00000000000..c979761f696 --- /dev/null +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/AbstractCompareViewerInformationControl.java @@ -0,0 +1,436 @@ +/******************************************************************************* + * Copyright (c) 2007, 2008 Wind River Systems, Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Anton Leherbauer (Wind River Systems) - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.internal.ui.text; + +import org.eclipse.compare.CompareConfiguration; +import org.eclipse.compare.CompareUI; +import org.eclipse.compare.structuremergeviewer.ICompareInput; +import org.eclipse.jface.action.IMenuManager; +import org.eclipse.jface.dialogs.IDialogSettings; +import org.eclipse.jface.dialogs.PopupDialog; +import org.eclipse.jface.preference.IPreferenceStore; +import org.eclipse.jface.preference.PreferenceConverter; +import org.eclipse.jface.text.IInformationControl; +import org.eclipse.jface.text.IInformationControlExtension; +import org.eclipse.jface.text.IInformationControlExtension2; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.ViewForm; +import org.eclipse.swt.events.DisposeEvent; +import org.eclipse.swt.events.DisposeListener; +import org.eclipse.swt.events.FocusListener; +import org.eclipse.swt.events.KeyEvent; +import org.eclipse.swt.events.KeyListener; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.RGB; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Shell; + +import org.eclipse.cdt.ui.CUIPlugin; +import org.eclipse.cdt.ui.PreferenceConstants; + +/** + * Abstract class for "quick" compare views in light-weight controls. + * + * @since 5.0 + */ +public abstract class AbstractCompareViewerInformationControl extends PopupDialog implements IInformationControl, IInformationControlExtension, IInformationControlExtension2, DisposeListener { + + protected class CompareViewerControl extends ViewForm { + private CompareConfiguration fCompareConfiguration; + private Viewer fViewer; + public CompareViewerControl(Composite parent, int styles, CompareConfiguration cc) { + super(parent, styles & ~SWT.BORDER); + verticalSpacing= 0; + fCompareConfiguration= cc; + } + public CompareConfiguration getCompareConfiguration() { + return fCompareConfiguration; + } + public void setInput(ICompareInput input) { + if (fViewer == null) { + fViewer= createContentViewer(this, input, fCompareConfiguration); + applyBackgroundColor(fBackgroundColor, fViewer.getControl()); + setContent(fViewer.getControl()); + } + fViewer.setInput(input); + } + } + + private final int fStyle; + + private CompareViewerControl fCompareViewerControl; + private ICompareInput fCompareInput; + + private Color fBackgroundColor; + private boolean fIsSystemBackgroundColor; + + private int fMaxWidth; + private int fMaxHeight; + + private boolean fUseDefaultBounds; + + /** + * Creates a source viewer information control with the given shell as parent. The given + * styles are applied to the shell and the source viewer. + * + * @param parent the parent shell + * @param shellStyle the additional styles for the shell + * @param textStyle the additional styles for the source viewer + * @param takeFocus flag indicating whether to take the focus + * @param showViewMenu flag indicating whether to show the "view" menu + * @param persistBounds flag indicating whether control size and location should be persisted + */ + public AbstractCompareViewerInformationControl(Shell parent, int shellStyle, int textStyle, boolean takeFocus, boolean showViewMenu, boolean persistBounds) { + super(parent, shellStyle, takeFocus, persistBounds, showViewMenu, false, null, null); + fStyle= textStyle & ~(SWT.V_SCROLL | SWT.H_SCROLL); + // Title and status text must be set to get the title label created, so force empty values here. + if (hasHeader()) + setTitleText(""); //$NON-NLS-1$ + setInfoText(""); // //$NON-NLS-1$ + + // Create all controls + create(); + } + + private void initializeColors() { + RGB bgRGB= getHoverBackgroundColorRGB(); + if (bgRGB != null) { + fBackgroundColor= new Color(getShell().getDisplay(), bgRGB); + fIsSystemBackgroundColor= false; + } else { + fBackgroundColor= getShell().getDisplay().getSystemColor(SWT.COLOR_INFO_BACKGROUND); + fIsSystemBackgroundColor= true; + } + } + + private RGB getHoverBackgroundColorRGB() { + IPreferenceStore store= CUIPlugin.getDefault().getPreferenceStore(); + return store.getBoolean(PreferenceConstants.EDITOR_SOURCE_HOVER_BACKGROUND_COLOR_SYSTEM_DEFAULT) + ? null + : PreferenceConverter.getColor(store, PreferenceConstants.EDITOR_SOURCE_HOVER_BACKGROUND_COLOR); + } + + /* + * @see org.eclipse.jface.dialogs.PopupDialog#createContents(org.eclipse.swt.widgets.Composite) + */ + protected Control createContents(Composite parent) { + initializeColors(); + Control contents= super.createContents(parent); + applyBackgroundColor(fBackgroundColor, contents); + return contents; + } + + protected void applyBackgroundColor(Color color, Control control) { + super.applyBackgroundColor(fBackgroundColor, control); + } + + /** + * Create the main content for this information control. + * + * @param parent The parent composite + * @return The control representing the main content. + * + */ + protected Control createDialogArea(Composite parent) { + CompareConfiguration compareConfig= new CompareConfiguration(); + compareConfig.setLeftEditable(false); + compareConfig.setRightEditable(false); + fCompareViewerControl= createCompareViewerControl(parent, fStyle, compareConfig); + + final Control control= fCompareViewerControl; + control.addKeyListener(new KeyListener() { + public void keyPressed(KeyEvent e) { + if (e.character == 0x1B) // ESC + dispose(); + } + public void keyReleased(KeyEvent e) { + // do nothing + } + }); + + addDisposeListener(this); + return fCompareViewerControl; + } + + protected CompareViewerControl createCompareViewerControl(Composite parent, int style, CompareConfiguration compareConfig) { + CompareViewerControl compareViewer= new CompareViewerControl(parent, style, compareConfig); + return compareViewer; + } + + protected Viewer createContentViewer(Composite parent, ICompareInput input, CompareConfiguration cc) { + return CompareUI.findContentViewer(null, input, parent, cc); + } + + /** + * Returns the name of the dialog settings section. + *

+ * The default is to return null. + *

+ * @return the name of the dialog settings section or null if + * nothing should be persisted + */ + protected String getId() { + return null; + } + + /** + * Returns the compare viewer. + * + * @return the compare viewer. + */ + protected final CompareViewerControl getCompareViewer() { + return fCompareViewerControl; + } + + /** + * Returns the compare configuration. + * + * @return the compare configuration. + */ + protected final CompareConfiguration getCompareConfiguration() { + return fCompareViewerControl.getCompareConfiguration(); + } + + /** + * Returns true if the control has a header, false otherwise. + *

+ * The default is to return false. + *

+ * + * @return true if the control has a header + */ + protected boolean hasHeader() { + // default is to have no header + return false; + } + + /** + * {@inheritDoc} + */ + public void setInformation(String content) { + } + + /** + * {@inheritDoc} + */ + public void setInput(Object input) { + if (input instanceof ICompareInput) { + fCompareInput= (ICompareInput) input; + if (fCompareViewerControl != null) { + fCompareViewerControl.setInput(fCompareInput); + } + } else if (input instanceof String) { + // do nothing + } else { + fCompareInput= null; + if (fCompareViewerControl != null) { + fCompareViewerControl.setInput(fCompareInput); + } + } + } + + /** + * Fills the view menu. + * Clients can extend or override. + * + * @param viewMenu the menu manager that manages the menu + */ + protected void fillViewMenu(IMenuManager viewMenu) { + } + + /* + * @see org.eclipse.jface.dialogs.PopupDialog#fillDialogMenu(IMenuManager) + */ + protected void fillDialogMenu(IMenuManager dialogMenu) { + super.fillDialogMenu(dialogMenu); + fillViewMenu(dialogMenu); + } + + /** + * {@inheritDoc} + */ + public void setVisible(boolean visible) { + if (visible) { + open(); + } else { + saveDialogBounds(getShell()); + getShell().setVisible(false); + } + } + + /** + * {@inheritDoc} + */ + public final void dispose() { + if (!fIsSystemBackgroundColor) { + fBackgroundColor.dispose(); + } + close(); + } + + protected Point getInitialLocation(Point initialSize) { + if (!getPersistBounds()) { + Point size = new Point(400, 400); + Rectangle parentBounds = getParentShell().getBounds(); + int x = parentBounds.x + parentBounds.width / 2 - size.x / 2; + int y = parentBounds.y + parentBounds.height / 2 - size.y / 2; + return new Point(x, y); + } + return super.getInitialLocation(initialSize); + } + + /** + * {@inheritDoc} + * @param event can be null + *

+ * Subclasses may extend. + *

+ */ + public void widgetDisposed(DisposeEvent event) { + fCompareViewerControl= null; + } + + /** + * {@inheritDoc} + */ + public boolean hasContents() { + return fCompareViewerControl != null && fCompareInput != null; + } + + /** + * {@inheritDoc} + */ + public void setSizeConstraints(int maxWidth, int maxHeight) { + fMaxWidth= maxWidth; + fMaxHeight= maxHeight; + } + + /** + * {@inheritDoc} + */ + public Point computeSizeHint() { + // compute the preferred size + int x= SWT.DEFAULT; + int y= SWT.DEFAULT; + Point size= getShell().computeSize(x, y); + if (size.x > fMaxWidth) + x= fMaxWidth; + if (size.y > fMaxHeight) + y= fMaxHeight; + + // recompute using the constraints if the preferred size is larger than the constraints + if (x != SWT.DEFAULT || y != SWT.DEFAULT) + size= getShell().computeSize(x, y, false); + + return size; + } + + /** + * {@inheritDoc} + */ + public void setLocation(Point location) { + if (!getPersistBounds() || getDialogSettings() == null || fUseDefaultBounds) + getShell().setLocation(location); + } + + /** + * {@inheritDoc} + */ + public void setSize(int width, int height) { + if (!getPersistBounds() || getDialogSettings() == null || fUseDefaultBounds) { + getShell().setSize(width, height); + } + } + + /** + * {@inheritDoc} + */ + public void addDisposeListener(DisposeListener listener) { + getShell().addDisposeListener(listener); + } + + /** + * {@inheritDoc} + */ + public void removeDisposeListener(DisposeListener listener) { + getShell().removeDisposeListener(listener); + } + + /** + * {@inheritDoc} + */ + public void setForegroundColor(Color foreground) { + applyForegroundColor(foreground, getContents()); + } + + /** + * {@inheritDoc} + */ + public void setBackgroundColor(Color background) { + applyBackgroundColor(background, getContents()); + } + + /* + * @see org.eclipse.jface.dialogs.PopupDialog#getFocusControl() + */ + protected Control getFocusControl() { + return fCompareViewerControl; + } + + /** + * {@inheritDoc} + */ + public boolean isFocusControl() { + return fCompareViewerControl.isFocusControl(); + } + + /** + * {@inheritDoc} + */ + public void setFocus() { + getShell().forceFocus(); + fCompareViewerControl.setFocus(); + } + + /** + * {@inheritDoc} + */ + public void addFocusListener(FocusListener listener) { + getShell().addFocusListener(listener); + } + + /** + * {@inheritDoc} + */ + public void removeFocusListener(FocusListener listener) { + getShell().removeFocusListener(listener); + } + + /* + * @see org.eclipse.jface.dialogs.PopupDialog#getDialogSettings() + */ + protected IDialogSettings getDialogSettings() { + String sectionName= getId(); + if (sectionName == null) { + return null; + } + IDialogSettings settings= CUIPlugin.getDefault().getDialogSettings().getSection(sectionName); + if (settings == null) { + fUseDefaultBounds= true; + settings= CUIPlugin.getDefault().getDialogSettings().addNewSection(sectionName); + } + return settings; + } +} diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/AbstractSourceViewerInformationControl.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/AbstractSourceViewerInformationControl.java index 0ea94761a33..f33ff0e7083 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/AbstractSourceViewerInformationControl.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/AbstractSourceViewerInformationControl.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007 Wind River Systems, Inc. and others. + * Copyright (c) 2007, 2008 Wind River Systems, Inc. and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -52,9 +52,9 @@ import org.eclipse.cdt.ui.text.ICPartitions; import org.eclipse.cdt.internal.ui.editor.CSourceViewer; /** - * Abstract class for "quick" views in light-weight controls. + * Abstract class for "quick" source views in light-weight controls. * - * @since 4.0 + * @since 5.0 */ public abstract class AbstractSourceViewerInformationControl extends PopupDialog implements IInformationControl, IInformationControlExtension, IInformationControlExtension2, DisposeListener { diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CHoverMessages.properties b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CHoverMessages.properties index 9193bc9a323..65fbc30671e 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CHoverMessages.properties +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CHoverMessages.properties @@ -11,7 +11,7 @@ ############################################################################### CMacroExpansionControl_statusText=Press {0} or {1} to step through macro expansion -CMacroExpansionControl_title_expansion=Expansion \#{0) of {1} +CMacroExpansionControl_title_expansion=Expansion \#{0} of {1} CMacroExpansionControl_title_fullyExpanded=Fully Expanded CMacroExpansionControl_title_macroExpansion=Macro Expansion CMacroExpansionControl_title_original=Original diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CInformationProvider.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CInformationProvider.java index 5a65ba60179..f6005f3780d 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CInformationProvider.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CInformationProvider.java @@ -33,8 +33,9 @@ import org.eclipse.cdt.internal.ui.text.HTMLTextPresenter; /** - * Provides information for the current word under the cursor based on available hovers. + * Provides information for the current word under the cursor based on the documentation hover. * + * @see CDocHover * @since 5.0 */ public class CInformationProvider implements IInformationProvider, IInformationProviderExtension2 { @@ -91,7 +92,7 @@ public class CInformationProvider implements IInformationProvider, IInformationP fPartListener= new EditorWatcher(); IWorkbenchWindow window= fEditor.getSite().getWorkbenchWindow(); window.getPartService().addPartListener(fPartListener); - fImplementation= new BestMatchHover(); + fImplementation= new CDocHover(); fImplementation.setEditor(fEditor); } } diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CMacroCompareViewer.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CMacroCompareViewer.java new file mode 100644 index 00000000000..56c1f702712 --- /dev/null +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CMacroCompareViewer.java @@ -0,0 +1,290 @@ +/******************************************************************************* + * Copyright (c) 2008 Wind River Systems, Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Anton Leherbauer (Wind River Systems) - initial API and implementation + *******************************************************************************/ + +package org.eclipse.cdt.internal.ui.text.c.hover; + +import org.eclipse.compare.CompareConfiguration; +import org.eclipse.compare.contentmergeviewer.ITokenComparator; +import org.eclipse.compare.rangedifferencer.IRangeComparator; +import org.eclipse.jface.action.IToolBarManager; +import org.eclipse.jface.resource.JFaceResources; +import org.eclipse.jface.text.ITextPresentationListener; +import org.eclipse.jface.text.TextPresentation; +import org.eclipse.jface.text.TextViewer; +import org.eclipse.swt.custom.StyleRange; +import org.eclipse.swt.events.DisposeEvent; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.Font; +import org.eclipse.swt.graphics.RGB; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.text.edits.ReplaceEdit; + +import org.eclipse.cdt.core.dom.rewrite.MacroExpansionExplorer.IMacroExpansionStep; + +import org.eclipse.cdt.internal.ui.compare.CMergeViewer; + +/** + * A viewer for comparison of macro expansions. + * + * @since 5.0 + */ +class CMacroCompareViewer extends CMergeViewer { + + private static final RGB CHANGE_COLOR= new RGB(212,212,212); + + private class ReplaceEditsHighlighter implements ITextPresentationListener { + private boolean fBefore; + private int[] fStarts; + private int[] fLengths; + private Color fBackground; + + public ReplaceEditsHighlighter(Color background, boolean before) { + fBackground= background; + fBefore= before; + } + + public void setReplaceEdits(ReplaceEdit[] edits) { + int[] deltas= new int[edits.length]; + if (fBefore) { + for (int i= 1; i < edits.length; i++) { + ReplaceEdit edit= edits[i-1]; + deltas[i]= deltas[i-1] + (edit.getText().length() - edit.getLength()); + } + } + fStarts= new int[edits.length]; + fLengths= new int[edits.length]; + for (int i= 0; i < edits.length; i++) { + ReplaceEdit edit= edits[i]; + fStarts[i]= edit.getOffset() + deltas[i]; + fLengths[i]= fBefore ? edit.getLength() : edit.getText().length(); + } + } + + /* + * @see org.eclipse.jface.text.ITextPresentationListener#applyTextPresentation(org.eclipse.jface.text.TextPresentation) + */ + public void applyTextPresentation(TextPresentation textPresentation) { + for (int i = 0; i < fStarts.length; i++) { + textPresentation.mergeStyleRange(new StyleRange(fStarts[i], fLengths[i], null, fBackground)); + } + } + + } + +// private class MacroExpansionComparator implements ITokenComparator { +// +// private final int[] fStarts; +// private final int[] fLengths; +// private int fCount; +// +// public MacroExpansionComparator(String text, ReplaceEdit[] edits, boolean before) { +// int[] deltas= new int[edits.length]; +// if (before) { +// for (int i= 1; i < edits.length; i++) { +// ReplaceEdit edit= edits[i-1]; +// deltas[i]= deltas[i-1] + (edit.getText().length() - edit.getLength()); +// } +// } +// fStarts= new int[edits.length * 2 + 1]; +// fLengths= new int[edits.length * 2 + 1]; +// int offset= 0; +// int i= 0; +// for (; i < edits.length; i++) { +// if (offset >= text.length()) { +// break; +// } +// fStarts[2*i]= offset; +// ReplaceEdit edit= edits[i]; +// fLengths[2*i]= edit.getOffset() + deltas[i] - offset; +// fStarts[2*i+1]= edit.getOffset() + deltas[i]; +// fLengths[2*i+1]= before ? edit.getLength() : edit.getText().length(); +// offset= fStarts[2*i+1] + fLengths[2*i+1]; +// } +// fCount= 2*i; +// +// if (offset < text.length()) { +// fStarts[fCount]= offset; +// fLengths[fCount]= text.length() - offset; +// fCount++; +// } +// } +// +// /* +// * @see org.eclipse.compare.contentmergeviewer.ITokenComparator#getTokenLength(int) +// */ +// public int getTokenLength(int index) { +// return fLengths[index]; +// } +// +// /* +// * @see org.eclipse.compare.contentmergeviewer.ITokenComparator#getTokenStart(int) +// */ +// public int getTokenStart(int index) { +// return fStarts[index]; +// } +// +// /* +// * @see org.eclipse.compare.rangedifferencer.IRangeComparator#getRangeCount() +// */ +// public int getRangeCount() { +// return fCount; +// } +// +// /* +// * @see org.eclipse.compare.rangedifferencer.IRangeComparator#rangesEqual(int, org.eclipse.compare.rangedifferencer.IRangeComparator, int) +// */ +// public boolean rangesEqual(int thisIndex, IRangeComparator other, int otherIndex) { +// return thisIndex == otherIndex && thisIndex % 2 == 0; +// } +// +// /* +// * @see org.eclipse.compare.rangedifferencer.IRangeComparator#skipRangeComparison(int, int, org.eclipse.compare.rangedifferencer.IRangeComparator) +// */ +// public boolean skipRangeComparison(int length, int maxLength, IRangeComparator other) { +// return false; +// } +// +// } + + /** + * A dummy {@link ITokenComparator}. + */ + private static class NullTokenComparator implements ITokenComparator { + public int getTokenLength(int index) { + return 0; + } + public int getTokenStart(int index) { + return 0; + } + public int getRangeCount() { + return 0; + } + public boolean rangesEqual(int thisIndex, IRangeComparator other, int otherIndex) { + return true; + } + public boolean skipRangeComparison(int length, int maxLength, IRangeComparator other) { + return true; + } + } + + TextViewer fLeftViewer; + TextViewer fRightViewer; + TextViewer fTopViewer; + + int fIndex; + private CMacroExpansionInput fInput; + private int fStepIndex; + private ReplaceEditsHighlighter fLeftHighlighter; + private ReplaceEditsHighlighter fRightHighlighter; + private Color fChangeBackground; + + public CMacroCompareViewer(Composite parent, int styles, CompareConfiguration mp) { + super(parent, styles, mp); + Font font= JFaceResources.getFont(CMergeViewer.class.getName()); + fLeftViewer.getTextWidget().setFont(font); + fRightViewer.getTextWidget().setFont(font); + fTopViewer.getTextWidget().setFont(font); + + fChangeBackground= new Color(parent.getDisplay(), CHANGE_COLOR); + fLeftViewer.addTextPresentationListener(fLeftHighlighter= new ReplaceEditsHighlighter(fChangeBackground, true)); + fRightViewer.addTextPresentationListener(fRightHighlighter= new ReplaceEditsHighlighter(fChangeBackground, false)); + fIndex= 0; + } + + /* + * @see org.eclipse.cdt.internal.ui.compare.AbstractMergeViewer#handleDispose(org.eclipse.swt.events.DisposeEvent) + */ + protected void handleDispose(DisposeEvent event) { + fLeftViewer.removeTextPresentationListener(fLeftHighlighter); + fRightViewer.removeTextPresentationListener(fRightHighlighter); + fChangeBackground.dispose(); + super.handleDispose(event); + } + + protected IToolBarManager getToolBarManager(Composite parent) { + // no toolbar + return null; + } + + /* + * @see org.eclipse.cdt.internal.ui.compare.AbstractMergeViewer#configureTextViewer(org.eclipse.jface.text.TextViewer) + */ + protected void configureTextViewer(TextViewer textViewer) { + super.configureTextViewer(textViewer); + + // hack: gain access to text viewers + switch (fIndex++) { + case 0: + fTopViewer= textViewer; + break; + case 1: + fLeftViewer= textViewer; + break; + case 2: + fRightViewer= textViewer; + } + } + + /* + * @see org.eclipse.compare.contentmergeviewer.TextMergeViewer#createTokenComparator(java.lang.String) + */ + protected ITokenComparator createTokenComparator(String line) { +// boolean before= fIndex++ % 2 != 0; +// final IMacroExpansionStep step; +// if (fStepIndex < fInput.fExplorer.getExpansionStepCount()) { +// step= fInput.fExplorer.getExpansionStep(fStepIndex); +// } else { +// before= !before; +// step= fInput.fExplorer.getFullExpansion(); +// } +// return new MacroExpansionComparator(line, step.getReplacements(), before); + return new NullTokenComparator(); + } + + public void setMacroExpansionInput(CMacroExpansionInput input) { + fInput= input; + } + + /* + * @see org.eclipse.jface.viewers.ContentViewer#setInput(java.lang.Object) + */ + public void setInput(Object input) { + fLeftViewer.setRedraw(false); + fRightViewer.setRedraw(false); + + final ReplaceEdit[] edits; + try { + if (fStepIndex < fInput.fExplorer.getExpansionStepCount()) { + final IMacroExpansionStep step; + step= fInput.fExplorer.getExpansionStep(fStepIndex); + edits= step.getReplacements(); + } else { + edits= new ReplaceEdit[0]; + } + fLeftHighlighter.setReplaceEdits(edits); + fRightHighlighter.setReplaceEdits(edits); + + super.setInput(input); + } finally { + fLeftViewer.setRedraw(true); + fRightViewer.setRedraw(true); + } + if (edits.length > 0) { + fLeftViewer.revealRange(edits[0].getOffset(), edits[0].getLength()); + fRightViewer.revealRange(edits[0].getOffset(), edits[0].getText().length()); + } + } + + public void setMacroExpansionStep(int index) { + fStepIndex= index; + } + +} diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CMacroExpansionControl.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CMacroExpansionControl.java index 4dd5d06bb6d..178a17d1b07 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CMacroExpansionControl.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CMacroExpansionControl.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007 Wind River Systems, Inc. and others. + * Copyright (c) 2007, 2008 Wind River Systems, Inc. and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -11,26 +11,8 @@ package org.eclipse.cdt.internal.ui.text.c.hover; -import java.util.ArrayList; -import java.util.Collection; - -import org.eclipse.core.commands.AbstractHandler; -import org.eclipse.core.commands.ExecutionEvent; -import org.eclipse.core.commands.ExecutionException; -import org.eclipse.core.commands.IHandler; -import org.eclipse.jface.text.Document; -import org.eclipse.jface.text.IDocument; -import org.eclipse.osgi.util.NLS; import org.eclipse.swt.SWT; import org.eclipse.swt.widgets.Shell; -import org.eclipse.ui.IWorkbench; -import org.eclipse.ui.PlatformUI; -import org.eclipse.ui.contexts.IContextActivation; -import org.eclipse.ui.contexts.IContextService; -import org.eclipse.ui.handlers.IHandlerService; -import org.eclipse.ui.keys.IBindingService; - -import org.eclipse.cdt.ui.CUIPlugin; import org.eclipse.cdt.internal.ui.text.AbstractSourceViewerInformationControl; @@ -41,30 +23,6 @@ import org.eclipse.cdt.internal.ui.text.AbstractSourceViewerInformationControl; */ public class CMacroExpansionControl extends AbstractSourceViewerInformationControl { - private static final String COMMAND_ID_EXPANSION_BACK= "org.eclipse.cdt.ui.hover.backwardMacroExpansion"; //$NON-NLS-1$ - private static final String COMMAND_ID_EXPANSION_FORWARD= "org.eclipse.cdt.ui.hover.forwardMacroExpansion"; //$NON-NLS-1$ - private static final String CONTEXT_ID_MACRO_EXPANSION_HOVER= "org.eclipse.cdt.ui.macroExpansionHoverScope"; //$NON-NLS-1$ - - private IHandlerService fHandlerService; - private Collection fHandlerActivations; - private IContextService fContextService; - private IContextActivation fContextActivation; - private int fIndex; - private CMacroExpansionInput fInput; - - /** - * Creates a new control for use as a "quick view" where the control immediately takes the focus. - * - * @param parent parent shell - * @param shellStyle shell style bits - * @param style text viewer style bits - * @param input the input object, may be null - */ - public CMacroExpansionControl(Shell parent, int shellStyle, int style, CMacroExpansionInput input) { - super(parent, shellStyle, style, true, false, true); - setMacroExpansionInput(input); - } - /** * Creates a new control for use as a hover which does not take the focus. * @@ -86,93 +44,6 @@ public class CMacroExpansionControl extends AbstractSourceViewerInformationContr return true; } - /* - * @see org.eclipse.jface.dialogs.PopupDialog#open() - */ - public int open() { - int result= super.open(); - - if (fInput != null) { - IHandler fBackwardHandler= new AbstractHandler() { - public Object execute(ExecutionEvent event) throws ExecutionException { - backward(); - return null; - } - }; - IHandler fForwardHandler= new AbstractHandler() { - public Object execute(ExecutionEvent event) throws ExecutionException { - forward(); - return null; - } - }; - - IWorkbench workbench= PlatformUI.getWorkbench(); - fHandlerService= (IHandlerService) workbench.getService(IHandlerService.class); - fContextService= (IContextService) workbench.getService(IContextService.class); - fContextActivation= fContextService.activateContext(CONTEXT_ID_MACRO_EXPANSION_HOVER); - fHandlerActivations= new ArrayList(); - fHandlerActivations.add(fHandlerService.activateHandler(COMMAND_ID_EXPANSION_BACK, fBackwardHandler)); - fHandlerActivations.add(fHandlerService.activateHandler(COMMAND_ID_EXPANSION_FORWARD, fForwardHandler)); - - String infoText= getInfoText(); - if (infoText != null) { - setInfoText(infoText); - } - } - - return result; - } - - protected void forward() { - ++fIndex; - if (fIndex >= fInput.fExpansions.length) { - fIndex= 0; - } - showExpansion(fIndex); - } - - protected void backward() { - --fIndex; - if (fIndex < 0) { - fIndex += fInput.fExpansions.length; - } - showExpansion(fIndex); - } - - /** - * Returns the text to be shown in the popups's information area. - * May return null. - * - * @return The text to be shown in the popup's information area or null - */ - protected String getInfoText() { - IWorkbench workbench= PlatformUI.getWorkbench(); - IBindingService bindingService= (IBindingService) workbench.getService(IBindingService.class); - String formattedBindingBack= bindingService.getBestActiveBindingFormattedFor(COMMAND_ID_EXPANSION_BACK); - String formattedBindingForward= bindingService.getBestActiveBindingFormattedFor(COMMAND_ID_EXPANSION_FORWARD); - - String infoText= null; - if (formattedBindingBack != null && formattedBindingForward != null) { - infoText= NLS.bind(CHoverMessages.CMacroExpansionControl_statusText, formattedBindingBack, formattedBindingForward); - } - return infoText; - } - - /* - * @see org.eclipse.jface.dialogs.PopupDialog#close() - */ - public boolean close() { - if (fHandlerService != null) { - fHandlerService.deactivateHandlers(fHandlerActivations); - fHandlerActivations.clear(); - fHandlerService= null; - } - if (fContextActivation != null) { - fContextService.deactivateContext(fContextActivation); - } - return super.close(); - } - /* * @see org.eclipse.cdt.internal.ui.text.AbstractSourceViewerInformationControl#getId() */ @@ -180,45 +51,4 @@ public class CMacroExpansionControl extends AbstractSourceViewerInformationContr return "org.eclipse.cdt.ui.text.hover.CMacroExpansion"; //$NON-NLS-1$ } - /* - * @see org.eclipse.cdt.internal.ui.text.AbstractSourceViewerInformationControl#setInput(java.lang.Object) - */ - public void setInput(Object input) { - if (input instanceof String && fInput == null) { - super.setInput(input); - return; - } - if (input instanceof CMacroExpansionInput) { - setMacroExpansionInput((CMacroExpansionInput) input); - } - } - - /** - * Set the input for this information control. - * @param input - */ - private void setMacroExpansionInput(CMacroExpansionInput input) { - fInput= input; - fIndex= input.fExpansions.length - 1; - showExpansion(fIndex); - } - - private void showExpansion(int index) { - if (fIndex == 0) { - setTitleText(CHoverMessages.CMacroExpansionControl_title_original); - } else if (fIndex < fInput.fExpansions.length - 1) { - setTitleText(NLS.bind(CHoverMessages.CMacroExpansionControl_title_expansion, - String.valueOf(fIndex), String.valueOf(fInput.fExpansions.length - 1))); - } else { - setTitleText(CHoverMessages.CMacroExpansionControl_title_fullyExpanded); - } - IDocument document= getSourceViewer().getDocument(); - if (document == null) { - document= new Document(fInput.fExpansions[index]); - CUIPlugin.getDefault().getTextTools().setupCDocument(document); - getSourceViewer().setDocument(document); - } else { - document.set(fInput.fExpansions[index]); - } - } } diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CMacroExpansionExplorationControl.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CMacroExpansionExplorationControl.java new file mode 100644 index 00000000000..a667da59b82 --- /dev/null +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CMacroExpansionExplorationControl.java @@ -0,0 +1,360 @@ +/******************************************************************************* + * Copyright (c) 2007, 2008 Wind River Systems, Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Anton Leherbauer (Wind River Systems) - initial API and implementation + *******************************************************************************/ + +package org.eclipse.cdt.internal.ui.text.c.hover; + +import java.util.ArrayList; +import java.util.Collection; + +import org.eclipse.compare.CompareConfiguration; +import org.eclipse.compare.ITypedElement; +import org.eclipse.compare.Splitter; +import org.eclipse.compare.structuremergeviewer.Differencer; +import org.eclipse.compare.structuremergeviewer.DocumentRangeNode; +import org.eclipse.compare.structuremergeviewer.ICompareInput; +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.core.commands.IHandler; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.jface.preference.IPreferenceStore; +import org.eclipse.jface.resource.JFaceResources; +import org.eclipse.jface.text.Document; +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.source.ISourceViewer; +import org.eclipse.jface.text.source.SourceViewer; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.osgi.util.NLS; +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.StyledText; +import org.eclipse.swt.graphics.Font; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.ui.IWorkbench; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.contexts.IContextActivation; +import org.eclipse.ui.contexts.IContextService; +import org.eclipse.ui.handlers.IHandlerService; +import org.eclipse.ui.keys.IBindingService; + +import org.eclipse.cdt.core.dom.ast.IMacroBinding; +import org.eclipse.cdt.ui.CUIPlugin; +import org.eclipse.cdt.ui.PreferenceConstants; +import org.eclipse.cdt.ui.text.ICPartitions; + +import org.eclipse.cdt.internal.ui.editor.CSourceViewer; +import org.eclipse.cdt.internal.ui.text.AbstractCompareViewerInformationControl; +import org.eclipse.cdt.internal.ui.text.CTextTools; +import org.eclipse.cdt.internal.ui.text.SimpleCSourceViewerConfiguration; + +/** + * Information control for macro expansion exploration. + * + * @since 5.0 + */ +public class CMacroExpansionExplorationControl extends AbstractCompareViewerInformationControl { + + private static final String COMMAND_ID_EXPANSION_BACK= "org.eclipse.cdt.ui.hover.backwardMacroExpansion"; //$NON-NLS-1$ + private static final String COMMAND_ID_EXPANSION_FORWARD= "org.eclipse.cdt.ui.hover.forwardMacroExpansion"; //$NON-NLS-1$ + private static final String CONTEXT_ID_MACRO_EXPANSION_HOVER= "org.eclipse.cdt.ui.macroExpansionHoverScope"; //$NON-NLS-1$ + + private static class CDiffNode extends DocumentRangeNode implements ITypedElement { + public CDiffNode(DocumentRangeNode parent, int type, String id, IDocument doc, int start, int length) { + super(parent, type, id, doc, start, length); + } + public CDiffNode(int type, String id, IDocument doc, int start, int length) { + super(type, id, doc, start, length); + } + public String getName() { + return getId(); + } + public String getType() { + return "c2"; //$NON-NLS-1$ + } + public Image getImage() { + return null; + } + } + + private IHandlerService fHandlerService; + private Collection fHandlerActivations; + private IContextService fContextService; + private IContextActivation fContextActivation; + private int fIndex; + private CMacroExpansionInput fInput; + private CMacroCompareViewer fMacroCompareViewer; + private ISourceViewer fMacroViewer; + + /** + * Creates a new control for use as a "quick view" where the control immediately takes the focus. + * + * @param parent parent shell + * @param shellStyle shell style bits + * @param style text viewer style bits + * @param input the input object, may be null + */ + public CMacroExpansionExplorationControl(Shell parent, int shellStyle, int style, CMacroExpansionInput input) { + super(parent, shellStyle, style, true, true, true); + setMacroExpansionInput(input); + } + + /* + * @see org.eclipse.cdt.internal.ui.text.AbstractSourceViewerInformationControl#hasHeader() + */ + protected boolean hasHeader() { + return true; + } + + /* + * @see org.eclipse.cdt.internal.ui.text.AbstractCompareViewerInformationControl#createCompareViewerControl(org.eclipse.swt.widgets.Composite, int, org.eclipse.compare.CompareConfiguration) + */ + protected CompareViewerControl createCompareViewerControl(Composite parent, int style, CompareConfiguration compareConfig) { + Splitter splitter= new Splitter(parent, SWT.VERTICAL); + splitter.setLayoutData(new GridData(GridData.FILL_BOTH)); + fMacroViewer= createSourceViewer(splitter, style | SWT.V_SCROLL | SWT.H_SCROLL); + CompareViewerControl control= super.createCompareViewerControl(splitter, style, compareConfig); + splitter.setWeights(new int[] { 30, 70 }); + return control; + } + + /* + * @see org.eclipse.cdt.internal.ui.text.AbstractCompareViewerInformationControl#createContentViewer(org.eclipse.swt.widgets.Composite, org.eclipse.compare.structuremergeviewer.ICompareInput, org.eclipse.compare.CompareConfiguration) + */ + protected Viewer createContentViewer(Composite parent, ICompareInput input, CompareConfiguration cc) { + fMacroCompareViewer= new CMacroCompareViewer(parent, SWT.NULL, cc); + if (fInput != null) { + fMacroCompareViewer.setMacroExpansionInput(fInput); + fMacroCompareViewer.setMacroExpansionStep(fIndex); + } + return fMacroCompareViewer; + } + + protected ISourceViewer createSourceViewer(Composite parent, int style) { + IPreferenceStore store= CUIPlugin.getDefault().getCombinedPreferenceStore(); + SourceViewer sourceViewer= new CSourceViewer(parent, null, null, false, style, store); + CTextTools tools= CUIPlugin.getDefault().getTextTools(); + sourceViewer.configure(new SimpleCSourceViewerConfiguration(tools.getColorManager(), store, null, ICPartitions.C_PARTITIONING, false)); + sourceViewer.setEditable(false); + + StyledText styledText= sourceViewer.getTextWidget(); + + Font font= JFaceResources.getFont(PreferenceConstants.EDITOR_TEXT_FONT); + styledText.setFont(font); + + GridData gd= new GridData(GridData.BEGINNING | GridData.FILL_BOTH); + gd.heightHint= styledText.getLineHeight() * 2; + styledText.setLayoutData(gd); + styledText.setForeground(parent.getDisplay().getSystemColor(SWT.COLOR_INFO_FOREGROUND)); + + final Document doc= new Document(); + CUIPlugin.getDefault().getTextTools().setupCDocument(doc); + sourceViewer.setDocument(doc); + return sourceViewer; + } + + /* + * @see org.eclipse.jface.dialogs.PopupDialog#open() + */ + public int open() { + int result= super.open(); + + if (fInput != null) { + IHandler fBackwardHandler= new AbstractHandler() { + public Object execute(ExecutionEvent event) throws ExecutionException { + backward(); + return null; + } + }; + IHandler fForwardHandler= new AbstractHandler() { + public Object execute(ExecutionEvent event) throws ExecutionException { + forward(); + return null; + } + }; + + IWorkbench workbench= PlatformUI.getWorkbench(); + fHandlerService= (IHandlerService) workbench.getService(IHandlerService.class); + fContextService= (IContextService) workbench.getService(IContextService.class); + fContextActivation= fContextService.activateContext(CONTEXT_ID_MACRO_EXPANSION_HOVER); + fHandlerActivations= new ArrayList(); + fHandlerActivations.add(fHandlerService.activateHandler(COMMAND_ID_EXPANSION_BACK, fBackwardHandler)); + fHandlerActivations.add(fHandlerService.activateHandler(COMMAND_ID_EXPANSION_FORWARD, fForwardHandler)); + + String infoText= getInfoText(); + if (infoText != null) { + setInfoText(infoText); + } + } + + return result; + } + + protected void forward() { + ++fIndex; + if (fIndex > fInput.fExplorer.getExpansionStepCount()) { + fIndex= 0; + } + showExpansion(); + } + + protected void backward() { + --fIndex; + if (fIndex < 0) { + fIndex = fInput.fExplorer.getExpansionStepCount(); + } + showExpansion(); + } + + /** + * Returns the text to be shown in the popups's information area. + * May return null. + * + * @return The text to be shown in the popup's information area or null + */ + private String getInfoText() { + IWorkbench workbench= PlatformUI.getWorkbench(); + IBindingService bindingService= (IBindingService) workbench.getService(IBindingService.class); + String formattedBindingBack= bindingService.getBestActiveBindingFormattedFor(COMMAND_ID_EXPANSION_BACK); + String formattedBindingForward= bindingService.getBestActiveBindingFormattedFor(COMMAND_ID_EXPANSION_FORWARD); + + String infoText= null; + if (formattedBindingBack != null && formattedBindingForward != null) { + infoText= NLS.bind(CHoverMessages.CMacroExpansionControl_statusText, formattedBindingBack, formattedBindingForward); + } + return infoText; + } + + /* + * @see org.eclipse.jface.dialogs.PopupDialog#close() + */ + public boolean close() { + if (fHandlerService != null) { + fHandlerService.deactivateHandlers(fHandlerActivations); + fHandlerActivations.clear(); + fHandlerService= null; + } + if (fContextActivation != null) { + fContextService.deactivateContext(fContextActivation); + } + return super.close(); + } + + /* + * @see org.eclipse.cdt.internal.ui.text.AbstractCompareViewerInformationControl#getId() + */ + protected String getId() { + return "org.eclipse.cdt.ui.text.hover.CMacroExpansionExploration"; //$NON-NLS-1$ + } + + /* + * @see org.eclipse.cdt.internal.ui.text.AbstractCompareViewerInformationControl#setInput(java.lang.Object) + */ + public void setInput(Object input) { + if (input instanceof CMacroExpansionInput) { + setMacroExpansionInput((CMacroExpansionInput) input); + } else { + if (fMacroCompareViewer != null) { + fMacroCompareViewer.setMacroExpansionStep(fIndex); + } + super.setInput(input); + } + } + + /** + * Set the input for this information control. + * @param input + */ + private void setMacroExpansionInput(CMacroExpansionInput input) { + fInput= input; + fIndex= 0; + if (fMacroCompareViewer != null) { + fMacroCompareViewer.setMacroExpansionInput(fInput); + } + showExpansion(); + } + + private void showExpansion() { + final int idxLeft= fIndex; + final int idxRight= (fIndex + 1) % (fInput.fExplorer.getExpansionStepCount() + 1); + + CompareConfiguration config= getCompareConfiguration(); + config.setAncestorLabel(getLabelForIndex(0)); + config.setLeftLabel(getLabelForIndex(idxLeft)); + config.setRightLabel(getLabelForIndex(idxRight)); + + final ITypedElement original= getContentForIndex(0); + final ITypedElement left= getContentForIndex(idxLeft); + final ITypedElement right= getContentForIndex(idxRight); + + setTitleText(CHoverMessages.CMacroExpansionControl_title_macroExpansion); + fMacroViewer.getDocument().set(getMacroText(fIndex)); + setInput(createCompareInput(original, left, right)); + } + + private String getLabelForIndex(int index) { + if (index == 0) { + return CHoverMessages.CMacroExpansionControl_title_original; + } else if (index < fInput.fExplorer.getExpansionStepCount()) { + return NLS.bind(CHoverMessages.CMacroExpansionControl_title_expansion, + String.valueOf(index), String.valueOf(fInput.fExplorer.getExpansionStepCount())); + } else { + return CHoverMessages.CMacroExpansionControl_title_fullyExpanded; + } + } + private Object createCompareInput(ITypedElement original, ITypedElement left, ITypedElement right) { + Differencer d= new Differencer(); + return d.findDifferences(false, new NullProgressMonitor(), null, original, left, right); + } + + private ITypedElement getContentForIndex(int index) { + final String text; + if (index < fInput.fExplorer.getExpansionStepCount()) { + text= fInput.fExplorer.getExpansionStep(index).getCodeBeforeStep(); + } else { + text= fInput.fExplorer.getFullExpansion().getCodeAfterStep(); + } + final Document doc= new Document(text); + CUIPlugin.getDefault().getTextTools().setupCDocument(doc); + return new CDiffNode(0, String.valueOf(index), doc, 0, text.length()); + } + + private String getMacroText(int index) { + final String text; + if (index < fInput.fExplorer.getExpansionStepCount()) { + IMacroBinding binding= fInput.fExplorer.getExpansionStep(index).getExpandedMacro(); + StringBuffer buffer= new StringBuffer(); + buffer.append("#define ").append(binding.getName()); //$NON-NLS-1$ + char[][] params= binding.getParameterList(); + if (params != null) { + buffer.append('('); + for (int i= 0; i < params.length; i++) { + if (i > 0) { + buffer.append(','); + buffer.append(' '); + } + char[] param= params[i]; + buffer.append(new String(param)); + } + buffer.append(')'); + } + buffer.append(' '); + buffer.append(binding.getExpansionImage()); + text= buffer.toString(); + } else { + text= ""; //$NON-NLS-1$ + } + return text; + } + + +} diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CMacroExpansionHover.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CMacroExpansionHover.java index 5e46a99574d..a1e52cfab38 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CMacroExpansionHover.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CMacroExpansionHover.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007 Wind River Systems, Inc. and others. + * Copyright (c) 2007, 2008 Wind River Systems, Inc. and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -11,33 +11,31 @@ package org.eclipse.cdt.internal.ui.text.c.hover; -import java.lang.ref.WeakReference; +import java.lang.ref.Reference; +import java.lang.ref.SoftReference; import java.util.ArrayList; import java.util.Collection; -import java.util.HashMap; import java.util.Iterator; import java.util.List; -import java.util.Map; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.Status; import org.eclipse.jface.text.BadLocationException; -import org.eclipse.jface.text.Document; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IInformationControl; import org.eclipse.jface.text.IInformationControlCreator; import org.eclipse.jface.text.IRegion; +import org.eclipse.jface.text.ITextSelection; import org.eclipse.jface.text.ITextViewer; import org.eclipse.jface.text.Position; import org.eclipse.jface.text.Region; -import org.eclipse.jface.text.TextUtilities; import org.eclipse.jface.text.information.IInformationProviderExtension2; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.ISelectionProvider; import org.eclipse.swt.SWT; import org.eclipse.swt.widgets.Shell; -import org.eclipse.text.edits.MalformedTreeException; -import org.eclipse.text.edits.TextEdit; import org.eclipse.ui.IEditorInput; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.texteditor.ITextEditor; @@ -46,40 +44,22 @@ import org.eclipse.cdt.core.dom.ast.ASTVisitor; import org.eclipse.cdt.core.dom.ast.IASTDeclaration; import org.eclipse.cdt.core.dom.ast.IASTExpression; import org.eclipse.cdt.core.dom.ast.IASTFileLocation; -import org.eclipse.cdt.core.dom.ast.IASTFunctionStyleMacroParameter; import org.eclipse.cdt.core.dom.ast.IASTMacroExpansion; import org.eclipse.cdt.core.dom.ast.IASTName; import org.eclipse.cdt.core.dom.ast.IASTNode; import org.eclipse.cdt.core.dom.ast.IASTNodeLocation; -import org.eclipse.cdt.core.dom.ast.IASTPreprocessorFunctionStyleMacroDefinition; -import org.eclipse.cdt.core.dom.ast.IASTPreprocessorMacroDefinition; import org.eclipse.cdt.core.dom.ast.IASTStatement; import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit; import org.eclipse.cdt.core.dom.ast.IBinding; import org.eclipse.cdt.core.dom.ast.IMacroBinding; -import org.eclipse.cdt.core.dom.parser.IScannerExtensionConfiguration; -import org.eclipse.cdt.core.dom.parser.c.GCCScannerExtensionConfiguration; -import org.eclipse.cdt.core.dom.parser.cpp.GPPScannerExtensionConfiguration; -import org.eclipse.cdt.core.formatter.CodeFormatter; -import org.eclipse.cdt.core.model.ICProject; +import org.eclipse.cdt.core.dom.rewrite.MacroExpansionExplorer; import org.eclipse.cdt.core.model.ILanguage; import org.eclipse.cdt.core.model.ITranslationUnit; import org.eclipse.cdt.core.model.IWorkingCopy; -import org.eclipse.cdt.core.parser.CodeReader; -import org.eclipse.cdt.core.parser.EndOfFileException; -import org.eclipse.cdt.core.parser.IGCCToken; -import org.eclipse.cdt.core.parser.IScannerInfo; -import org.eclipse.cdt.core.parser.IToken; -import org.eclipse.cdt.core.parser.ParserLanguage; -import org.eclipse.cdt.core.parser.ParserUtil; -import org.eclipse.cdt.core.parser.ScannerInfo; import org.eclipse.cdt.ui.CUIPlugin; import org.eclipse.cdt.ui.IWorkingCopyManager; -import org.eclipse.cdt.internal.core.dom.NullCodeReaderFactory; import org.eclipse.cdt.internal.core.model.ASTCache.ASTRunnable; -import org.eclipse.cdt.internal.core.parser.scanner.CPreprocessor; -import org.eclipse.cdt.internal.corext.util.CodeFormatterUtil; import org.eclipse.cdt.internal.ui.editor.ASTProvider; @@ -226,16 +206,14 @@ public class CMacroExpansionHover extends AbstractCEditorTextHover implements II */ private static class ComputeExpansionRegionRunnable implements ASTRunnable { private final Position fTextRegion; + private final boolean fAllowSelection; private IASTNode fEnclosingNode; - private Map fMacroDict; private List fExpansionNodes= new ArrayList(); + private MacroExpansionExplorer fExplorer; - /** - * @param tUnit - * @param textRegion - */ - private ComputeExpansionRegionRunnable(ITranslationUnit tUnit, IRegion textRegion) { + private ComputeExpansionRegionRunnable(ITranslationUnit tUnit, IRegion textRegion, boolean allowSelection) { fTextRegion= new Position(textRegion.getOffset(), textRegion.getLength()); + fAllowSelection= allowSelection; } /* @@ -243,79 +221,56 @@ public class CMacroExpansionHover extends AbstractCEditorTextHover implements II */ public IStatus runOnAST(ILanguage lang, IASTTranslationUnit ast) { if (ast != null) { - // try object style macro expansion first + // try macro name match first IASTNode node= ast.selectNodeForLocation(ast.getFilePath(), fTextRegion.getOffset(), fTextRegion.getLength()); if (node instanceof IASTName) { IASTName macroName= (IASTName) node; IBinding binding= macroName.getBinding(); if (binding instanceof IMacroBinding) { - IMacroBinding macroBinding= (IMacroBinding) binding; - if (!macroBinding.isFunctionStyle()) { - addExpansionNode(node); - buildMacroDictionary(ast); - return Status.OK_STATUS; - } + addExpansionNode(node); + createMacroExpansionExplorer(ast, getExpansionRegion()); + return Status.OK_STATUS; } } - // function style macro or selection - FindEnclosingNodeAction nodeFinder= new FindEnclosingNodeAction(ast.getFilePath(), fTextRegion.getOffset(), fTextRegion.getLength()); - ast.accept(nodeFinder); - fEnclosingNode= nodeFinder.getNode(); - if (fEnclosingNode != null) { - boolean macroOccurrence= false; - IASTNodeLocation[] locations= fEnclosingNode.getNodeLocations(); - for (int i = 0; i < locations.length; i++) { - IASTNodeLocation location= locations[i]; - if (location instanceof IASTMacroExpansion) { - IASTFileLocation fileLocation= location.asFileLocation(); - if (fileLocation != null && ast.getFilePath().equals(fileLocation.getFileName())) { - if (fTextRegion.overlapsWith(fileLocation.getNodeOffset(), fileLocation.getNodeLength())) { - nodeFinder= new FindEnclosingNodeAction(ast.getFilePath(), fileLocation.getNodeOffset(), fileLocation.getNodeLength()); - ast.accept(nodeFinder); - addExpansionNode(nodeFinder.getNode()); - macroOccurrence= true; + if (fAllowSelection) { + // selection + FindEnclosingNodeAction nodeFinder= new FindEnclosingNodeAction(ast.getFilePath(), fTextRegion.getOffset(), fTextRegion.getLength()); + ast.accept(nodeFinder); + fEnclosingNode= nodeFinder.getNode(); + if (fEnclosingNode != null) { + boolean macroOccurrence= false; + IASTNodeLocation[] locations= fEnclosingNode.getNodeLocations(); + for (int i = 0; i < locations.length; i++) { + IASTNodeLocation location= locations[i]; + if (location instanceof IASTMacroExpansion) { + IASTFileLocation fileLocation= location.asFileLocation(); + if (fileLocation != null && ast.getFilePath().equals(fileLocation.getFileName())) { + if (fTextRegion.overlapsWith(fileLocation.getNodeOffset(), fileLocation.getNodeLength())) { + nodeFinder= new FindEnclosingNodeAction(ast.getFilePath(), fileLocation.getNodeOffset(), fileLocation.getNodeLength()); + ast.accept(nodeFinder); + addExpansionNode(nodeFinder.getNode()); + macroOccurrence= true; + } } } } - } - if (macroOccurrence) { - CollectEnclosedNodesAction nodeCollector= new CollectEnclosedNodesAction(ast.getFilePath(), fTextRegion.getOffset(), fTextRegion.getLength()); - ast.accept(nodeCollector); - fExpansionNodes.addAll(nodeCollector.getNodes()); - buildMacroDictionary(ast); - return Status.OK_STATUS; + if (macroOccurrence) { + CollectEnclosedNodesAction nodeCollector= new CollectEnclosedNodesAction(ast.getFilePath(), fTextRegion.getOffset(), fTextRegion.getLength()); + ast.accept(nodeCollector); + fExpansionNodes.addAll(nodeCollector.getNodes()); + createMacroExpansionExplorer(ast, getExpansionRegion()); + return Status.OK_STATUS; + } } } } return Status.CANCEL_STATUS; } - private void buildMacroDictionary(IASTTranslationUnit ast) { - Map macroDict= new HashMap(500); - IASTPreprocessorMacroDefinition[] macroDefs; - final IASTPreprocessorMacroDefinition[] localMacroDefs= ast.getMacroDefinitions(); - for (macroDefs= localMacroDefs; macroDefs != null; macroDefs= (macroDefs == localMacroDefs) ? ast.getBuiltinMacroDefinitions() : null) { - for (int i = 0; i < macroDefs.length; i++) { - IASTPreprocessorMacroDefinition macroDef= macroDefs[i]; - StringBuffer macroName= new StringBuffer(); - macroName.append(macroDef.getName().toCharArray()); - if (macroDef instanceof IASTPreprocessorFunctionStyleMacroDefinition) { - macroName.append('('); - IASTPreprocessorFunctionStyleMacroDefinition functionMacro= (IASTPreprocessorFunctionStyleMacroDefinition)macroDef; - IASTFunctionStyleMacroParameter[] macroParams= functionMacro.getParameters(); - for (int j = 0; j < macroParams.length; j++) { - if (j > 0) { - macroName.append(','); - } - IASTFunctionStyleMacroParameter param= macroParams[j]; - macroName.append(param.getParameter()); - } - macroName.append(')'); - } - macroDict.put(macroName.toString(), macroDef.getExpansion()); - } + private void createMacroExpansionExplorer(IASTTranslationUnit ast, IRegion region) { + if (region != null) { + fExplorer= MacroExpansionExplorer.create(ast, region); } - fMacroDict= macroDict; } private void addExpansionNode(IASTNode node) { @@ -375,41 +330,42 @@ public class CMacroExpansionHover extends AbstractCEditorTextHover implements II return null; } - Map getMacroDictionary() { - return fMacroDict; - } - IASTNode getEnclosingNode() { return fEnclosingNode; } + + MacroExpansionExplorer getMacroExpansionExplorer() { + return fExplorer; + } } - private static class Cache { - ComputeExpansionRegionRunnable fComputer; - IWorkingCopy fTranslationUnit; - String fExpansionText; - String fExpandedText; - } - - private WeakReference fCache; + private Reference fCache; /* * @see org.eclipse.cdt.internal.ui.text.c.hover.AbstractCEditorTextHover#getHoverInfo(org.eclipse.jface.text.ITextViewer, org.eclipse.jface.text.IRegion) */ public String getHoverInfo(ITextViewer textViewer, IRegion hoverRegion) { - IEditorPart editor = getEditor(); + CMacroExpansionInput input= createMacroExpansionInput(getEditor(), hoverRegion, true); + if (input == null) { + return null; + } + fCache= new SoftReference(input); + return input.fExplorer.getFullExpansion().getCodeAfterStep(); + } + + public static CMacroExpansionInput createMacroExpansionInput(IEditorPart editor, IRegion hoverRegion, boolean allowSelection) { if (editor == null || !(editor instanceof ITextEditor)) { return null; } - IEditorInput input= editor.getEditorInput(); + IEditorInput editorInput= editor.getEditorInput(); IWorkingCopyManager manager= CUIPlugin.getDefault().getWorkingCopyManager(); - IWorkingCopy tu = manager.getWorkingCopy(input); + IWorkingCopy tu = manager.getWorkingCopy(editorInput); if (tu == null) { return null; } - + IProgressMonitor monitor= new NullProgressMonitor(); - ComputeExpansionRegionRunnable computer= new ComputeExpansionRegionRunnable(tu, hoverRegion); + ComputeExpansionRegionRunnable computer= new ComputeExpansionRegionRunnable(tu, hoverRegion, allowSelection); IStatus status= ASTProvider.getASTProvider().runOnAST(tu, ASTProvider.WAIT_ACTIVE_ONLY, monitor, computer); if (!status.isOK()) { return null; @@ -418,49 +374,19 @@ public class CMacroExpansionHover extends AbstractCEditorTextHover implements II if (region == null) { return null; } - ITextEditor textEditor= (ITextEditor)editor; - IDocument document= textEditor.getDocumentProvider().getDocument(input); - region= alignRegion(region, document); - - String expansionText; - try { - expansionText= document.get(region.getOffset(), region.getLength()); - } catch (BadLocationException exc) { - CUIPlugin.getDefault().log(exc); + MacroExpansionExplorer explorer= computer.getMacroExpansionExplorer(); + if (explorer == null) { return null; } - // expand - String expandedText= expandMacros(computer.getMacroDictionary(), expansionText, tu.isCXXLanguage()); - - // format - final String lineDelimiter= TextUtilities.getDefaultLineDelimiter(document); - final int nodeKind = getNodeKind(computer.getEnclosingNode()); - String formattedText= formatSource(nodeKind, expandedText, lineDelimiter, tu.getCProject()); - - // cache objects for later macro exploration - Cache cache= new Cache(); - cache.fComputer= computer; - cache.fExpansionText= expansionText; - cache.fTranslationUnit= tu; - cache.fExpandedText= formattedText; - fCache= new WeakReference(cache); - return formattedText; - } - - private static int getNodeKind(IASTNode node) { - if (node instanceof IASTDeclaration) { - return CodeFormatter.K_TRANSLATION_UNIT; - } - if (node instanceof IASTStatement) { - return CodeFormatter.K_STATEMENTS; - } - if (node instanceof IASTExpression) { - return CodeFormatter.K_EXPRESSION; - } - if (node instanceof IASTTranslationUnit) { - return CodeFormatter.K_TRANSLATION_UNIT; - } - return CodeFormatter.K_UNKNOWN; + ITextEditor textEditor= (ITextEditor)editor; + IDocument document= textEditor.getDocumentProvider().getDocument(editorInput); + region= alignRegion(region, document); + + CMacroExpansionInput input= new CMacroExpansionInput(); + input.fExplorer= explorer; + input.fDocument= document; + input.fRegion= region; + return input; } private static final IRegion alignRegion(IRegion region, IDocument document) { @@ -491,151 +417,6 @@ public class CMacroExpansionHover extends AbstractCEditorTextHover implements II } } - /** - * Format given source content according given options. - * - * @param kind - * one of {@link CodeFormatter#K_TRANSLATION_UNIT}, - * {@link CodeFormatter#K_STATEMENTS}, - * {@link CodeFormatter#K_EXPRESSION} - * @param content - * the source content - * @param lineDelimiter - * the line delimiter to be used - * @param project - * @return the formatted source text or the original if the text could not - * be formatted successfully - */ - private static String formatSource(int kind, String content, String lineDelimiter, ICProject project) { - TextEdit edit= CodeFormatterUtil.format(kind, content, 0, lineDelimiter, project.getOptions(true)); - if (edit != null) { - IDocument doc= new Document(content); - try { - edit.apply(doc); - content= doc.get().trim(); - } catch (MalformedTreeException exc) { - CUIPlugin.getDefault().log(exc); - } catch (BadLocationException exc) { - CUIPlugin.getDefault().log(exc); - } - } - return content; - } - - private String expandMacros(Map macroDict, String expansionText, boolean isCpp) { - final IScannerInfo scannerInfo= new ScannerInfo(macroDict); - final CodeReader codeReader= new CodeReader(expansionText.toCharArray()); - final IScannerExtensionConfiguration configuration; - final ParserLanguage parserLanguage; - if (isCpp) { - configuration= new GPPScannerExtensionConfiguration(); - parserLanguage= ParserLanguage.CPP; - } else { - configuration= new GCCScannerExtensionConfiguration(); - parserLanguage= ParserLanguage.C; - } - CPreprocessor preprocessor= new CPreprocessor(codeReader, scannerInfo, parserLanguage, ParserUtil.getParserLogService(), configuration, NullCodeReaderFactory.getInstance()); - StringBuffer expandedText= new StringBuffer(expansionText.length()); - IToken token= null; - IToken prevToken; - while (true) { - try { - prevToken= token; - token= preprocessor.nextToken(); - } catch (EndOfFileException exc) { - break; - } - if (requireSpace(prevToken, token)) { - expandedText.append(' '); - } - expandedText.append(token.getImage()); - } - return expandedText.toString(); - } - - private static boolean requireSpace(IToken prevToken, IToken token) { - if (prevToken == null) { - return false; - } - if (prevToken.isOperator() && token.isOperator()) { - return true; - } - switch (prevToken.getType()) { - case IToken.tLPAREN: case IToken.tLBRACKET: - return false; - - // bit operations - case IToken.tAMPERASSIGN: - case IToken.tBITOR: case IToken.tBITORASSIGN: - case IToken.tSHIFTL: case IToken.tSHIFTLASSIGN: - case IToken.tSHIFTR: case IToken.tSHIFTRASSIGN: - case IToken.tXOR: case IToken.tXORASSIGN: - - // logical operations - case IToken.tAND: case IToken.tOR: - - // arithmetic - case IToken.tDIV: case IToken.tDIVASSIGN: - case IToken.tMINUS: case IToken.tMINUSASSIGN: - case IToken.tMOD: case IToken.tMODASSIGN: - case IToken.tPLUS: case IToken.tPLUSASSIGN: - case IToken.tSTARASSIGN: - case IGCCToken.tMAX: case IGCCToken.tMIN: - - // comparison - case IToken.tEQUAL: case IToken.tNOTEQUAL: - case IToken.tGT: case IToken.tGTEQUAL: - case IToken.tLT: case IToken.tLTEQUAL: - - // other - case IToken.tASSIGN: case IToken.tCOMMA: - return true; - } - - switch (token.getType()) { - case IToken.tRPAREN: case IToken.tRBRACKET: - return false; - - // bit operations - case IToken.tAMPER: case IToken.tAMPERASSIGN: - case IToken.tBITOR: case IToken.tBITORASSIGN: - case IToken.tSHIFTL: case IToken.tSHIFTLASSIGN: - case IToken.tSHIFTR: case IToken.tSHIFTRASSIGN: - case IToken.tXOR: case IToken.tXORASSIGN: - - // logical operations - case IToken.tAND: case IToken.tOR: - - // arithmetic - case IToken.tDIV: case IToken.tDIVASSIGN: - case IToken.tMINUS: case IToken.tMINUSASSIGN: - case IToken.tMOD: case IToken.tMODASSIGN: - case IToken.tPLUS: case IToken.tPLUSASSIGN: - case IToken.tSTAR: case IToken.tSTARASSIGN: - case IGCCToken.tMAX: case IGCCToken.tMIN: - - // comparison - case IToken.tEQUAL: case IToken.tNOTEQUAL: - case IToken.tGT: case IToken.tGTEQUAL: - case IToken.tLT: case IToken.tLTEQUAL: - return true; - - // other - case IToken.tASSIGN: - return true; - - case IToken.tCOMMA: - return false; - } - - char lastChar= prevToken.getCharImage()[prevToken.getLength() - 1]; - char nextChar= token.getCharImage()[0]; - if (Character.isJavaIdentifierPart(lastChar) && Character.isJavaIdentifierPart(nextChar)) { - return true; - } - return false; - } - /* * @see org.eclipse.jface.text.ITextHoverExtension#getHoverControlCreator() */ @@ -655,21 +436,30 @@ public class CMacroExpansionHover extends AbstractCEditorTextHover implements II public IInformationControl createInformationControl(Shell parent) { int shellStyle= SWT.RESIZE; int style= SWT.V_SCROLL | SWT.H_SCROLL; - return new CMacroExpansionControl(parent, shellStyle, style, createMacroExpansionInput()); + return new CMacroExpansionExplorationControl(parent, shellStyle, style, getMacroExpansionInput()); } }; } - protected CMacroExpansionInput createMacroExpansionInput() { - // TODO compute all expansion steps - Cache cache= (Cache) fCache.get(); - fCache= null; - if (cache != null) { - CMacroExpansionInput input= new CMacroExpansionInput(); - input.fExpansions= new String[] { cache.fExpansionText, cache.fExpandedText }; - return input; + protected CMacroExpansionInput getMacroExpansionInput() { + if (fCache == null) { + return null; } - return null; + CMacroExpansionInput input= (CMacroExpansionInput) fCache.get(); + fCache= null; + if (input == null) { + IEditorPart editor= getEditor(); + if (editor != null) { + ISelectionProvider provider= editor.getSite().getSelectionProvider(); + ISelection selection= provider.getSelection(); + if (selection instanceof ITextSelection) { + ITextSelection textSelection= (ITextSelection) selection; + IRegion region= new Region(textSelection.getOffset(), textSelection.getLength()); + input= createMacroExpansionInput(editor, region, true); + } + } + } + return input; } } diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CMacroExpansionInput.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CMacroExpansionInput.java index 586d4bcb1e6..35273705a69 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CMacroExpansionInput.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CMacroExpansionInput.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007 Wind River Systems, Inc. and others. + * Copyright (c) 2007, 2008 Wind River Systems, Inc. and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -11,11 +11,18 @@ package org.eclipse.cdt.internal.ui.text.c.hover; +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.IRegion; + +import org.eclipse.cdt.core.dom.rewrite.MacroExpansionExplorer; + /** - * An input object to the {@link CMacroExpansionControl}. + * An input object to the {@link CMacroExpansionExplorationControl}. * * @since 5.0 */ -public class CMacroExpansionInput { - String[] fExpansions; +class CMacroExpansionInput { + MacroExpansionExplorer fExplorer; + IDocument fDocument; + IRegion fRegion; }