[Title] Add Dynamic Help View and Code Assist feature.
authoryser.lee <yser.lee@samsung.com>
Thu, 17 May 2012 11:08:50 +0000 (20:08 +0900)
committeryser.lee <yser.lee@samsung.com>
Thu, 17 May 2012 11:11:34 +0000 (20:11 +0900)
[Type] Feature
[Module] bada IDE
[Priority] Normal
[CQ#]
[Redmine#]
[Problem]
[Cause]
[Solution]
[TestCase]

org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CDocBrowserInformationControl.java [new file with mode: 0644]
org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CDocBrowserInformationControlInput.java [new file with mode: 0644]
org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CDocHover.java
org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CElementLinks.java [new file with mode: 0644]
org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CHoverMessages.java
org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CHoverMessages.properties
org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/contentassist/DOMCompletionProposalComputer.java
org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/CUIPreferenceInitializer.java

diff --git a/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CDocBrowserInformationControl.java b/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CDocBrowserInformationControl.java
new file mode 100644 (file)
index 0000000..7123832
--- /dev/null
@@ -0,0 +1,596 @@
+package org.eclipse.cdt.internal.ui.text.c.hover;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.util.Iterator;
+
+import org.eclipse.cdt.ui.CUIPreferenceInitializer;
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.ListenerList;
+import org.eclipse.jface.action.ToolBarManager;
+import org.eclipse.jface.internal.text.html.BrowserInformationControlInput;
+import org.eclipse.jface.internal.text.html.HTML2TextReader;
+import org.eclipse.jface.internal.text.html.HTMLPrinter;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.text.AbstractInformationControl;
+import org.eclipse.jface.text.IDelayedInputChangeProvider;
+import org.eclipse.jface.text.IInformationControlExtension2;
+import org.eclipse.jface.text.IInputChangedListener;
+import org.eclipse.jface.text.TextPresentation;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.SWTError;
+import org.eclipse.swt.browser.Browser;
+import org.eclipse.swt.browser.LocationListener;
+import org.eclipse.swt.browser.OpenWindowListener;
+import org.eclipse.swt.browser.ProgressAdapter;
+import org.eclipse.swt.browser.ProgressEvent;
+import org.eclipse.swt.browser.WindowEvent;
+import org.eclipse.swt.custom.StyleRange;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.graphics.TextLayout;
+import org.eclipse.swt.graphics.TextStyle;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Slider;
+
+/**
+ * Displays doxygen HTML information.
+ */
+public class CDocBrowserInformationControl extends AbstractInformationControl implements
+               IInformationControlExtension2, IDelayedInputChangeProvider {
+
+       /**
+        * Tells whether the SWT Browser widget and hence this information
+        * control is available.
+        * 
+        * @param parent the parent component used for checking or <code>null</code> if none
+        * @return <code>true</code> if this control is available
+        */
+       public static boolean isAvailable(Composite parent) {
+               if (!fgAvailabilityChecked) {
+                       try {
+                               Browser browser= new Browser(parent, SWT.NONE);
+                               browser.dispose();
+                               fgIsAvailable= true;
+
+                               Slider sliderV= new Slider(parent, SWT.VERTICAL);
+                               Slider sliderH= new Slider(parent, SWT.HORIZONTAL);
+                               int width= sliderV.computeSize(SWT.DEFAULT, SWT.DEFAULT).x;
+                               int height= sliderH.computeSize(SWT.DEFAULT, SWT.DEFAULT).y;
+                               fgScrollBarSize= new Point(width, height);
+                               sliderV.dispose();
+                               sliderH.dispose();
+                       } catch (SWTError er) {
+                               fgIsAvailable= false;
+                       } finally {
+                               fgAvailabilityChecked= true;
+                       }
+               }
+
+               return fgIsAvailable;
+       }
+
+       /**
+        * Minimal size constraints.
+        * @since 3.2
+        */
+       private static final int MIN_WIDTH= 80;
+
+       private static final int MIN_HEIGHT= 50;
+
+
+       /**
+        * Availability checking cache.
+        */
+       private static boolean fgIsAvailable= false;
+
+       private static boolean fgAvailabilityChecked= false;
+
+       /**
+        * Cached scroll bar width and height
+        * @since 3.4
+        */
+       private static Point fgScrollBarSize;
+
+       /** The control's browser widget */
+       private Browser fBrowser;
+
+       /** Tells whether the browser has content */
+       private boolean fBrowserHasContent;
+
+       /** Text layout used to approximate size of content when rendered in browser */
+       private TextLayout fTextLayout;
+
+       /** Bold text style */
+       private TextStyle fBoldStyle;
+
+       private BrowserInformationControlInput fInput;
+
+       /**
+        * <code>true</code> iff the browser has completed loading of the last
+        * input set via {@link #setInformation(String)}.
+        * @since 3.4
+        */
+       private boolean fCompleted= false;
+
+       /**
+        * The listener to be notified when a delayed location changing event happened.
+        * @since 3.4
+        */
+       private IInputChangedListener fDelayedInputChangeListener;
+
+       /**
+        * The listeners to be notified when the input changed.
+        * @since 3.4
+        */
+       private ListenerList/*<IInputChangedListener>*/fInputChangeListeners= new ListenerList(ListenerList.IDENTITY);
+
+       /**
+        * The symbolic name of the font used for size computations, or <code>null</code> to use dialog font.
+        * @since 3.4
+        */
+       private final String fSymbolicFontName;
+
+
+       /**
+        * Creates a browser information control with the given shell as parent.
+        * 
+        * @param parent the parent shell
+        * @param symbolicFontName the symbolic name of the font used for size computations
+        * @param resizable <code>true</code> if the control should be resizable
+        * @since 3.4
+        */
+       public CDocBrowserInformationControl(Shell parent, String symbolicFontName, boolean resizable) {
+               super(parent, resizable);
+               fSymbolicFontName= symbolicFontName;
+               create();
+       }
+
+       /**
+        * Creates a browser information control with the given shell as parent.
+        * 
+        * @param parent the parent shell
+        * @param symbolicFontName the symbolic name of the font used for size computations
+        * @param statusFieldText the text to be used in the optional status field
+        *            or <code>null</code> if the status field should be hidden
+        * @since 3.4
+        */
+       public CDocBrowserInformationControl(Shell parent, String symbolicFontName, String statusFieldText) {
+               super(parent, statusFieldText);
+               fSymbolicFontName= symbolicFontName;
+               create();
+       }
+
+       /**
+        * Creates a browser information control with the given shell as parent.
+        * 
+        * @param parent the parent shell
+        * @param symbolicFontName the symbolic name of the font used for size computations
+        * @param toolBarManager the manager or <code>null</code> if toolbar is not desired
+        * @since 3.4
+        */
+       public CDocBrowserInformationControl(Shell parent, String symbolicFontName, ToolBarManager toolBarManager) {
+               super(parent, toolBarManager);
+               fSymbolicFontName= symbolicFontName;
+               create();
+       }
+
+       /*
+        * @see org.eclipse.jface.text.AbstractInformationControl#createContent(org.eclipse.swt.widgets.Composite)
+        */
+       protected void createContent(Composite parent) {
+               fBrowser= new Browser(parent, SWT.NONE);
+               fBrowser.setJavascriptEnabled(false);
+
+               Display display= getShell().getDisplay();
+               fBrowser.setForeground(display.getSystemColor(SWT.COLOR_INFO_FOREGROUND));
+               fBrowser.setBackground(display.getSystemColor(SWT.COLOR_INFO_BACKGROUND));
+
+               fBrowser.addProgressListener(new ProgressAdapter() {
+                       public void completed(ProgressEvent event) {
+                               fCompleted= true;
+                       }
+               });
+
+               fBrowser.addOpenWindowListener(new OpenWindowListener() {
+                       public void open(WindowEvent event) {
+                               event.required= true; // Cancel opening of new windows
+                       }
+               });
+
+               // Replace browser's built-in context menu with none
+               fBrowser.setMenu(new Menu(getShell(), SWT.NONE));
+
+               createTextLayout();
+       }
+
+       /**
+        * {@inheritDoc}
+        * @deprecated use {@link #setInput(Object)}
+        */
+       public void setInformation(final String content) {
+               setInput(new BrowserInformationControlInput(null) {
+                       public String getHtml() {
+                               return content;
+                       }
+
+                       public String getInputName() {
+                               return ""; //$NON-NLS-1$
+                       }
+
+                       public Object getInputElement() {
+                               return content;
+                       }
+               });
+       }
+
+       /**
+        * {@inheritDoc} This control can handle {@link String} and
+        * {@link BrowserInformationControlInput}.
+        */
+       public void setInput(Object input) {
+               Assert.isLegal(input == null || input instanceof String || input instanceof BrowserInformationControlInput);
+
+               if (input instanceof String) {
+                       setInformation((String)input);
+                       return;
+               }
+
+               fInput= (BrowserInformationControlInput)input;
+
+               String content= null;
+               if (fInput != null)
+                       content= fInput.getHtml();
+
+               fBrowserHasContent= content != null && content.length() > 0;
+
+               if (!fBrowserHasContent)
+                       content= "<html><body ></html>"; //$NON-NLS-1$
+
+               boolean RTL= (getShell().getStyle() & SWT.RIGHT_TO_LEFT) != 0;
+               boolean resizable= isResizable();
+
+               // The default "overflow:auto" would not result in a predictable width for the client area
+               // and the re-wrapping would cause visual noise
+               String[] styles= null;
+               if (RTL && resizable)
+                       styles= new String[] { "direction:rtl;", "overflow:scroll;", "word-wrap:break-word;" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+               else if (RTL && !resizable)
+                       styles= new String[] { "direction:rtl;", "overflow:hidden;", "word-wrap:break-word;" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+               else if (!resizable)
+                       //XXX: In IE, "word-wrap: break-word;" causes bogus wrapping even in non-broken words :-(see e.g. Javadoc of String).
+                       // Re-check whether we really still need this now that the Javadoc Hover header already sets this style.
+                       styles= new String[] { "overflow:hidden;"/*, "word-wrap: break-word;"*/}; //$NON-NLS-1$
+               else
+                       styles= new String[] { "overflow:scroll;" }; //$NON-NLS-1$
+
+               StringBuffer buffer= new StringBuffer(content);
+               HTMLPrinter.insertStyles(buffer, styles);
+               content= buffer.toString();
+
+               /*
+                * XXX: Should add some JavaScript here that shows something like
+                * "(continued...)" or "..." at the end of the visible area when the page overflowed
+                * with "overflow:hidden;".
+                */
+
+               fCompleted= false;
+               if (!content.contains(".html")) {
+                       return;
+               }
+               String url = CUIPreferenceInitializer.doxygenDirectoryPath + "/" + content;
+               CElementLinks.isSet = 1;
+               fBrowser.setUrl(url);
+
+               Object[] listeners= fInputChangeListeners.getListeners();
+               for (int i= 0; i < listeners.length; i++)
+                       ((IInputChangedListener)listeners[i]).inputChanged(fInput);
+       }
+
+       /*
+        * @see IInformationControl#setVisible(boolean)
+        */
+       public void setVisible(boolean visible) {
+               Shell shell= getShell();
+               if (shell.isVisible() == visible)
+                       return;
+
+               if (!visible) {
+                       super.setVisible(false);
+                       setInput(null);
+                       return;
+               }
+
+               /*
+                * The Browser widget flickers when made visible while it is not completely loaded.
+                * The fix is to delay the call to setVisible until either loading is completed
+                * (see ProgressListener in constructor), or a timeout has been reached.
+                */
+               final Display display= shell.getDisplay();
+
+               // Make sure the display wakes from sleep after timeout:
+               display.timerExec(100, new Runnable() {
+                       public void run() {
+                               fCompleted= true;
+                       }
+               });
+
+               while (!fCompleted) {
+                       // Drive the event loop to process the events required to load the browser widget's contents:
+                       if (!display.readAndDispatch()) {
+                               display.sleep();
+                       }
+               }
+
+               shell= getShell();
+               if (shell == null || shell.isDisposed())
+                       return;
+
+               /*
+                * Avoids flickering when replacing hovers, especially on Vista in ON_CLICK mode.
+                * Causes flickering on GTK. Carbon does not care.
+                */
+               if ("win32".equals(SWT.getPlatform())) //$NON-NLS-1$
+                       shell.moveAbove(null);
+
+               super.setVisible(true);
+       }
+
+       /*
+        * @see org.eclipse.jface.text.AbstractInformationControl#setSize(int, int)
+        */
+       public void setSize(int width, int height) {
+               fBrowser.setRedraw(false); // avoid flickering
+               try {
+                       //super.setSize(width, height);
+                       super.setSize(750, 300); // TODO Modify
+               } finally {
+                       fBrowser.setRedraw(true);
+               }
+       }
+
+       /**
+        * Creates and initializes the text layout used
+        * to compute the size hint.
+        * 
+        * @since 3.2
+        */
+       private void createTextLayout() {
+               fTextLayout= new TextLayout(fBrowser.getDisplay());
+
+               // Initialize fonts
+               String symbolicFontName= fSymbolicFontName == null ? JFaceResources.DIALOG_FONT : fSymbolicFontName;
+               Font font= JFaceResources.getFont(symbolicFontName);
+               fTextLayout.setFont(font);
+               fTextLayout.setWidth(-1);
+               font= JFaceResources.getFontRegistry().getBold(symbolicFontName);
+               fBoldStyle= new TextStyle(font, null, null);
+
+               // Compute and set tab width
+               fTextLayout.setText("    "); //$NON-NLS-1$
+               int tabWidth= fTextLayout.getBounds().width;
+               fTextLayout.setTabs(new int[] { tabWidth });
+               fTextLayout.setText(""); //$NON-NLS-1$
+       }
+
+       /*
+        * @see org.eclipse.jface.text.AbstractInformationControl#handleDispose()
+        * @since 3.6
+        */
+       protected void handleDispose() {
+               if (fTextLayout != null) {
+                       fTextLayout.dispose();
+                       fTextLayout= null;
+               }
+               fBrowser= null;
+
+               super.handleDispose();
+       }
+
+       /*
+        * @see IInformationControl#computeSizeHint()
+        */
+       public Point computeSizeHint() {
+               Point sizeConstraints= getSizeConstraints();
+               Rectangle trim= computeTrim();
+               int height= trim.height;
+
+               //FIXME: The HTML2TextReader does not render <p> like a browser.
+               // Instead of inserting an empty line, it just adds a single line break.
+               // Furthermore, the indentation of <dl><dd> elements is too small (e.g with a long @see line)
+               TextPresentation presentation= new TextPresentation();
+               HTML2TextReader reader= new HTML2TextReader(new StringReader(fInput.getHtml()), presentation);
+               String text;
+               try {
+                       text= reader.getString();
+               } catch (IOException e) {
+                       text= ""; //$NON-NLS-1$
+               }
+
+               fTextLayout.setText(text);
+               fTextLayout.setWidth(sizeConstraints == null ? SWT.DEFAULT : sizeConstraints.x - trim.width);
+               Iterator iter= presentation.getAllStyleRangeIterator();
+               while (iter.hasNext()) {
+                       StyleRange sr= (StyleRange)iter.next();
+                       if (sr.fontStyle == SWT.BOLD)
+                               fTextLayout.setStyle(fBoldStyle, sr.start, sr.start + sr.length - 1);
+               }
+
+               Rectangle bounds= fTextLayout.getBounds(); // does not return minimum width, see https://bugs.eclipse.org/bugs/show_bug.cgi?id=217446
+               int lineCount= fTextLayout.getLineCount();
+               int textWidth= 0;
+               for (int i= 0; i < lineCount; i++) {
+                       Rectangle rect= fTextLayout.getLineBounds(i);
+                       int lineWidth= rect.x + rect.width;
+                       if (i == 0)
+                               lineWidth+= fInput.getLeadingImageWidth();
+                       textWidth= Math.max(textWidth, lineWidth);
+               }
+               bounds.width= textWidth;
+               fTextLayout.setText(""); //$NON-NLS-1$
+
+               int minWidth= bounds.width;
+               height= height + bounds.height;
+
+               // Add some air to accommodate for different browser renderings
+               minWidth+= 15;
+               height+= 15;
+
+
+               // Apply max size constraints
+               if (sizeConstraints != null) {
+                       if (sizeConstraints.x != SWT.DEFAULT)
+                               minWidth= Math.min(sizeConstraints.x, minWidth + trim.width);
+                       if (sizeConstraints.y != SWT.DEFAULT)
+                               height= Math.min(sizeConstraints.y, height);
+               }
+
+               // Ensure minimal size
+               int width= Math.max(MIN_WIDTH, minWidth);
+               height= Math.max(MIN_HEIGHT, height);
+
+               return new Point(width, height);
+       }
+
+       /*
+        * @see org.eclipse.jface.text.IInformationControlExtension3#computeTrim()
+        */
+       public Rectangle computeTrim() {
+               Rectangle trim= super.computeTrim();
+               if (isResizable()) {
+                       boolean RTL= (getShell().getStyle() & SWT.RIGHT_TO_LEFT) != 0;
+                       if (RTL) {
+                               trim.x-= fgScrollBarSize.x;
+                       }
+                       trim.width+= fgScrollBarSize.x;
+                       trim.height+= fgScrollBarSize.y;
+               }
+               return trim;
+       }
+
+       /**
+        * Adds the listener to the collection of listeners who will be
+        * notified when the current location has changed or is about to change.
+        * 
+        * @param listener the location listener
+        * @since 3.4
+        */
+       public void addLocationListener(LocationListener listener) {
+               fBrowser.addLocationListener(listener);
+       }
+
+       /*
+        * @see IInformationControl#setForegroundColor(Color)
+        */
+       public void setForegroundColor(Color foreground) {
+               super.setForegroundColor(foreground);
+               fBrowser.setForeground(foreground);
+       }
+
+       /*
+        * @see IInformationControl#setBackgroundColor(Color)
+        */
+       public void setBackgroundColor(Color background) {
+               super.setBackgroundColor(background);
+               fBrowser.setBackground(background);
+       }
+
+       /*
+        * @see IInformationControlExtension#hasContents()
+        */
+       public boolean hasContents() {
+               return fBrowserHasContent;
+       }
+
+       /**
+        * Adds a listener for input changes to this input change provider.
+        * Has no effect if an identical listener is already registered.
+        * 
+        * @param inputChangeListener the listener to add
+        * @since 3.4
+        */
+       public void addInputChangeListener(IInputChangedListener inputChangeListener) {
+               Assert.isNotNull(inputChangeListener);
+               fInputChangeListeners.add(inputChangeListener);
+       }
+
+       /**
+        * Removes the given input change listener from this input change provider.
+        * Has no effect if an identical listener is not registered.
+        * 
+        * @param inputChangeListener the listener to remove
+        * @since 3.4
+        */
+       public void removeInputChangeListener(IInputChangedListener inputChangeListener) {
+               fInputChangeListeners.remove(inputChangeListener);
+       }
+
+       /*
+        * @see org.eclipse.jface.text.IDelayedInputChangeProvider#setDelayedInputChangeListener(org.eclipse.jface.text.IInputChangedListener)
+        * @since 3.4
+        */
+       public void setDelayedInputChangeListener(IInputChangedListener inputChangeListener) {
+               fDelayedInputChangeListener= inputChangeListener;
+       }
+
+       /**
+        * Tells whether a delayed input change listener is registered.
+        * 
+        * @return <code>true</code> iff a delayed input change
+        *         listener is currently registered
+        * @since 3.4
+        */
+       public boolean hasDelayedInputChangeListener() {
+               return fDelayedInputChangeListener != null;
+       }
+
+       /**
+        * Notifies listeners of a delayed input change.
+        * 
+        * @param newInput the new input, or <code>null</code> to request cancellation
+        * @since 3.4
+        */
+       public void notifyDelayedInputChange(Object newInput) {
+               if (fDelayedInputChangeListener != null)
+                       fDelayedInputChangeListener.inputChanged(newInput);
+       }
+
+       /*
+        * @see java.lang.Object#toString()
+        * @since 3.4
+        */
+       public String toString() {
+               String style= (getShell().getStyle() & SWT.RESIZE) == 0 ? "fixed" : "resizeable"; //$NON-NLS-1$ //$NON-NLS-2$
+               return super.toString() + " -  style: " + style; //$NON-NLS-1$
+       }
+
+       /**
+        * @return the current browser input or <code>null</code>
+        */
+       public BrowserInformationControlInput getInput() {
+               return fInput;
+       }
+
+       /*
+        * @see org.eclipse.jface.text.IInformationControlExtension5#computeSizeConstraints(int, int)
+        */
+       public Point computeSizeConstraints(int widthInChars, int heightInChars) {
+               if (fSymbolicFontName == null)
+                       return null;
+
+               GC gc= new GC(fBrowser);
+               Font font= fSymbolicFontName == null ? JFaceResources.getDialogFont() : JFaceResources.getFont(fSymbolicFontName);
+               gc.setFont(font);
+               int width= gc.getFontMetrics().getAverageCharWidth();
+               int height= gc.getFontMetrics().getHeight();
+               gc.dispose();
+
+               return new Point(widthInChars * width, heightInChars * height);
+       }
+}
diff --git a/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CDocBrowserInformationControlInput.java b/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CDocBrowserInformationControlInput.java
new file mode 100644 (file)
index 0000000..3305a84
--- /dev/null
@@ -0,0 +1,66 @@
+package org.eclipse.cdt.internal.ui.text.c.hover;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.jface.internal.text.html.BrowserInformationControlInput;
+
+/**
+ * Provides input for CDocBrowserInformationControl.
+ */
+public class CDocBrowserInformationControlInput extends        BrowserInformationControlInput {
+       private final String fElement;
+       private final String fHtml;
+       private final int fLeadingImageWidth;
+
+       /**
+        * Creates a new browser information control input.
+        *
+        * @param previous previous input, or <code>null</code> if none available
+        * @param element the element, or <code>null</code> if none available
+        * @param html HTML contents, must not be null
+        * @param leadingImageWidth the indent required for the element image
+        */
+       public CDocBrowserInformationControlInput(CDocBrowserInformationControlInput previous, String element, String html, int leadingImageWidth) {
+               super(previous);
+               Assert.isNotNull(html);
+               fElement= element;
+               fHtml= html;
+               fLeadingImageWidth= leadingImageWidth;
+       }
+
+       /*
+        * @see org.eclipse.jface.internal.text.html.BrowserInformationControlInput#getLeadingImageWidth()
+        * @since 3.4
+        */
+       public int getLeadingImageWidth() {
+               return fLeadingImageWidth;
+       }
+
+       /**
+        * Returns the Java element.
+        *
+        * @return the element or <code>null</code> if none available
+        */
+       public String getElement() {
+               return fElement;
+       }
+
+       @Override
+       public String getHtml() {
+               // TODO Auto-generated method stub
+               return fHtml;
+       }
+
+       @Override
+       public Object getInputElement() {
+               // TODO Auto-generated method stub
+               return fElement == null ? (Object) fHtml : fElement;
+       }
+
+       @Override
+       public String getInputName() {
+               // TODO Auto-generated method stub
+               //return fElement == null ? "" : fElement.getElementName(); //$NON-NLS-1$
+               return fElement == null ? "" : fElement;
+       }
+
+}
index e912220..34dc834 100644 (file)
  *******************************************************************************/
 package org.eclipse.cdt.internal.ui.text.c.hover;
 
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.Set;
+import java.util.StringTokenizer;
 
+import org.eclipse.cdt.core.dom.ast.DOMException;
+import org.eclipse.cdt.core.dom.ast.IASTName;
+import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
+import org.eclipse.cdt.core.dom.ast.IBinding;
+import org.eclipse.cdt.core.model.CModelException;
+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.KeywordSetKey;
+import org.eclipse.cdt.core.parser.ParserFactory;
+import org.eclipse.cdt.core.parser.ParserLanguage;
+import org.eclipse.cdt.internal.core.model.ASTCache.ASTRunnable;
+import org.eclipse.cdt.internal.corext.util.Strings;
+import org.eclipse.cdt.internal.ui.CHelpProviderManager;
+import org.eclipse.cdt.internal.ui.editor.ASTProvider;
+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.CUIPlugin;
+import org.eclipse.cdt.ui.CUIPreferenceInitializer;
+import org.eclipse.cdt.ui.IFunctionSummary;
+import org.eclipse.cdt.ui.IFunctionSummary.IFunctionPrototypeSummary;
+import org.eclipse.cdt.ui.IRequiredInclude;
+import org.eclipse.cdt.ui.IWorkingCopyManager;
+import org.eclipse.cdt.ui.PreferenceConstants;
+import org.eclipse.cdt.ui.text.ICHelpInvocationContext;
+import org.eclipse.cdt.ui.text.IHoverHelpInvocationContext;
 import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.ISchedulingRule;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.action.ToolBarManager;
+import org.eclipse.jface.internal.text.html.BrowserInformationControlInput;
+import org.eclipse.jface.internal.text.html.BrowserInput;
+import org.eclipse.jface.text.AbstractReusableInformationControlCreator;
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.DefaultInformationControl;
+import org.eclipse.jface.text.IInformationControl;
+import org.eclipse.jface.text.IInformationControlCreator;
+import org.eclipse.jface.text.IInformationControlExtension4;
+import org.eclipse.jface.text.IInputChangedListener;
 import org.eclipse.jface.text.IRegion;
 import org.eclipse.jface.text.ITextViewer;
 import org.eclipse.jface.text.Region;
+import org.eclipse.swt.SWT;
 import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.widgets.Shell;
 import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.ISharedImages;
+import org.eclipse.ui.IWorkbenchSite;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.editors.text.EditorsUI;
 
-import org.eclipse.cdt.core.model.ITranslationUnit;
-import org.eclipse.cdt.ui.CUIPlugin;
-import org.eclipse.cdt.ui.IFunctionSummary;
-import org.eclipse.cdt.ui.IRequiredInclude;
-import org.eclipse.cdt.ui.IFunctionSummary.IFunctionPrototypeSummary;
-import org.eclipse.cdt.ui.text.ICHelpInvocationContext;
-import org.eclipse.cdt.ui.text.IHoverHelpInvocationContext;
+/**
+ * Provides doxygen hover.
+ */
+public class CDocHover extends AbstractCEditorTextHover {
 
-import org.eclipse.cdt.internal.ui.CHelpProviderManager;
-import org.eclipse.cdt.internal.ui.editor.CEditorMessages;
-import org.eclipse.cdt.internal.ui.text.CWordFinder;
-import org.eclipse.cdt.internal.ui.text.HTMLPrinter;
+       private static String doxygenDirectoryPath;
 
-public class CDocHover extends AbstractCEditorTextHover {
-       
        /**
         * Constructor for DefaultCEditorTextHover
         */
        public CDocHover() {
+               doxygenDirectoryPath = CUIPreferenceInitializer.doxygenDirectoryPath;
+       }
+
+       private static class SingletonRule implements ISchedulingRule {
+               public static final ISchedulingRule INSTANCE = new SingletonRule();
+               public boolean contains(ISchedulingRule rule) {
+                       return rule == this;
+               }
+               public boolean isConflicting(ISchedulingRule rule) {
+                       return rule == this;
+               }
+       }
+
+       /**
+        * Computes the source location for a given identifier.
+        */
+       private static class ComputeSourceRunnable implements ASTRunnable {
+
+               private final IRegion fTextRegion;
+               private String fSource;
+
+               /**
+                * If method is in source file, this is used.
+                */
+               private final int methodInSource = 1001;
+               /**
+                * If method is in header file, this is used.
+                */
+               private final int methodInHeader = 1002;
+
+               public ComputeSourceRunnable(ITranslationUnit tUnit, IRegion textRegion) {
+                       fTextRegion = textRegion;
+                       fSource = null;
+               }
+
+               /**
+                * Tokenizer
+                * 
+                * @param string  string to tokenize
+                * @return array of tokenized string
+                */
+               private String[] tokenizeString(String string) {
+                       StringTokenizer tokenizer = new StringTokenizer(string);
+                       String tokenOfString[] = new String[tokenizer.countTokens()];
+                       int index = 0;
+                       while (tokenizer.hasMoreTokens()) {
+                               tokenOfString[index] = tokenizer.nextToken();
+                               index++;
+                       }
+                       return tokenOfString;
+               }
+               /**
+                * Tokenizer with delimiter
+                * 
+                * @param string  string to tokenize
+                * @param delimiter  delimiter
+                * @return array of tokenized string
+                */
+               private String[] tokenizeStringWithDelimiter(String string, String delimiter) {
+                       StringTokenizer tokenizer = new StringTokenizer(string, delimiter);
+                       String tokenOfString[] = new String[tokenizer.countTokens()];
+                       int index = 0;
+                       while (tokenizer.hasMoreTokens()) {
+                               tokenOfString[index] = tokenizer.nextToken();
+                               index++;
+                       }
+                       return tokenOfString;
+               }
+               /**
+                * Check HTML file existence.
+                * 
+                * @param htmlFileName  HTML file name
+                * @return true if it exist, false if it doesn't exist
+                * @throws IOException  if an I/O error has occurred
+                */
+               private boolean checkHTMLFileExistence(String htmlFileName) throws IOException {
+                       File file = new File(doxygenDirectoryPath);
+                       File fileList[] = file.listFiles();
+                       for (int i = 0; i < fileList.length; i++) {
+                               if (htmlFileName.equals(fileList[i].getName())) {
+                                       return true;
+                               }
+                       }
+
+                       return false;
+               }
+               /**
+                * Find location of member variable of class.
+                * 
+                * @param htmlLine  1 line of HTML file
+                * @param memberName  method name
+                * @return location of member variable of class n HTML file
+                */
+               private String searchMemberVariableLocationOfCalss(String htmlLine, String memberName) {
+                       String tempString = null;
+                       String htmlFile = null;
+                       if (htmlLine.contains("class=\"memlist\"") == true) {
+                               tempString = htmlLine.trim();
+                               tempString = htmlLine.substring( htmlLine.indexOf(">", htmlLine.indexOf("href")) + 1, htmlLine.length());
+                               if (tempString.indexOf(memberName) == 0) {
+                                       htmlFile = htmlLine.substring(htmlLine.indexOf("href") + 6, htmlLine.indexOf("\"", htmlLine.indexOf("href") + 6));
+                                       return htmlFile;
+                               }
+                       }
+                       return null;
+               }
+               /**
+                * Change string with enumeration brace.
+                * 
+                * @param str  string with enumeration brace
+                * @return changed string
+                */
+               private String changeStringWithEnumerationBrace(String str) {
+                       StringBuilder sb = new StringBuilder(str);
+                       int index = 0;
+                       int index2 = 0;
+                       while (index != 4) {
+                               index = sb.indexOf("enum {", index) + 5;
+                               index2 = sb.indexOf("}", index);
+                               if ((index2 != -1) && (index != -1)) {
+                                       sb.delete(index2, index2 + 1);
+                                       sb.delete(index, index + 1);
+                               }
+                       }
+                       return sb.toString();
+               }
+               /**
+                * Change string with void.
+                * 
+                * @param str  string with void
+                * @return changed string
+                */
+               private String changeStringWithVoid(String str) {
+                       StringBuilder sb = new StringBuilder(str);
+                       int index = 0;
+                       int index2 = 0;
+                       while (index != -1) {
+                               index = sb.indexOf("(void)", index);
+                               index2 = index + 5;
+                               if ((index2 != -1) && (index != -1)) {
+                                       sb.delete(index2, index2 + 1);
+                                       sb.delete(index, index + 1);
+                               }
+                       }
+                       return sb.toString();
+               }
+               /**
+                * Change string with template.
+                * 
+                * @param str  string with template
+                * @return changed string
+                */
+               private String changeStringWithTemplate(String str) {
+                       StringBuilder sb = new StringBuilder(str);
+                       String type = str.substring(str.indexOf("<") + 1, str.indexOf(">"));
+                       if (!type.contains(",")) {
+                               str = str.replaceAll(type, "");
+                               return str;
+                       } else if (type.contains(",")) {
+                               sb.replace(sb.indexOf("<") + 1, sb.indexOf(",", sb.indexOf("<")), "");
+                               sb.replace(sb.indexOf(",", sb.indexOf("<")) + 1, sb.indexOf(">"), "");
+                               return sb.toString();
+                       }
+                       return null;
+               }
+               /**
+                * Change string with asterisk.
+                * 
+                * @param str  string with asterisk
+                * @return changed string
+                */
+               private String changeStringWithAsterisk(String str) {
+                       StringBuilder sb = new StringBuilder(str);
+                       int index = 0;          
+                       while (index != -1) {
+                               index = sb.indexOf("*", index);
+                               if (index != -1) {
+                                       sb.delete(index, index + 1);
+                                       sb.replace(index - 1, index, "* ");
+                               }
+                       }
+
+                       return sb.toString();
+               }
+               /**
+                * Find location of method of class in HTML file.
+                * 
+                * @param htmlLine  1 line of HTML file
+                * @param binding  IBinding
+                * @param isWhere  methodInSource if method is in source file, methodInHeader if method is in header file
+                * @param isMethodOfClass  true if method of class, false if method of interface
+                * @return location of method of class in HTML file
+                * @throws DOMException 
+                */
+               private String searchMethodLocationOfClass(String htmlLine, IBinding binding, int isWhere, boolean isMethodOfClass) throws DOMException {
+                       String htmlFile = null;
+
+                       String str[] = tokenizeString(binding.toString());
+                       if (str.length == 2) {
+                               if (str[1].equals("CPPFIELD")) {
+                                       if ( (htmlFile = searchMemberVariableLocationOfCalss(htmlLine, str[0])) != null) {
+                                               return htmlFile;
+                                       }
+                               }
+                       }
+
+                       String bindingString = binding.toString();
+                       if (bindingString.contains("long int")) {
+                               bindingString = bindingString.replaceAll("long int", "long");
+                       }
+                       if (bindingString.contains("short int")) {
+                               bindingString = bindingString.replaceAll("short int", "short");
+                       }
+                       if (bindingString.contains("enum {")) {
+                               bindingString = changeStringWithEnumerationBrace(bindingString);
+                       }
+                       if (bindingString.contains("enum ")) {
+                               bindingString = bindingString.replaceAll("enum ", "");
+                       }
+                       /* handling defined type start */
+                       if (bindingString.contains("wchar_t")) {
+                               bindingString = bindingString.replaceAll("wchar_t", "mchar");
+                       }
+                       if (bindingString.contains("Buffer<double>")) {
+                               bindingString = bindingString.replaceAll("Buffer<double>", "DoubleBuffer");
+                       }
+                       if (bindingString.contains("Buffer<float>")) {
+                               bindingString = bindingString.replaceAll("Buffer<float>", "FloatBuffer");
+                       }
+                       if (bindingString.contains("Buffer<int>")) {
+                               bindingString = bindingString.replaceAll("Buffer<int>", "IntBuffer");
+                       }
+                       if (bindingString.contains("Buffer<long>")) {
+                               bindingString = bindingString.replaceAll("Buffer<long>", "LongBuffer");
+                       }
+                       if (bindingString.contains("Buffer<long long>")) {
+                               bindingString = bindingString.replaceAll("Buffer<long long>", "LongLongBuffer");
+                       }
+                       if (bindingString.contains("Buffer<mchar>")) {
+                               bindingString = bindingString.replaceAll("Buffer<mchar>", "McharBuffer");
+                       }
+                       if (bindingString.contains("Buffer<short>")) {
+                               bindingString = bindingString.replaceAll("Buffer<short>", "ShortBuffer");
+                       }
+                       if (bindingString.contains("UUID_")) {
+                               bindingString = bindingString.replaceAll("UUID_", "UUID");
+                       }
+                       /* handling defined type end */
+                       if (bindingString.contains("(void)")) {
+                               changeStringWithVoid(bindingString);
+                       }
+                       String ownerOfBinding = binding.getOwner().toString();
+                       String namespace = ownerOfBinding.substring(0, ownerOfBinding.lastIndexOf(":") + 1);
+                       String methodName = tokenizeStringWithDelimiter(bindingString, "(),")[0];
+                       if (!methodName.equals("Compare")) {
+                               if (!bindingString.contains("Osp::Base::Object")) {
+                                       if (bindingString.contains(namespace)) {
+                                               bindingString = bindingString.replaceAll(namespace, "");
+                                       }
+                               }
+                       } else if (methodName.equals("Compare")) {
+                               if (!bindingString.contains("Osp::Base::Object")) {
+                                       if (bindingString.contains(namespace)) {
+                                               bindingString = bindingString.replaceAll(namespace, "");
+                                       }
+                               }
+                       }
+                       if (ownerOfBinding.equals("Osp::Base::Utility::StringUtil CPPCLASSTYPE")) {
+                               bindingString = bindingString.replaceAll("Osp::Base::", "");
+                       }
+                       if (ownerOfBinding.equals("Osp::Ui::Controls::Frame CPPCLASSTYPE")) {
+                               if (!bindingString.contains("AddControl")) {
+                                       bindingString = bindingString.replaceAll("Osp::Ui::", "");
+                               }
+                       }
+                       if (bindingString.contains("{")) {
+                               bindingString = bindingString.substring(0, bindingString.indexOf("{") - 1);
+                               bindingString = bindingString + " CPPMETHOD";
+                               if (bindingString.contains("<")) {
+                                       bindingString = changeStringWithTemplate(bindingString);
+                               }
+                       }
+                       bindingString = bindingString.replaceAll(" ", "");
+
+                       String bindingStringMethod[] = tokenizeStringWithDelimiter(bindingString, "(),");
+                       String htmlLineString = null;                   
+                       int isWhereTemp = 0;
+                       if (isWhere == methodInSource) {
+                               isWhereTemp = 2;
+                       } else if (isWhere == methodInHeader) {
+                               isWhereTemp = 1;
+                       }                       
+                       boolean isSame = true;
+
+                       if (htmlLine.contains("class=\"memlist\"") == true) {
+                               htmlLineString = htmlLine.trim();
+                               htmlLineString = htmlLine.substring( htmlLine.indexOf(">", htmlLine.indexOf("href")) + 1, htmlLine.length());
+                               if (htmlLineString.contains("const ")) {
+                                       htmlLineString = htmlLineString.replaceAll("const ", "const");
+                               }
+                               if (htmlLineString.contains(" &amp;")) {
+                                       htmlLineString = htmlLineString.replaceAll(" &amp;", "& ");
+                               }
+                               if (htmlLineString.contains("*")) {
+                                       htmlLineString = changeStringWithAsterisk(htmlLineString);
+                               }
+                               if (htmlLineString.contains("&lt; ")) {
+                                       htmlLineString = htmlLineString.replaceAll("&lt; ", "<");
+                               }
+                               if (htmlLineString.contains(" &gt;")) {
+                                       htmlLineString = htmlLineString.replaceAll(" &gt;", ">");
+                               }
+                               if (htmlLineString.contains("<")) {
+                                       htmlLineString = changeStringWithTemplate(htmlLineString);
+                               }
+                               if (htmlLineString.contains("(") && htmlLineString.contains(")")) { /* if member of class is method*/
+                                       String tokenOfMethod1 = htmlLineString.substring(0, htmlLineString.indexOf("("));
+                                       String tokenOfMethod2 = htmlLineString.substring(htmlLineString.indexOf("("), htmlLineString.indexOf(")") + 1);
+                                       String tokenOfMethod3 = htmlLineString.substring(htmlLineString.indexOf(")") + 1, htmlLineString.length());
+                                       /* handling defined type start */
+                                       if (tokenOfMethod2.contains("AppId")) {
+                                               tokenOfMethod2 = tokenOfMethod2.replaceAll("AppId", "Osp::Base::String");
+                                       }
+                                       if (tokenOfMethod2.contains("AppSecret")) {
+                                               tokenOfMethod2 = tokenOfMethod2.replaceAll("AppSecret", "Osp::Base::String");
+                                       }
+                                       if (tokenOfMethod2.contains("BuddyCategoryId")) {
+                                               tokenOfMethod2 = tokenOfMethod2.replaceAll("BuddyCategoryId", "Osp::Base::String");
+                                       }
+                                       if (tokenOfMethod2.contains("ChatMsgId")) {
+                                               tokenOfMethod2 = tokenOfMethod2.replaceAll("ChatMsgId", "int");
+                                       }
+                                       if (tokenOfMethod2.contains("KeyData")) {
+                                               tokenOfMethod2 = tokenOfMethod2.replaceAll("KeyData", "char");
+                                       }
+                                       if (tokenOfMethod2.contains("LandmarkId")) {
+                                               tokenOfMethod2 = tokenOfMethod2.replaceAll("LandmarkId", "long");
+                                       }
+                                       if (tokenOfMethod2.contains("LoginId")) {
+                                               tokenOfMethod2 = tokenOfMethod2.replaceAll("LoginId", "Osp::Base::String");
+                                       }
+                                       if (tokenOfMethod2.contains("NetAccountId")) {
+                                               tokenOfMethod2 = tokenOfMethod2.replaceAll("NetAccountId", "int");
+                                       }
+                                       if (tokenOfMethod2.contains("RecordId")) {
+                                               tokenOfMethod2 = tokenOfMethod2.replaceAll("RecordId", "long long");
+                                       }
+                                       if (tokenOfMethod2.contains("RecurrenceId")) {
+                                               tokenOfMethod2 = tokenOfMethod2.replaceAll("RecurrenceId", "Osp::Base::DateTime");
+                                       }
+                                       if (tokenOfMethod2.contains("RequestId")) {
+                                               tokenOfMethod2 = tokenOfMethod2.replaceAll("RequestId", "long");
+                                       }
+                                       if (tokenOfMethod2.contains("result")) {
+                                               tokenOfMethod2 = tokenOfMethod2.replaceAll("result", "unsigned long");
+                                       }
+                                       if (tokenOfMethod2.contains("UserId")) {
+                                               tokenOfMethod2 = tokenOfMethod2.replaceAll("UserId", "Osp::Base::String");
+                                       }
+                                       if (tokenOfMethod2.contains("xmlChar")) {
+                                               tokenOfMethod2 = tokenOfMethod2.replaceAll("xmlChar", "unsigned char");
+                                       }
+                                       if (tokenOfMethod2.contains("byte")) {
+                                               tokenOfMethod2 = tokenOfMethod2.replaceAll("byte", "unsigned char");
+                                       }
+                                       if (tokenOfMethod2.contains("unsigned ")) {
+                                               tokenOfMethod2 = tokenOfMethod2.replaceAll("unsigned ", "unsigned");
+                                       }
+                                       if (tokenOfMethod2.contains("long long")) {
+                                               tokenOfMethod2 = tokenOfMethod2.replaceAll("long long", "longlong");
+                                       }
+                                       /* handling defined type end */
+                                       htmlLineString = tokenOfMethod1 + tokenOfMethod2 + tokenOfMethod3;
+                               }
+                               if (isMethodOfClass == false) {
+                                       htmlLineString = htmlLineString.replaceAll("=0", "");
+                               }
+                               if (htmlLineString.indexOf(bindingStringMethod[0]) == 0) { /* method name in HTML file and method[0] variable are same */
+                                       if (bindingStringMethod.length != isWhereTemp) { /* method has parameter variable */
+                                               if ( (bindingStringMethod.length == isWhereTemp + 1) && (bindingStringMethod[1].equals("void")) && (htmlLineString.contains("(void")) ) { /* method has void parameter variable */
+                                                       htmlFile = htmlLine.substring(htmlLine.indexOf("href") + 6, htmlLine.indexOf("\"", htmlLine.indexOf("href") + 6));
+                                                       return htmlFile;
+                                               }
+                                               htmlLineString = htmlLineString.substring(htmlLineString.indexOf("(") + 1, htmlLineString.indexOf(")"));
+                                               String htmlLineStringMethod[] = tokenizeStringWithDelimiter(htmlLineString, ", ");
+                                               if ( ( (bindingStringMethod.length - isWhereTemp) * 2 ) == htmlLineStringMethod.length ) { /* the number of parameter variable of method in HTML file and the number of parameter variable of method are same */
+                                                       if (binding.toString().contains("enum {")) {
+                                                               htmlFile = htmlLine.substring(htmlLine.indexOf("href") + 6, htmlLine.indexOf("\"", htmlLine.indexOf("href") + 6));
+                                                               return htmlFile;
+                                                       }
+                                                       if (binding.getOwner().toString().contains("CPP_CLASS_INSTANCE")) {
+                                                               htmlFile = htmlLine.substring(htmlLine.indexOf("href") + 6, htmlLine.indexOf("\"", htmlLine.indexOf("href") + 6));
+                                                               return htmlFile;
+                                                       }
+                                                       for (int i = 0; i < bindingStringMethod.length - 1; i++) {
+                                                               if ( !bindingStringMethod[i + 1].equals(htmlLineStringMethod[i * 2]) ) {
+                                                                       isSame = false;
+                                                                       break;
+                                                               }
+                                                               if (isSame == true) {
+                                                                       htmlFile = htmlLine.substring(htmlLine.indexOf("href") + 6, htmlLine.indexOf("\"", htmlLine.indexOf("href") + 6));
+                                                                       return htmlFile;
+                                                               }
+                                                       }
+                                               }
+                                       } else if (bindingStringMethod.length == isWhereTemp) { /* method doesn't have parameter variable */
+                                               htmlFile = htmlLine.substring(htmlLine.indexOf("href") + 6, htmlLine.indexOf("\"", htmlLine.indexOf("href") + 6));
+                                               return htmlFile;
+                                       }
+                               }
+                       }
+                       
+                       return null;
+               }
+               /**
+                * Find location of method of class in HTML file, if mouseover event occurs in header file.
+                * 
+                * @param htmlLine  1 line of HTML file
+                * @param binding  IBinding
+                * @return location of method of class in HTML file
+                * @throws DOMException, IOExceptio
+                */
+               private String searchMethod(String htmlLine, IBinding binding) throws DOMException, IOException {
+                       String stringOfOwner = binding.getOwner().toString();
+                       String htmlFileName = null;
+                       boolean isExist = false;
+
+                       if (htmlLine.contains("class=\"el\"") == true) {
+                               if (htmlLine.contains(">" + stringOfOwner + "<")) {
+                                       int beginIndex = htmlLine.indexOf("\">", htmlLine.indexOf(">" + stringOfOwner + "<") + stringOfOwner.length() + 4);
+                                       int endIndex = htmlLine.indexOf("<", beginIndex);
+                                       String namespace = htmlLine.substring(beginIndex + 2, endIndex);
+                                       if (checkIsInterface(stringOfOwner) == false) {
+                                               htmlFileName = "class" + namespace.replaceAll("::", "_1_1") +"_1_1" + stringOfOwner + "-members.html";
+                                               
+                                               isExist = checkHTMLFileExistence(htmlFileName); /* check HTML file existence */
+
+                                               if (isExist == true) {
+                                                       BufferedReader reader = new BufferedReader(new FileReader(doxygenDirectoryPath + "/" + htmlFileName));
+                                                       String tempString = null;
+                                                       String htmlFileName2 = null;
+                                                       while ( (tempString = reader.readLine()) != null) {
+                                                               if ( (htmlFileName2 = searchMethodLocationOfClass(tempString, binding, methodInHeader, true)) != null) {
+                                                                       break;
+                                                               }
+                                                       }
+                                                       reader.close();
+                                                       htmlFileName = htmlFileName2;
+                                               }
+
+                                               return htmlFileName;
+                                       } else if (checkIsInterface(stringOfOwner) == true) {
+                                               htmlFileName = "interface" + namespace.replaceAll("::", "_1_1") +"_1_1" + stringOfOwner + "-members.html";
+
+                                               isExist = checkHTMLFileExistence(htmlFileName); /* check HTML file existence */
+
+                                               if (isExist == true) {
+                                                       BufferedReader reader = new BufferedReader(new FileReader(doxygenDirectoryPath + "/" + htmlFileName));
+                                                       String tempString = null;
+                                                       String htmlFileName2 = null;
+                                                       while ( (tempString = reader.readLine()) != null) {
+                                                               if ( (htmlFileName2 = searchMethodLocationOfClass(tempString, binding, methodInHeader, false)) != null) {
+                                                                       break;
+                                                               }
+                                                       }
+                                                       reader.close();
+                                                       htmlFileName = htmlFileName2;
+                                               }
+
+                                               return htmlFileName;
+                                       }
+                               }
+                       }
+
+                       return null;
+               }
+               /**
+                * Check is owner a interface or a class.
+                * 
+                * @param owner  string of owner
+                * @return true if interface, false if class
+                */
+               private boolean checkIsInterface(String owner) {
+                       boolean isInterface = false;
+                       if (owner.substring(0, 1).equals("I")) {
+                               if (Character.isUpperCase(owner.charAt(1)) == true) {
+                                       isInterface = true;
+                               } else if (Character.isUpperCase(owner.charAt(1)) == false) {
+                                       isInterface = false;
+                               }
+                       } else if (!owner.substring(0, 1).equals("I")) {
+                               isInterface = false;
+                       }
+
+                       return isInterface;
+               }
+               /**
+                * Check is owner a interface or a class.
+                * 
+                * @param owner  string array of owner
+                * @return true if interface, false if class
+                */
+               private boolean checkIsInterface(String[] owner) {
+                       boolean isInterface = false;
+                       if (owner[owner.length - 1].substring(0, 1).equals("I")) {
+                               if (Character.isUpperCase(owner[owner.length - 1].charAt(1)) == true) {
+                                       isInterface = true;
+                               } else if (Character.isUpperCase(owner[owner.length - 1].charAt(1)) == false) {
+                                       isInterface = false;
+                               }
+                       } else if (!owner[owner.length - 1].substring(0, 1).equals("I")) {
+                               isInterface = false;
+                       }
+
+                       return isInterface;
+               }
+               /**
+                * Find location of enumerator in HTML file.
+                * 
+                * @param htmlFileName  name of HTML file
+                * @param binding  IBinding
+                * @param isWhere  methodInSource if enumerator is in source file, methodInHeader if enumerator is in header file
+                * @return location of enumerator in HTML file
+                * @throws IOException 
+                */
+               private String searchEnumerator(String htmlFileName, IBinding binding, int isWhere) throws IOException {
+                       String enumeratorName = null;
+                       if (isWhere == methodInSource) {
+                               enumeratorName = tokenizeString(binding.toString())[0];
+                       } else if (isWhere == methodInHeader) {
+                               enumeratorName = binding.getName();
+                       }
+
+                       boolean isExist = false;
+
+                       isExist = checkHTMLFileExistence(htmlFileName); /* check HTML file existence */
+
+                       if (isExist == true) {
+                               BufferedReader reader = new BufferedReader(new FileReader(doxygenDirectoryPath + "/" + htmlFileName));
+                               String htmlLine = null;
+                               String htmlFileName2 = null;
+                               while ( (htmlLine = reader.readLine()) != null) {
+                                       if (htmlLine.contains(enumeratorName)) {
+                                               htmlLine = reader.readLine();
+                                               htmlFileName2 = htmlLine.substring(htmlLine.indexOf("href") + 6, htmlLine.indexOf("\"", htmlLine.indexOf("href") + 6));
+                                               break;
+                                       }
+                               }
+                               reader.close();
+                               htmlFileName = htmlFileName2;
+                       } else if (isExist == false) {
+                               return null;
+                       }
+
+                       return htmlFileName;
+               }
+               /**
+                * Find location of enumeration in HTML file.
+                * 
+                * @param htmlFileName  name of HTML file
+                * @param binding  IBinding
+                * @return location of enumeration in HTML file
+                * @throws IOException 
+                */
+               private String searchEnumeration(String htmlFileName, IBinding binding) throws IOException {
+                       String enumerationName = null;
+                       enumerationName = binding.getName();
+
+                       boolean isExist = false;
+
+                       isExist = checkHTMLFileExistence(htmlFileName); /* check HTML file existence */
+
+                       if (isExist == true) {
+                               BufferedReader reader = new BufferedReader(new FileReader(doxygenDirectoryPath + "/" + htmlFileName));
+                               String htmlLine = null;
+                               String htmlFileName2 = null;
+                               while ( (htmlLine = reader.readLine()) != null) {
+                                       if (htmlLine.contains(enumerationName)) {
+                                               htmlLine = reader.readLine();
+                                               htmlFileName2 = htmlLine.substring(htmlLine.indexOf("href") + 6, htmlLine.indexOf("\"", htmlLine.indexOf("href") + 6));
+                                               break;
+                                       }
+                               }
+                               reader.close();
+                               htmlFileName = htmlFileName2;
+                       } else if (isExist == false) {
+                               return null;
+                       }
+
+                       return htmlFileName;
+               }
+
+               /*
+                * @see org.eclipse.cdt.internal.core.model.ASTCache.ASTRunnable#runOnAST(org.eclipse.cdt.core.dom.ast.IASTTranslationUnit)
+                */
+               public IStatus runOnAST(ILanguage lang, IASTTranslationUnit ast) {
+                       if (ast != null) {
+                               try {
+                                       IASTName name= ast.getNodeSelector(null).findEnclosingName(fTextRegion.getOffset(), fTextRegion.getLength());
+                                       if (name != null) {
+                                               IBinding binding= name.resolveBinding();
+
+                                               if (binding != null) {
+                                                       String htmlFileName = null;
+                                                       boolean isExist = false;
+
+                                                       if (binding.getOwner() == null) {
+                                                               String stringOfBinding[] = tokenizeString(binding.toString());
+                                                               if (stringOfBinding.length == 2) { /* Case 1-1. using root namespace in source file */
+                                                                       if (stringOfBinding[0].equals("Osp") && stringOfBinding[1].equals("CPPNAMESPACE")) {
+                                                                               htmlFileName = "namespaceOsp.html";
+                                                                               isExist = checkHTMLFileExistence(htmlFileName);
+                                                                       }
+                                                               } else if (stringOfBinding.length == 1) {  /* Case 1-2. declaration root namespace in header or source file */
+                                                                       if (stringOfBinding[0].equals("Osp")) {
+                                                                               htmlFileName = "namespaceOsp.html";
+                                                                               isExist = checkHTMLFileExistence(htmlFileName);
+                                                                       }
+                                                               }
+                                                       } else if (binding.getOwner() != null) {
+                                                               String stringOfOwner[] = tokenizeString(binding.getOwner().toString());
+                                                               if (stringOfOwner.length == 3) {
+                                                                       if (stringOfOwner[2].equals("CPPENUMERATION")) {
+                                                                               String stringOfBinding[] = tokenizeString(binding.toString());
+                                                                               if (stringOfBinding[1].equals("CPPENUMERATOR")) { /* Case 2-0. enumerator in source file */
+                                                                                       char firstChar = stringOfBinding[0].charAt(0);
+                                                                                       if (firstChar == 'A') {
+                                                                                               htmlFileName = "namespacemembers_eval.html";
+                                                                                       } else {
+                                                                                               for (int i = 66; i < 91; i++) {
+                                                                                                       if ((int)firstChar == i) {
+                                                                                                               htmlFileName = "namespacemembers_eval_0x" + Integer.toHexString(i + 32) + ".html";
+                                                                                                       }
+                                                                                               }
+                                                                                       }
+
+                                                                                       String htmlFileName2 = null;
+                                                                                       if ( (htmlFileName2 = searchEnumerator(htmlFileName, binding, methodInSource)) != null) {
+                                                                                               isExist = true;
+                                                                                               htmlFileName = htmlFileName2;
+                                                                                       }
+                                                                               }
+                                                                       }
+                                                               } else if (stringOfOwner.length == 2) {
+                                                                       if (stringOfOwner[1].equals("CPPNAMESPACE")) {
+                                                                               String stringOfBinding[] = tokenizeString(binding.toString());
+                                                                               if (stringOfBinding[1].equals("CPPNAMESPACE")) { /* Case 2-1-1. using namespace in source file */
+                                                                                       htmlFileName = "namespace" + tokenizeString(binding.toString())[0].replaceAll("::", "_1_1") + ".html";
+                                                                                       isExist = checkHTMLFileExistence(htmlFileName);
+                                                                               } else if (stringOfBinding[1].equals("CPPCLASSTYPE")) { /* Case 2-1-2. class in source file */
+                                                                                       htmlFileName = "class" + stringOfBinding[0].replaceAll("::", "_1_1") + ".html";
+                                                                                       isExist = checkHTMLFileExistence(htmlFileName); /* check HTML file existence */
+                                                                               } else if (stringOfBinding[1].equals("CPP_CLASS_TEMPLATE")) { /* Case 2-1-3. class template in source file */
+                                                                                       htmlFileName = "class" + stringOfBinding[0].replaceAll("::", "_1_1") + ".html";
+                                                                                       isExist = checkHTMLFileExistence(htmlFileName); /* check HTML file existence */
+                                                                               } /*else if (stringOfBinding[1].equals("CPPENUMERATOR")) { Case 2-1-4. enumerator in source file
+                                                                                       char firstChar = stringOfBinding[0].charAt(0);
+                                                                                       if (firstChar == 'A') {
+                                                                                               htmlFileName = "namespacemembers_eval.html";
+                                                                                       } else {
+                                                                                               for (int i = 66; i < 91; i++) {
+                                                                                                       if ((int)firstChar == i) {
+                                                                                                               htmlFileName = "namespacemembers_eval_0x" + Integer.toHexString(i + 32) + ".html";
+                                                                                                       }
+                                                                                               }
+                                                                                       }
+
+                                                                                       String htmlFileName2 = null;
+                                                                                       if ( (htmlFileName2 = searchEnumerator(htmlFileName, binding, methodInSource)) != null) {
+                                                                                               isExist = true;
+                                                                                               htmlFileName = htmlFileName2;
+                                                                                       }
+                                                                               }*/ else if (stringOfBinding.length == 3 && stringOfBinding[2].equals("CPPENUMERATION")) { /* Case 2-1-5. enumeration used as parameter variable in header file */
+                                                                                       char firstChar = stringOfBinding[1].charAt(0);
+                                                                                       if (firstChar == 'A') {
+                                                                                               htmlFileName = "namespacemembers_enum.html";
+                                                                                       } else {
+                                                                                               for (int i = 66; i < 91; i++) {
+                                                                                                       if ((int)firstChar == i) {
+                                                                                                               htmlFileName = "namespacemembers_enum_0x" + Integer.toHexString(i + 32) + ".html";
+                                                                                                       }
+                                                                                               }
+                                                                                       }
+
+                                                                                       String htmlFileName2 = null;
+                                                                                       if ( (htmlFileName2 = searchEnumeration(htmlFileName, binding)) != null) {
+                                                                                               isExist = true;
+                                                                                               htmlFileName = htmlFileName2;
+                                                                                       }
+                                                                               } else if (binding.toString().contains("CPPTYPEDEF") && binding.toString().contains("enum")) { /* Case 2-1-6. typedef enumeration used as parameter variable in header file */
+                                                                                       char firstChar = stringOfBinding[0].charAt(0);
+                                                                                       if (firstChar == 'A') {
+                                                                                               htmlFileName = "namespacemembers_enum.html";
+                                                                                       } else {
+                                                                                               for (int i = 66; i < 91; i++) {
+                                                                                                       if ((int)firstChar == i) {
+                                                                                                               htmlFileName = "namespacemembers_enum_0x" + Integer.toHexString(i + 32) + ".html";
+                                                                                                       }
+                                                                                               }
+                                                                                       }
+
+                                                                                       String htmlFileName2 = null;
+                                                                                       if ( (htmlFileName2 = searchEnumeration(htmlFileName, binding)) != null) {
+                                                                                               isExist = true;
+                                                                                               htmlFileName = htmlFileName2;
+                                                                                       }
+                                                                               }
+                                                                       } else if (stringOfOwner[1].equals("CPPCLASSTYPE")) { /* Case 2-2. constructor or member method in source file */
+                                                                               String tokenOfStringOfOwner[] = tokenizeStringWithDelimiter(stringOfOwner[0], "::");
+                                                                               if ( checkIsInterface(tokenOfStringOfOwner) == false ) { /* Case 2-2-1. constructor or member method of class in source file */
+                                                                                       htmlFileName = "class" + stringOfOwner[0].replaceAll("::", "_1_1") + "-members.html";
+
+                                                                                       isExist = checkHTMLFileExistence(htmlFileName); /* check HTML file existence */
+
+                                                                                       if (isExist == true) {
+                                                                                               BufferedReader reader = new BufferedReader(new FileReader(doxygenDirectoryPath + "/" + htmlFileName));
+                                                                                               String tempString = null;
+                                                                                               String htmlFileName2 = null;
+                                                                                               while ( (tempString = reader.readLine()) != null) {
+                                                                                                       if ( (htmlFileName2 = searchMethodLocationOfClass(tempString, binding, methodInSource, true)) != null) {
+                                                                                                               break;
+                                                                                                       }
+                                                                                               }
+                                                                                               reader.close();
+                                                                                               htmlFileName = htmlFileName2;
+                                                                                       }
+                                                                               } else if ( checkIsInterface(tokenOfStringOfOwner) == true ) { /* Case 2-2-2. constructor or member method of interface in source file */
+                                                                                       htmlFileName = "interface" + stringOfOwner[0].replaceAll("::", "_1_1") + "-members.html";
+
+                                                                                       isExist = checkHTMLFileExistence(htmlFileName); /* check HTML file existence */
+
+                                                                                       if (isExist == true) {
+                                                                                               BufferedReader reader = new BufferedReader(new FileReader(doxygenDirectoryPath + "/" + htmlFileName));
+                                                                                               String tempString = null;
+                                                                                               String htmlFileName2 = null;
+                                                                                               while ( (tempString = reader.readLine()) != null) {
+                                                                                                       if ( (htmlFileName2 = searchMethodLocationOfClass(tempString, binding, methodInSource, false)) != null) {
+                                                                                                               break;
+                                                                                                       }
+                                                                                               }
+                                                                                               reader.close();
+                                                                                               htmlFileName = htmlFileName2;
+                                                                                       }
+                                                                               }
+                                                                       } else if (stringOfOwner[1].equals("CPP_CLASS_INSTANCE")) { /* Case 2-3. member method with <type> in source file */
+                                                                               String tokenOfStringOfOwner[] = tokenizeStringWithDelimiter(stringOfOwner[0], "::");
+                                                                               if ( checkIsInterface(tokenOfStringOfOwner) == false ) { /* Case 2-3-1. member method with <type> of class in source file */
+                                                                                       String owner = stringOfOwner[0].substring(0, stringOfOwner[0].indexOf("<"));
+                                                                                       htmlFileName = "class" + owner.replaceAll("::", "_1_1") + "-members.html";
+
+                                                                                       isExist = checkHTMLFileExistence(htmlFileName); /* check HTML file existence */
+
+                                                                                       if (isExist == true) {
+                                                                                               BufferedReader reader = new BufferedReader(new FileReader(doxygenDirectoryPath + "/" + htmlFileName));
+                                                                                               String tempString = null;
+                                                                                               String htmlFileName2 = null;
+                                                                                               while ( (tempString = reader.readLine()) != null) {
+                                                                                                       if ( (htmlFileName2 = searchMethodLocationOfClass(tempString, binding, methodInSource, true)) != null) {
+                                                                                                               break;
+                                                                                                       }
+                                                                                               }
+                                                                                               reader.close();
+                                                                                               htmlFileName = htmlFileName2;
+                                                                                       }
+                                                                               } else if ( checkIsInterface(tokenOfStringOfOwner) == true ) { /* Case 2-3-2. member method with <type> of interface in source file */
+                                                                                       String owner = stringOfOwner[0].substring(0, stringOfOwner[0].indexOf("<"));
+                                                                                       htmlFileName = "interface" + owner.replaceAll("::", "_1_1") + "-members.html";
+
+                                                                                       isExist = checkHTMLFileExistence(htmlFileName); /* check HTML file existence */
+
+                                                                                       if (isExist == true) {
+                                                                                               BufferedReader reader = new BufferedReader(new FileReader(doxygenDirectoryPath + "/" + htmlFileName));
+                                                                                               String tempString = null;
+                                                                                               String htmlFileName2 = null;
+                                                                                               while ( (tempString = reader.readLine()) != null) {
+                                                                                                       if ( (htmlFileName2 = searchMethodLocationOfClass(tempString, binding, methodInSource, false)) != null) {
+                                                                                                               break;
+                                                                                                       }
+                                                                                               }
+                                                                                               reader.close();
+                                                                                               htmlFileName = htmlFileName2;
+                                                                                       }
+                                                                               }
+
+                                                                       }
+                                                               } else if (stringOfOwner.length == 1) {
+                                                                       String stringOfClass[] = tokenizeStringWithDelimiter(binding.getClass().toString(), ".");
+                                                                       if ( stringOfClass[stringOfClass.length - 1].equals("CPPNamespace") ) { /* Case 3-1-1. declaration namespace in header or source file */
+                                                                               htmlFileName = "namespace" + binding.toString().replaceAll("::", "_1_1") + ".html";
+                                                                               isExist = checkHTMLFileExistence(htmlFileName); /* check HTML file existence */
+                                                                       } else if ( stringOfClass[stringOfClass.length - 1].equals("CPPClassType") ) { /* Case 3-1-2. class in header file */
+                                                                               htmlFileName = "class" + binding.getOwner().toString().replaceAll("::", "_1_1") + "_1_1" + binding.toString() + ".html";
+                                                                               isExist = checkHTMLFileExistence(htmlFileName); /* check HTML file existence */
+                                                                       } /*else if ( stringOfClass[stringOfClass.length - 1].equals("CPPEnumerator") ) {  Case 3-1-3. enumerator in header file 
+                                                                               char firstChar = binding.getName().charAt(0);
+                                                                               if (firstChar == 'A') {
+                                                                                       htmlFileName = "namespacemembers_eval.html";
+                                                                               } else {
+                                                                                       for (int i = 66; i < 91; i++) {
+                                                                                               if ((int)firstChar == i) {
+                                                                                                       htmlFileName = "namespacemembers_eval_0x" + Integer.toHexString(i + 32) + ".html";
+                                                                                               }
+                                                                                       }
+                                                                               }
+
+                                                                               String htmlFileName2 = null;
+                                                                               if ( (htmlFileName2 = searchEnumerator(htmlFileName, binding, methodInHeader)) != null) {
+                                                                                       isExist = true;
+                                                                                       htmlFileName = htmlFileName2;
+                                                                               }
+                                                                       }*/ else if ( stringOfClass[stringOfClass.length - 1].equals("CPPEnumeration") ) { /* Case 3-1-4. declared enumeration in header file */
+                                                                               char firstChar = binding.getName().charAt(0);
+                                                                               if (firstChar == 'A') {
+                                                                                       htmlFileName = "namespacemembers_enum.html";
+                                                                               } else {
+                                                                                       for (int i = 66; i < 91; i++) {
+                                                                                               if ((int)firstChar == i) {
+                                                                                                       htmlFileName = "namespacemembers_enum_0x" + Integer.toHexString(i + 32) + ".html";
+                                                                                               }
+                                                                                       }
+                                                                               }
+
+                                                                               String htmlFileName2 = null;
+                                                                               if ( (htmlFileName2 = searchEnumeration(htmlFileName, binding)) != null) {
+                                                                                       isExist = true;
+                                                                                       htmlFileName = htmlFileName2;
+                                                                               }
+                                                                       } else if ( stringOfClass[stringOfClass.length - 1].equals("CPPTypedef") ) { /* Case 3-1-5. typedef declared enumeration in header file */
+                                                                               char firstChar = binding.getName().charAt(0);
+                                                                               if (firstChar == 'A') {
+                                                                                       htmlFileName = "namespacemembers_enum.html";
+                                                                               } else {
+                                                                                       for (int i = 66; i < 91; i++) {
+                                                                                               if ((int)firstChar == i) {
+                                                                                                       htmlFileName = "namespacemembers_enum_0x" + Integer.toHexString(i + 32) + ".html";
+                                                                                               }
+                                                                                       }
+                                                                               }
+
+                                                                               String htmlFileName2 = null;
+                                                                               if ( (htmlFileName2 = searchEnumeration(htmlFileName, binding)) != null) {
+                                                                                       isExist = true;
+                                                                                       htmlFileName = htmlFileName2;
+                                                                               }
+                                                                       } else if ( stringOfClass[stringOfClass.length - 1].equals("CPPClassType") || stringOfClass[stringOfClass.length - 1].equals("CPPMethod") ) { /* Case 3-1-6. constructor or member method in header file */
+                                                                               htmlFileName = "classes.html";
+
+                                                                               isExist = checkHTMLFileExistence(htmlFileName); /* check HTML file existence */
+
+                                                                               if (isExist == true) {
+                                                                                       BufferedReader reader = new BufferedReader(new FileReader(doxygenDirectoryPath + "/" + htmlFileName));
+                                                                                       String tempString = null;
+                                                                                       String htmlFileName2 = null;
+                                                                                       while ( (tempString = reader.readLine()) != null) {
+                                                                                               if ( (htmlFileName2 = searchMethod(tempString, binding)) != null) {
+                                                                                                       break;
+                                                                                               }
+                                                                                       }
+                                                                                       reader.close();
+                                                                                       htmlFileName = htmlFileName2;
+                                                                               }
+                                                                       }
+                                                               } else if (stringOfOwner.length == 0) {
+                                                                       String stringOfClass[] = tokenizeStringWithDelimiter(binding.getClass().toString(), ".");
+                                                                       if ( stringOfClass[stringOfClass.length - 1].equals("CPPEnumerator") ) { /* Case 4-1. enumerator in header file */
+                                                                               char firstChar = binding.getName().charAt(0);
+                                                                               if (firstChar == 'A') {
+                                                                                       htmlFileName = "namespacemembers_eval.html";
+                                                                               } else {
+                                                                                       for (int i = 66; i < 91; i++) {
+                                                                                               if ((int)firstChar == i) {
+                                                                                                       htmlFileName = "namespacemembers_eval_0x" + Integer.toHexString(i + 32) + ".html";
+                                                                                               }
+                                                                                       }
+                                                                               }
+
+                                                                               String htmlFileName2 = null;
+                                                                               if ( (htmlFileName2 = searchEnumerator(htmlFileName, binding, methodInHeader)) != null) {
+                                                                                       isExist = true;
+                                                                                       htmlFileName = htmlFileName2;
+                                                                               }
+                                                                       }
+                                                               }
+                                                       }
+
+                                                       if (isExist == true) {
+                                                               fSource = htmlFileName;
+                                                       }
+                                                       /* TODO Modify End */
+
+                                                       if (fSource != null) {
+                                                               return Status.OK_STATUS;
+                                                       }
+                                               }
+                                       }
+                               } catch (DOMException exc) {
+                                       return new Status(IStatus.ERROR, CUIPlugin.PLUGIN_ID, "Internal Error", exc); //$NON-NLS-1$
+                               } catch (Exception e) {
+                                       //
+                               }
+                       }
+                       return Status.CANCEL_STATUS;
+               }
+
+               /**
+                * @return the computed source or <code>null</code>, if no source could be computed
+                */
+               public String getSource() {
+                       return fSource;
+               }
+
        }
 
        /* (non-Javadoc)
@@ -120,6 +1079,125 @@ public class CDocHover extends AbstractCEditorTextHover {
                
                return null;
        }
+       
+       /*
+        * @see ITextHover#getHoverInfo(ITextViewer, IRegion)
+        */
+       @Override
+       public Object getHoverInfo2(ITextViewer textViewer, IRegion hoverRegion) {
+               IEditorPart editor = getEditor();
+               if (editor != null) {
+                       IEditorInput input = editor.getEditorInput();
+                       IWorkingCopyManager manager = CUIPlugin.getDefault().getWorkingCopyManager();
+                       IWorkingCopy copy = manager.getWorkingCopy(input);
+                       try {
+                               if (copy == null || !copy.isConsistent()) {
+                                       return null;
+                               }
+                       } catch (CModelException exc) {
+                               return null;
+                       }
+
+                       String expression;
+                       try {
+                               expression = textViewer.getDocument().get(hoverRegion.getOffset(), hoverRegion.getLength());
+                               expression = expression.trim();
+                               if (expression.length() == 0)
+                                       return null;
+
+                               //Before trying a search lets make sure that the user is not hovering over a keyword 
+                               if (selectionIsKeyword(expression))
+                                       return null;
+
+                               String source = null;
+
+                               // Try with the indexer
+                               source= searchInIndex(copy, hoverRegion);
+
+                               if (source == null || source.trim().length() == 0)
+                                       return null;
+
+                               if (!source.contains(".html")) {
+                                       return null;
+                               }
+
+                               // we are actually interested in the comments, too.
+                               //source= removeLeadingComments(source);
+
+                               String 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(), getTabWidth());
+
+                               if (!Character.isWhitespace(firstLine.charAt(0)))
+                                       sourceLines[0] = firstLine;
+
+                               source = Strings.concatenate(sourceLines, delim);
+
+                               return internalGetHoverInfo(source, hoverRegion);
+                       } catch (BadLocationException e) {
+                       }
+               }
+               return null;
+       }
+
+       private CDocBrowserInformationControlInput internalGetHoverInfo(String elements, IRegion hoverRegion) {
+               return getHoverInfo(elements, null, hoverRegion, null);
+       }
+
+       private static CDocBrowserInformationControlInput getHoverInfo(String elements, String editorInputElement, IRegion hoverRegion, CDocBrowserInformationControlInput previousInput) {
+               int leadingImageWidth = 20;
+               return new CDocBrowserInformationControlInput(previousInput, elements, elements, leadingImageWidth);
+       }
+
+       private static int getTabWidth() {
+               return 4;
+       }
+
+       private String searchInIndex(final ITranslationUnit tUnit, IRegion textRegion) {
+               final ComputeSourceRunnable computer= new ComputeSourceRunnable(tUnit, textRegion);
+               Job job= new Job(CHoverMessages.CSourceHover_jobTitle) {
+                       @Override
+                       protected IStatus run(IProgressMonitor monitor) {
+                               try {
+                                       return ASTProvider.getASTProvider().runOnAST(tUnit, ASTProvider.WAIT_ACTIVE_ONLY, monitor, computer);
+                               } catch (Throwable t) {
+                                       CUIPlugin.log(t);
+                               }
+                               return Status.CANCEL_STATUS;
+                       }
+               };
+               // If the hover thread is interrupted this might have negative
+               // effects on the index - see http://bugs.eclipse.org/219834
+               // Therefore we schedule a job to decouple the parsing from this thread.
+               job.setPriority(Job.DECORATE);
+               job.setSystem(true);
+               job.setRule(SingletonRule.INSTANCE);
+               job.schedule();
+               try {
+                       job.join();
+               } catch (InterruptedException exc) {
+                       job.cancel();
+                       return null;
+               }
+               return computer.getSource();
+       }
+
+
+       /**
+        * Test whether the given name is a known keyword.
+        * 
+        * @param name
+        * @return <code>true</code> if the name is a known keyword or <code>false</code> if the
+        *         name is not considered a keyword
+        */
+       private boolean selectionIsKeyword(String name) {
+               Set<String> keywords = ParserFactory.getKeywordSet(KeywordSetKey.KEYWORDS, ParserLanguage.CPP);
+               return keywords.contains(name);
+       }
 
        /* (non-Javadoc)
         * @see org.eclipse.jface.text.ITextHover#getHoverRegion(org.eclipse.jface.text.ITextViewer, int)
@@ -138,5 +1216,378 @@ public class CDocHover extends AbstractCEditorTextHover {
                }
                return null;
        }
-       
+
+       /*
+        * @see org.eclipse.jface.text.ITextHoverExtension2#getInformationPresenterControlCreator()
+        * @since 3.1
+        */
+       public IInformationControlCreator getInformationPresenterControlCreator() {
+               if (fPresenterControlCreator == null)
+                       fPresenterControlCreator = new PresenterControlCreator(getSite());
+               return fPresenterControlCreator;
+       }
+
+       private IWorkbenchSite getSite() {
+               IEditorPart editor= getEditor();
+               if (editor != null)
+                       return editor.getSite();
+
+               return null;
+       }
+
+       /*
+        * @see org.eclipse.jface.text.ITextHoverExtension#getHoverControlCreator()
+        * @since 3.0
+        */
+       @Override
+       public IInformationControlCreator getHoverControlCreator() {
+               if (fHoverControlCreator == null)
+                       fHoverControlCreator = new HoverControlCreator(getInformationPresenterControlCreator());
+               return fHoverControlCreator;
+       }
+
+       private static void addLinkListener(final CDocBrowserInformationControl control) {
+               control.addLocationListener(CElementLinks.createLocationListener(new CElementLinks.ILinkHandler() {
+                       /* (non-Javadoc)
+                        * @see org.eclipse.jdt.internal.ui.viewsupport.JavaElementLinks.ILinkHandler#handleInlineJavadocLink(org.eclipse.jdt.core.IJavaElement)
+                        */
+                       public void handleInlineCDocLink(String linkTarget) {
+                               CDocBrowserInformationControlInput hoverInfo = getHoverInfo(linkTarget, null, null, (CDocBrowserInformationControlInput) control.getInput());
+                               if (control.hasDelayedInputChangeListener()) {
+                                       control.notifyDelayedInputChange(hoverInfo);
+                               } else {
+                                       control.setInput(hoverInfo);
+                               }
+                       }
+
+                       public void handleTextSet() {
+                       }
+               }));
+       }
+
+       /**
+        * Get element name of back or forward action.
+        * 
+        * @param htmlName  HTML name
+        * @return element name
+        */
+       private static String getBackForwardElementName(String htmlName) {
+               String elementName = "";
+               try {
+                       if (htmlName.equals("namespaceOsp.html")) {
+                               elementName = "Osp";
+                       } else if (htmlName.equals("privlevel.html")) {
+                               elementName = "Privilege Level";
+                       } else if (htmlName.equals("privgroup.html")) {
+                               elementName = "Privilege Group";
+                       } else if (htmlName.contains("_1_1")) {
+                               if (!htmlName.contains("#")) {
+                                       elementName = htmlName.substring(htmlName.lastIndexOf("_1_1") + 4, htmlName.lastIndexOf(".html"));
+                               } else if (htmlName.contains("#_details")) {
+                                       elementName = "Detailed Description";
+                               } else if (htmlName.contains("#")) {
+                                       String htmlFileName = htmlName.substring(0, htmlName.lastIndexOf("#"));
+
+                                       File file = new File(doxygenDirectoryPath);
+                                       File fileList[] = file.listFiles();
+                                       BufferedReader reader = null;
+                                       for (int i = 0; i < fileList.length; i++) {
+                                               if (htmlFileName.equals(fileList[i].getName())) {
+                                                       reader = new BufferedReader(new FileReader(doxygenDirectoryPath + "/" + htmlFileName));
+                                                       String tempString = null;
+                                                       while ( (tempString = reader.readLine()) != null) {
+                                                               if (tempString.contains(htmlName)) {
+                                                                       int startIndex = tempString.indexOf(">", tempString.indexOf(htmlName)) + 1;
+                                                                       int endIndex = tempString.indexOf("</a>", startIndex);
+                                                                       elementName = tempString.substring(startIndex, endIndex);
+                                                                       break;
+                                                               }
+                                                       }
+                                               }
+                                       }
+                                       reader.close();
+                               }
+                       } else if (!htmlName.contains("_1_1")) {
+                               elementName = htmlName.substring(0, htmlName.indexOf(".html"));
+                               if (!htmlName.contains("#")) {
+                                       File file = new File(doxygenDirectoryPath);
+                                       File fileList[] = file.listFiles();
+                                       BufferedReader reader = null;
+                                       for (int i = 0; i < fileList.length; i++) {
+                                               reader = new BufferedReader(new FileReader(doxygenDirectoryPath + "/" + htmlName));
+                                               String tempString = null;
+                                               while ( (tempString = reader.readLine()) != null) {
+                                                       if (tempString.contains("h1")) {
+                                                               int startIndex = tempString.indexOf("h1") + 3;
+                                                               int endIndex = tempString.indexOf("<", startIndex);
+                                                               elementName = tempString.substring(startIndex, endIndex);
+                                                               break;
+                                                       }
+                                               }
+                                       }
+                                       reader.close();
+                               } else if (htmlName.contains("#")) {
+                                       String htmlFileName = htmlName.substring(0, htmlName.lastIndexOf("#"));
+                                       String htmlName2 = htmlName.substring(htmlName.indexOf("#"), htmlName.length());
+                                       boolean isSearchFail = false;
+
+                                       File file = new File(doxygenDirectoryPath);
+                                       File fileList[] = file.listFiles();
+                                       BufferedReader reader = null;
+                                       for (int i = 0; i < fileList.length; i++) {
+                                               if (htmlFileName.equals(fileList[i].getName())) {
+                                                       reader = new BufferedReader(new FileReader(doxygenDirectoryPath + "/" + htmlFileName));
+                                                       String tempString = null;
+                                                       while ( (tempString = reader.readLine()) != null) {
+                                                               if (tempString.contains(htmlName)) {
+                                                                       int startIndex = tempString.indexOf(">", tempString.indexOf(htmlName)) + 1;
+                                                                       int endIndex = tempString.indexOf("</a>", startIndex);
+                                                                       elementName = tempString.substring(startIndex, endIndex);
+                                                                       isSearchFail = true;
+                                                                       break;
+                                                               }
+                                                               if (isSearchFail == false) {
+                                                                       if (tempString.contains(htmlName2)) {
+                                                                               int startIndex = tempString.indexOf(">", tempString.indexOf(htmlName2)) + 1;
+                                                                               int endIndex = tempString.indexOf("</a>", startIndex);
+                                                                               elementName = tempString.substring(startIndex, endIndex);
+                                                                               break;
+                                                                       }
+                                                               }
+                                                       }
+                                               }
+                                       }
+                                       reader.close();
+
+                                       if (elementName.contains("<span>")) {
+                                               elementName = elementName.replaceAll("<span>", "");
+                                       }
+                                       if (elementName.contains("</span>")) {
+                                               elementName = elementName.replaceAll("</span>", "");
+                                       }
+                               }
+                       }
+               } catch (IOException e) {
+                       //
+               } catch (Exception e) {
+                       //
+               }
+               return elementName;
+       }
+
+       /**
+        * Action to go back to the previous input in the hover control.
+        *
+        * @since 3.4
+        */
+       private static final class BackAction extends Action {
+               private final CDocBrowserInformationControl fInfoControl;
+
+               public BackAction(CDocBrowserInformationControl infoControl) {
+                       fInfoControl= infoControl;
+                       setText(CHoverMessages.CDocHover_back);
+                       ISharedImages images = PlatformUI.getWorkbench().getSharedImages();
+                       setImageDescriptor(images.getImageDescriptor(ISharedImages.IMG_TOOL_BACK));
+                       setDisabledImageDescriptor(images.getImageDescriptor(ISharedImages.IMG_TOOL_BACK_DISABLED));
+
+                       update();
+               }
+
+               public void run() {
+                       BrowserInformationControlInput previous = (BrowserInformationControlInput) fInfoControl.getInput().getPrevious();
+                       if (previous != null) {
+                               fInfoControl.setInput(previous);
+                       }
+               }
+
+               public void update() {
+                       BrowserInformationControlInput current = fInfoControl.getInput();
+
+                       if (current != null && current.getPrevious() != null) {
+                               BrowserInput previous = current.getPrevious();
+                               setToolTipText("Back to " + getBackForwardElementName(previous.toString()));
+                               setEnabled(true);
+                       } else {
+                               setToolTipText(CHoverMessages.CDocHover_back);
+                               setEnabled(false);
+                       }
+               }
+       }
+
+       /**
+        * Action to go forward to the next input in the hover control.
+        *
+        * @since 3.4
+        */
+       private static final class ForwardAction extends Action {
+               private final CDocBrowserInformationControl fInfoControl;
+
+               public ForwardAction(CDocBrowserInformationControl infoControl) {
+                       fInfoControl = infoControl;
+                       setText(CHoverMessages.CDocHover_forward);
+                       ISharedImages images = PlatformUI.getWorkbench().getSharedImages();
+                       setImageDescriptor(images.getImageDescriptor(ISharedImages.IMG_TOOL_FORWARD));
+                       setDisabledImageDescriptor(images.getImageDescriptor(ISharedImages.IMG_TOOL_FORWARD_DISABLED));
+
+                       update();
+               }
+
+               public void run() {
+                       BrowserInformationControlInput next = (BrowserInformationControlInput) fInfoControl.getInput().getNext();
+                       if (next != null) {
+                               fInfoControl.setInput(next);
+                       }
+               }
+
+               public void update() {
+                       BrowserInformationControlInput current = fInfoControl.getInput();
+
+                       if (current != null && current.getNext() != null) {
+                               setToolTipText("Forward to " + getBackForwardElementName(current.getNext().toString()));
+                               setEnabled(true);
+                       } else {
+                               setToolTipText(CHoverMessages.CDocHover_forward);
+                               setEnabled(false);
+                       }
+               }
+       }
+
+       /**
+        * Presenter control creator.
+        *
+        * @since 3.3
+        */
+       public static final class PresenterControlCreator extends AbstractReusableInformationControlCreator {
+
+               private IWorkbenchSite fSite;
+
+               /**
+                * Creates a new PresenterControlCreator.
+                * 
+                * @param site the site or <code>null</code> if none
+                * @since 3.6
+                */
+               public PresenterControlCreator(IWorkbenchSite site) {
+                       fSite = site;
+               }
+
+               /*
+                * @see org.eclipse.jdt.internal.ui.text.java.hover.AbstractReusableInformationControlCreator#doCreateInformationControl(org.eclipse.swt.widgets.Shell)
+                */
+               public IInformationControl doCreateInformationControl(Shell parent) {
+                       if (CDocBrowserInformationControl.isAvailable(parent)) {
+                               ToolBarManager tbm = new ToolBarManager(SWT.FLAT);
+                               String font = PreferenceConstants.EDITOR_TEXT_FONT;
+                               CDocBrowserInformationControl iControl = new CDocBrowserInformationControl(parent, font, tbm);
+
+                               final BackAction backAction = new BackAction(iControl);
+                               backAction.setEnabled(false);
+                               tbm.add(backAction);
+                               final ForwardAction forwardAction = new ForwardAction(iControl);
+                               tbm.add(forwardAction);
+                               forwardAction.setEnabled(false);
+
+                               IInputChangedListener inputChangeListener= new IInputChangedListener() {
+                                       public void inputChanged(Object newInput) {
+                                               backAction.update();
+                                               forwardAction.update();
+                                       }
+                               };
+                               iControl.addInputChangeListener(inputChangeListener);
+
+                               tbm.update(true);
+
+                               addLinkListener(iControl);
+                               return iControl;
+
+                       } else {
+                               return new DefaultInformationControl(parent, true);
+                       }
+               }
+       }
+
+       /**
+        * Hover control creator.
+        *
+        * @since 3.3
+        */
+       public static final class HoverControlCreator extends AbstractReusableInformationControlCreator {
+               /**
+                * The information presenter control creator.
+                * @since 3.4
+                */
+               private final IInformationControlCreator fInformationPresenterControlCreator;
+               /**
+                * <code>true</code> to use the additional info affordance, <code>false</code> to use the hover affordance.
+                */
+               private final boolean fAdditionalInfoAffordance;
+
+               /**
+                * @param informationPresenterControlCreator control creator for enriched hover
+                * @since 3.4
+                */
+               public HoverControlCreator(IInformationControlCreator informationPresenterControlCreator) {
+                       this(informationPresenterControlCreator, false);
+               }
+
+               /**
+                * @param informationPresenterControlCreator control creator for enriched hover
+                * @param additionalInfoAffordance <code>true</code> to use the additional info affordance, <code>false</code> to use the hover affordance
+                * @since 3.4
+                */
+               public HoverControlCreator(IInformationControlCreator informationPresenterControlCreator, boolean additionalInfoAffordance) {
+                       fInformationPresenterControlCreator = informationPresenterControlCreator;
+                       fAdditionalInfoAffordance = additionalInfoAffordance;
+               }
+
+               /*
+                * @see org.eclipse.jdt.internal.ui.text.java.hover.AbstractReusableInformationControlCreator#doCreateInformationControl(org.eclipse.swt.widgets.Shell)
+                */
+               public IInformationControl doCreateInformationControl(Shell parent) {
+                       String tooltipAffordanceString = fAdditionalInfoAffordance ? "showTextHoverAffordance" : EditorsUI.getTooltipAffordanceString();
+                       if (CDocBrowserInformationControl.isAvailable(parent)) {
+                               String font= PreferenceConstants.EDITOR_TEXT_FONT;
+                               CDocBrowserInformationControl iControl = new CDocBrowserInformationControl(parent, font, tooltipAffordanceString) {
+                                       /*
+                                        * @see org.eclipse.jface.text.IInformationControlExtension5#getInformationPresenterControlCreator()
+                                        */
+                                       public IInformationControlCreator getInformationPresenterControlCreator() {
+                                               return fInformationPresenterControlCreator;
+                                       }
+                               };
+                               addLinkListener(iControl);
+                               return iControl;
+                       } else {
+                               return new DefaultInformationControl(parent, tooltipAffordanceString);
+                       }
+               }
+
+               /*
+                * @see org.eclipse.jdt.internal.ui.text.java.hover.AbstractReusableInformationControlCreator#canReuse(org.eclipse.jface.text.IInformationControl)
+                */
+               public boolean canReuse(IInformationControl control) {
+                       if (!super.canReuse(control))
+                               return false;
+
+                       if (control instanceof IInformationControlExtension4) {
+                               String tooltipAffordanceString = fAdditionalInfoAffordance ? "showTextHoverAffordance" : EditorsUI.getTooltipAffordanceString();
+                               ((IInformationControlExtension4)control).setStatusText(tooltipAffordanceString);
+                       }
+
+                       return true;
+               }
+       }
+
+       /**
+        * The hover control creator.
+        *
+        * @since 3.2
+        */
+       private IInformationControlCreator fHoverControlCreator;
+       /**
+        * The presentation control creator.
+        *
+        * @since 3.2
+        */
+       private IInformationControlCreator fPresenterControlCreator;
 }
diff --git a/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CElementLinks.java b/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/c/hover/CElementLinks.java
new file mode 100644 (file)
index 0000000..4430dc1
--- /dev/null
@@ -0,0 +1,100 @@
+package org.eclipse.cdt.internal.ui.text.c.hover;
+
+import java.io.File;
+import java.net.URI;
+import java.net.URISyntaxException;
+
+import org.eclipse.swt.browser.Browser;
+import org.eclipse.swt.browser.LocationAdapter;
+import org.eclipse.swt.browser.LocationEvent;
+import org.eclipse.swt.browser.LocationListener;
+
+/**
+ * Links inside doxygen hovers.
+ */
+public class CElementLinks {
+       /**
+        * A handler is asked to handle links to targets.
+        */
+       public interface ILinkHandler {
+
+               /**
+                * Handle normal kind of link to given target.
+                *
+                * @param target the target to show
+                */
+               void handleInlineCDocLink(String target);
+
+               /**
+                * Informs the handler that the text of the browser was set.
+                */
+               void handleTextSet();
+       }
+
+       public static final String CDOC_SCHEME= "file"; //$NON-NLS-1$
+       public static int isSet = 0;
+
+       private CElementLinks() {
+               // static only
+       }
+
+       /**
+        * Creates a location listener which uses the given handler
+        * to handle java element links.
+        *
+        * The location listener can be attached to a {@link Browser}
+        *
+        * @param handler the handler to use to handle links
+        * @return a new {@link LocationListener}
+        */
+       public static LocationListener createLocationListener(final ILinkHandler handler) {
+               return new LocationAdapter() {
+                       public void changing(LocationEvent event) {
+                               String loc = event.location;
+                               if (CElementLinks.isSet == 1) {
+                                       CElementLinks.isSet = 0;
+                                       return;
+                               }
+
+                               if ("about:blank".equals(loc)) { //$NON-NLS-1$
+                                       /*
+                                        * Using the Browser.setText API triggers a location change to "about:blank".
+                                        * XXX: remove this code once https://bugs.eclipse.org/bugs/show_bug.cgi?id=130314 is fixed
+                                        */
+                                       //input set with setText
+                                       handler.handleTextSet();
+                                       return;
+                               }
+
+                               event.doit= false;
+
+                               if (loc.startsWith("about:")) { //$NON-NLS-1$
+                                       // Relative links should be handled via head > base tag.
+                                       // If no base is available, links just won't work.
+                                       return;
+                               }
+
+                               URI uri;
+                               try {
+                                       uri= new URI(loc);
+                               } catch (URISyntaxException e) {
+                                       // try it with a file (workaround for https://bugs.eclipse.org/bugs/show_bug.cgi?id=237903 ):
+                                       File file= new File(loc);
+                                       if (!file.exists()) {
+                                               //JavaPlugin.log(e);
+                                               return;
+                                       }
+                                       uri = file.toURI();
+                                       loc = uri.toASCIIString();
+                               }
+
+                               String scheme = uri.getScheme();
+                               if (CElementLinks.CDOC_SCHEME.equals(scheme)) {
+                                       String uriString = uri.toString();
+                                       handler.handleInlineCDocLink(uriString.substring(uriString.lastIndexOf("/") + 1, uriString.length()));
+                                       event.doit= true;
+                               }
+                       }
+               };
+       }
+}
index 9838be3..6f63c01 100644 (file)
@@ -33,6 +33,9 @@ public final class CHoverMessages extends NLS {
 
        public static String CSourceHover_jobTitle;
 
+       public static String CDocHover_back;
+       public static String CDocHover_forward;
+
        static {
                NLS.initializeMessages(CHoverMessages.class.getName(), CHoverMessages.class);
        }
index cb14e7a..b44e269 100644 (file)
@@ -26,3 +26,6 @@ CMacroExpansionControl_title_original=Original
 CMacroExpansionInput_jobTitle= Computing Macro Expansion
 
 CSourceHover_jobTitle= Computing Source
+
+CDocHover_back=Back
+CDocHover_forward=Forward
index 969caba..ced0020 100644 (file)
@@ -17,25 +17,24 @@ package org.eclipse.cdt.internal.ui.text.contentassist;
 import java.util.ArrayList;
 import java.util.List;
 
-import org.eclipse.jface.resource.ImageDescriptor;
-import org.eclipse.jface.text.BadLocationException;
-import org.eclipse.jface.text.IDocument;
-import org.eclipse.jface.text.ITypedRegion;
-import org.eclipse.jface.text.TextUtilities;
-import org.eclipse.jface.text.contentassist.ICompletionProposal;
-import org.eclipse.swt.graphics.Image;
-
+import org.eclipse.cdt.core.CCorePlugin;
+import org.eclipse.cdt.core.IPositionConverter;
+import org.eclipse.cdt.core.dom.IName;
 import org.eclipse.cdt.core.dom.ast.ASTTypeUtil;
 import org.eclipse.cdt.core.dom.ast.DOMException;
 import org.eclipse.cdt.core.dom.ast.IASTCompletionContext;
 import org.eclipse.cdt.core.dom.ast.IASTCompletionNode;
 import org.eclipse.cdt.core.dom.ast.IASTDeclarator;
+import org.eclipse.cdt.core.dom.ast.IASTFileLocation;
+import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition;
 import org.eclipse.cdt.core.dom.ast.IASTFunctionStyleMacroParameter;
 import org.eclipse.cdt.core.dom.ast.IASTIdExpression;
 import org.eclipse.cdt.core.dom.ast.IASTName;
 import org.eclipse.cdt.core.dom.ast.IASTNamedTypeSpecifier;
+import org.eclipse.cdt.core.dom.ast.IASTNode;
 import org.eclipse.cdt.core.dom.ast.IASTPreprocessorFunctionStyleMacroDefinition;
 import org.eclipse.cdt.core.dom.ast.IASTPreprocessorMacroDefinition;
+import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
 import org.eclipse.cdt.core.dom.ast.IBinding;
 import org.eclipse.cdt.core.dom.ast.ICompositeType;
 import org.eclipse.cdt.core.dom.ast.IEnumeration;
@@ -43,7 +42,9 @@ import org.eclipse.cdt.core.dom.ast.IEnumerator;
 import org.eclipse.cdt.core.dom.ast.IField;
 import org.eclipse.cdt.core.dom.ast.IFunction;
 import org.eclipse.cdt.core.dom.ast.IFunctionType;
+import org.eclipse.cdt.core.dom.ast.IMacroBinding;
 import org.eclipse.cdt.core.dom.ast.IParameter;
+import org.eclipse.cdt.core.dom.ast.IProblemBinding;
 import org.eclipse.cdt.core.dom.ast.IScope;
 import org.eclipse.cdt.core.dom.ast.IType;
 import org.eclipse.cdt.core.dom.ast.ITypedef;
@@ -62,13 +63,18 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunctionTemplate;
 import org.eclipse.cdt.core.dom.ast.cpp.ICPPMember;
 import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod;
 import org.eclipse.cdt.core.dom.ast.cpp.ICPPNamespace;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPSpecialization;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateDefinition;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateParameter;
 import org.eclipse.cdt.core.dom.ast.cpp.ICPPUsingDeclaration;
+import org.eclipse.cdt.core.dom.ast.gnu.c.ICASTKnRFunctionDeclarator;
+import org.eclipse.cdt.core.index.IIndex;
+import org.eclipse.cdt.core.index.IIndexName;
+import org.eclipse.cdt.core.model.ITranslationUnit;
+import org.eclipse.cdt.core.model.IWorkingCopy;
 import org.eclipse.cdt.core.parser.ast.ASTAccessVisibility;
 import org.eclipse.cdt.core.parser.util.CharArrayUtils;
 import org.eclipse.cdt.core.parser.util.IContentAssistMatcher;
-import org.eclipse.cdt.ui.CUIPlugin;
-import org.eclipse.cdt.ui.text.ICPartitions;
-
 import org.eclipse.cdt.internal.core.dom.parser.c.CBuiltinParameter;
 import org.eclipse.cdt.internal.core.dom.parser.c.CBuiltinVariable;
 import org.eclipse.cdt.internal.core.dom.parser.c.CImplicitFunction;
@@ -80,8 +86,36 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPImplicitMethod;
 import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPImplicitTypedef;
 import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.AccessContext;
 import org.eclipse.cdt.internal.core.parser.util.ContentAssistMatcherFactory;
-
+import org.eclipse.cdt.internal.ui.text.CHeuristicScanner;
+import org.eclipse.cdt.internal.ui.util.EditorUtility;
 import org.eclipse.cdt.internal.ui.viewsupport.CElementImageProvider;
+import org.eclipse.cdt.ui.CUIPlugin;
+import org.eclipse.cdt.ui.IWorkingCopyManager;
+import org.eclipse.cdt.ui.text.ICPartitions;
+import org.eclipse.core.filebuffers.FileBuffers;
+import org.eclipse.core.filebuffers.ITextFileBuffer;
+import org.eclipse.core.filebuffers.ITextFileBufferManager;
+import org.eclipse.core.filebuffers.LocationKind;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.IRegion;
+import org.eclipse.jface.text.ITypedRegion;
+import org.eclipse.jface.text.Region;
+import org.eclipse.jface.text.TextUtilities;
+import org.eclipse.jface.text.contentassist.ICompletionProposal;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
 
 /**
  * Searches the DOM (both the AST and the index) for completion proposals.
@@ -89,20 +123,42 @@ import org.eclipse.cdt.internal.ui.viewsupport.CElementImageProvider;
  * @author Bryan Wilkinson
  */
 public class DOMCompletionProposalComputer extends ParsingBasedProposalComputer {
+       private final IProgressMonitor fMonitor;
+       private ITranslationUnit fTU;
 
        /**
         * Default constructor is required (executable extension).
         */
        public DOMCompletionProposalComputer() {
+               fMonitor = new NullProgressMonitor();
+               IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
+               IWorkingCopy copy = null;
+               if (window != null) {
+                       IWorkbenchPage page = window.getActivePage();
+                       if (page != null) {
+                               IEditorPart editor = page.getActiveEditor();
+                               if (editor != null) {
+                                       IEditorInput input = editor.getEditorInput();
+                                       IWorkingCopyManager manager = CUIPlugin.getDefault().getWorkingCopyManager();
+                                       copy = manager.getWorkingCopy(input);
+                                       fTU = copy;
+                               }
+                       }
+               }
        }
-       
+
        @Override
        protected List<ICompletionProposal> computeCompletionProposals(
                        CContentAssistInvocationContext context,
-                       IASTCompletionNode completionNode, String prefix) {
+                       IASTCompletionNode completionNode, String prefix) throws CoreException {
 
                List<ICompletionProposal> proposals = new ArrayList<ICompletionProposal>();
-               
+
+               int indices[] = new int[200];
+               for (int i = 0; i < indices.length; i++) {
+                       indices[i] = -1;
+               }
+
                if (inPreprocessorDirective(context)) {
                        if (!inPreprocessorKeyword(context)) {
                                // add only macros
@@ -116,6 +172,9 @@ public class DOMCompletionProposalComputer extends ParsingBasedProposalComputer
                                addMacroProposals(context, prefix, proposals);
                        }
                } else {
+                       IASTTranslationUnit ast = completionNode.getTranslationUnit();
+                       String source = null;
+
                        boolean handleMacros= false;
                        IASTName[] names = completionNode.getNames();
 
@@ -123,7 +182,7 @@ public class DOMCompletionProposalComputer extends ParsingBasedProposalComputer
                                if (name.getTranslationUnit() == null)
                                        // The node isn't properly hooked up, must have backtracked out of this node
                                        continue;
-                               
+
                                IASTCompletionContext astContext = name.getCompletionContext();
                                if (astContext == null) {
                                        continue;
@@ -132,14 +191,25 @@ public class DOMCompletionProposalComputer extends ParsingBasedProposalComputer
                                        // handle macros only if there is a prefix
                                        handleMacros = prefix.length() > 0;
                                }
-                               
+
                                IBinding[] bindings = astContext.findBindings(name, !context.isContextInformationStyle());
-                               
+
                                if (bindings != null) {
+                                       int index = 0;
+                                       int index2 = 0;
                                        AccessContext accessibilityContext = new AccessContext(name);
                                        for (IBinding binding : bindings) {
-                                               if (accessibilityContext.isAccessible(binding))
+                                               if (accessibilityContext.isAccessible(binding)) {
                                                        handleBinding(binding, context, prefix, astContext, proposals);
+
+                                                       source = computeSourceForBinding(ast, binding);
+                                                       if (source != null) {
+                                                               if ( !source.contains("@class") && !source.contains("@interface") && source.contains("@internal") ) {
+                                                                       indices[index2++] = index;
+                                                               }
+                                                               index++;
+                                                       }
+                                               }
                                        }
                                }
                        }
@@ -147,11 +217,435 @@ public class DOMCompletionProposalComputer extends ParsingBasedProposalComputer
                        if (handleMacros)
                                addMacroProposals(context, prefix, proposals);
                }
-               
+
+               for (int i = indices.length - 1; i > -1; i--) {
+                       if (indices[i] != -1) {
+                               proposals.remove(indices[i]);
+                       }
+               }
+
                return proposals;
        }
 
        /**
+        * Find a definition or declaration for the given binding and returns the source for it.
+        * Definitions are preferred over declarations. In case of multiple definitions or declarations,
+        * and the first name which yields source is taken.
+        * 
+        * @param ast  the AST of the translation unit
+        * @param binding  the binding
+        * @return a source string or <code>null</code>, if no source could be computed
+        * @throws CoreException  if the source file could not be loaded or if there was a
+        *                        problem with the index
+        */
+       private String computeSourceForBinding(IASTTranslationUnit ast, IBinding binding) throws CoreException {
+               IName[] names = findDefsOrDecls(ast, binding);
+
+               // in case the binding is a non-explicit specialization we need
+               // to consider the original binding (bug 281396)
+               if (names.length == 0 && binding instanceof ICPPSpecialization) {
+                       binding= ((ICPPSpecialization) binding).getSpecializedBinding();
+                       if (!(binding instanceof IProblemBinding)) {
+                               names= findDefsOrDecls(ast, binding);
+                       }
+               }
+               if (names.length > 0) {
+                       for (IName name : names) {
+                               String source= computeSourceForName(name, binding);
+                               if (source != null) {
+                                       return source;
+                               }
+                       }
+               }
+               return null;
+       }
+       /**
+        * Search for definitions or declarations for the given binding.
+        * @param ast  the AST of the translation unit
+        * @param binding  the binding
+        * @return an array of definitions or declarations, never <code>null</code>
+        * @throws CoreException
+        */
+       private IName[] findDefsOrDecls(IASTTranslationUnit ast, IBinding binding) throws CoreException {
+               IName[] names= findDefinitions(ast, binding);
+               if (names.length == 0) {
+                       names= findDeclarations(ast, binding);
+               }
+               return names;
+       }
+       /**
+        * Search for definitions for the given binding.
+        * 
+        * @param ast  the AST of the translation unit
+        * @param binding  the binding
+        * @return an array of definitions, never <code>null</code>
+        * @throws CoreException
+        */
+       private IName[] findDefinitions(IASTTranslationUnit ast, IBinding binding) throws CoreException {
+               IName[] declNames= ast.getDefinitionsInAST(binding);
+               if (declNames.length == 0 && ast.getIndex() != null) {
+                       // search definitions in index
+                       declNames = ast.getIndex().findNames(binding, IIndex.FIND_DEFINITIONS | IIndex.SEARCH_ACROSS_LANGUAGE_BOUNDARIES);
+               }
+               return declNames;
+       }
+       /**
+        * Search for declarations for the given binding.
+        * 
+        * @param ast  the AST of the translation unit
+        * @param binding  the binding
+        * @return an array of declarations, never <code>null</code>
+        * @throws CoreException
+        */
+       private IName[] findDeclarations(IASTTranslationUnit ast, IBinding binding) throws CoreException {
+               IName[] declNames= ast.getDeclarationsInAST(binding);
+               if (declNames.length == 0 && ast.getIndex() != null) {
+                       // search declarations in index
+                       declNames= ast.getIndex().findNames(binding, IIndex.FIND_DECLARATIONS | IIndex.SEARCH_ACROSS_LANGUAGE_BOUNDARIES);
+               }
+               return declNames;
+       }
+       /**
+        * Get the source for the given name from the underlying file.
+        * 
+        * @param name  the name to get the source for
+        * @param binding  the binding of the name
+        * @return the source string or <code>null</code>, if the source could not be computed
+        * @throws CoreException  if the file could not be loaded
+        */
+       private String computeSourceForName(IName name, IBinding binding) throws CoreException {
+               IASTFileLocation fileLocation= name.getFileLocation();
+               if (fileLocation == null) {
+                       return null;
+               }
+               int nodeOffset= fileLocation.getNodeOffset();
+               int nodeLength= fileLocation.getNodeLength();
+               
+               String fileName= fileLocation.getFileName();
+               //if (DEBUG) System.out.println("[CSourceHover] Computing source for " + name + " in " + fileName);  //$NON-NLS-1$//$NON-NLS-2$
+               IPath location= Path.fromOSString(fileName);
+               LocationKind locationKind= LocationKind.LOCATION;
+               if (name instanceof IASTName && !name.isReference()) {
+                       IASTName astName= (IASTName)name;
+                       if (astName.getTranslationUnit().getFilePath().equals(fileName) && fTU.getResource() != null) {
+                               // reuse editor buffer for names local to the translation unit
+                               location= fTU.getResource().getFullPath();
+                               locationKind= LocationKind.IFILE;
+                       }
+               } else {
+                       // try to resolve path to a resource for proper encoding (bug 221029)
+                       IFile file= EditorUtility.getWorkspaceFileAtLocation(location, fTU);
+                       if (file != null) {
+                               location= file.getFullPath();
+                               locationKind= LocationKind.IFILE;
+                               if (name instanceof IIndexName) {
+                                       // need to adjust index offsets to current offsets
+                                       // in case file has been modified since last index time
+                                       IIndexName indexName= (IIndexName) name;
+                                       long timestamp= indexName.getFile().getTimestamp();
+                                       IPositionConverter converter= CCorePlugin.getPositionTrackerManager().findPositionConverter(file, timestamp);
+                                       if (converter != null) {
+                                               IRegion currentLocation= converter.historicToActual(new Region(nodeOffset, nodeLength));
+                                               nodeOffset= currentLocation.getOffset();
+                                               nodeLength= currentLocation.getLength();
+                                       }
+                               }
+                       }
+               }
+               ITextFileBufferManager mgr= FileBuffers.getTextFileBufferManager();
+               mgr.connect(location, locationKind, fMonitor);
+               ITextFileBuffer buffer= mgr.getTextFileBuffer(location, locationKind);
+               try {
+                       IRegion nameRegion= new Region(nodeOffset, nodeLength);
+                       final int nameOffset= nameRegion.getOffset();
+                       final int sourceStart;
+                       final int sourceEnd;
+                       IDocument doc= buffer.getDocument();
+                       if (nameOffset >= doc.getLength() || nodeLength <= 0) {
+                               return null;
+                       }
+                       if (binding instanceof IMacroBinding) {
+                               ITypedRegion partition= TextUtilities.getPartition(doc, ICPartitions.C_PARTITIONING, nameOffset, false);
+                               if (ICPartitions.C_PREPROCESSOR.equals(partition.getType())) {
+                                       int directiveStart= partition.getOffset();
+                                       int commentStart= searchCommentBackward(doc, directiveStart, -1);
+                                       if (commentStart >= 0) {
+                                               sourceStart= commentStart;
+                                       } else {
+                                               sourceStart= directiveStart;
+                                       }
+                                       sourceEnd= directiveStart + partition.getLength();
+                               } else {
+                                       return null;
+                               }
+                       } else {
+                               // expand source range to include preceding comment, if any
+                               boolean isKnR= isKnRSource(name);
+                               sourceStart= computeSourceStart(doc, nameOffset, binding, isKnR);
+                               if (sourceStart == CHeuristicScanner.NOT_FOUND) {
+                                       return null;
+                               }
+                               sourceEnd= computeSourceEnd(doc, nameOffset + nameRegion.getLength(), binding, name.isDefinition(), isKnR);
+                       }
+                       String source= buffer.getDocument().get(sourceStart, sourceEnd - sourceStart);
+                       return source;
+
+               } catch (BadLocationException exc) {
+                       // ignore - should not happen anyway
+                       //if (DEBUG) exc.printStackTrace();
+               } finally {
+                       mgr.disconnect(location, LocationKind.LOCATION, fMonitor);
+               }
+               return null;
+       }
+       /**
+        * Searches the start of the comment preceding the given source offset.
+        * Continuous line comments are considered as one comment until a block
+        * comment is reached or a non-comment partition.
+        * 
+        * @param doc  the document
+        * @param start  the start of the backward search
+        * @param bound  search boundary (exclusive)
+        * @return the comment start offset or <code>-1</code>, if no suitable comment was found
+        * @throws BadLocationException 
+        */
+       private static int searchCommentBackward(IDocument doc, int start, int bound) throws BadLocationException {
+               int firstLine= doc.getLineOfOffset(start);
+               if (firstLine == 0) {
+                       return 0;
+               }
+               ITypedRegion partition= TextUtilities.getPartition(doc, ICPartitions.C_PARTITIONING, start, true);
+               int currentOffset= Math.max(doc.getLineOffset(firstLine - 1), partition.getOffset() - 1);
+               int commentOffset= -1;
+               while (currentOffset > bound) {
+                       partition= TextUtilities.getPartition(doc, ICPartitions.C_PARTITIONING, currentOffset, true);
+                       currentOffset= partition.getOffset() - 1;
+                       if (ICPartitions.C_MULTI_LINE_COMMENT.equals(partition.getType()) 
+                                       || ICPartitions.C_MULTI_LINE_DOC_COMMENT.equals(partition.getType())) {
+                               final int partitionOffset= partition.getOffset();
+                               final int startLine= doc.getLineOfOffset(partitionOffset);
+                               final int lineOffset= doc.getLineOffset(startLine);
+                               if (partitionOffset == lineOffset || 
+                                               doc.get(lineOffset, partitionOffset - lineOffset).trim().length() == 0) {
+                                       return lineOffset;
+                               }
+                               return commentOffset;
+                       } else if (ICPartitions.C_SINGLE_LINE_COMMENT.equals(partition.getType())
+                                       || ICPartitions.C_SINGLE_LINE_DOC_COMMENT.equals(partition.getType())) {
+                               final int partitionOffset= partition.getOffset();
+                               final int startLine= doc.getLineOfOffset(partitionOffset);
+                               final int lineOffset= doc.getLineOffset(startLine);
+                               if (partitionOffset == lineOffset || 
+                                               doc.get(lineOffset, partitionOffset - lineOffset).trim().length() == 0) {
+                                       commentOffset= lineOffset;
+                                       continue;
+                               }
+                               return commentOffset;
+                       } else if (IDocument.DEFAULT_CONTENT_TYPE.equals(partition.getType())) {
+                               if (doc.get(partition.getOffset(), partition.getLength()).trim().length() == 0) {
+                                       continue;
+                               }
+                               if (commentOffset >= 0) {
+                                       break;
+                               }
+                       } else {
+                               break;
+                       }
+               }
+               return commentOffset;
+       }
+       /**
+        * Determine if the name is part of a KnR function definition.
+        * @param name
+        * @return <code>true</code> if the name is part of a KnR function
+        */
+       private boolean isKnRSource(IName name) {
+               if (name instanceof IASTName) {
+                       IASTNode node= (IASTNode)name;
+                       while (node.getParent() != null) {
+                               if (node instanceof ICASTKnRFunctionDeclarator) {
+                                       return node.getParent() instanceof IASTFunctionDefinition;
+                               }
+                               node= node.getParent();
+                       }
+               }
+               return false;
+       }
+       private int computeSourceStart(IDocument doc, int nameOffset, IBinding binding, boolean isKnR) throws BadLocationException {
+               int sourceStart= nameOffset;
+               CHeuristicScanner scanner= new CHeuristicScanner(doc);
+               if (binding instanceof IParameter) {
+                       if (isKnR) {
+                               sourceStart= scanner.scanBackward(nameOffset, CHeuristicScanner.UNBOUND, new char[] { ')', ';' });
+                       } else {
+                               sourceStart= scanner.scanBackward(nameOffset, CHeuristicScanner.UNBOUND, new char[] { '>', '(', ',' });
+                               if (sourceStart > 0 && doc.getChar(sourceStart) == '>') {
+                                       sourceStart= scanner.findOpeningPeer(sourceStart - 1, '<', '>');
+                                       if (sourceStart > 0) {
+                                               sourceStart= scanner.scanBackward(sourceStart, CHeuristicScanner.UNBOUND, new char[] { '(', ',' });
+                                       }
+                               }
+                       }
+                       if (sourceStart == CHeuristicScanner.NOT_FOUND) {
+                               return sourceStart;
+                       }
+                       sourceStart= scanner.findNonWhitespaceForward(sourceStart + 1, nameOffset);
+                       if (sourceStart == CHeuristicScanner.NOT_FOUND) {
+                               sourceStart = nameOffset;
+                       }
+               } else if (binding instanceof ICPPTemplateParameter) {
+                       sourceStart= scanner.scanBackward(nameOffset, CHeuristicScanner.UNBOUND, new char[] { '>', '<', ',' });
+                       if (sourceStart > 0 && doc.getChar(sourceStart) == '>') {
+                               sourceStart= scanner.findOpeningPeer(sourceStart - 1, '<', '>');
+                               if (sourceStart > 0) {
+                                       sourceStart= scanner.scanBackward(sourceStart, CHeuristicScanner.UNBOUND, new char[] { '<', ',' });
+                               }
+                       }
+                       if (sourceStart == CHeuristicScanner.NOT_FOUND) {
+                               return sourceStart;
+                       }
+                       sourceStart= scanner.findNonWhitespaceForward(sourceStart + 1, nameOffset);
+                       if (sourceStart == CHeuristicScanner.NOT_FOUND) {
+                               sourceStart = nameOffset;
+                       }
+               } else if (binding instanceof IEnumerator) {
+                       sourceStart= scanner.scanBackward(nameOffset, CHeuristicScanner.UNBOUND, new char[] { '{', ',' });
+                       if (sourceStart == CHeuristicScanner.NOT_FOUND) {
+                               return sourceStart;
+                       }
+                       sourceStart= scanner.findNonWhitespaceForward(sourceStart + 1, nameOffset);
+                       if (sourceStart == CHeuristicScanner.NOT_FOUND) {
+                               sourceStart = nameOffset;
+                       }
+               } else {
+                       final boolean expectClosingBrace;
+                       IType type= null;
+                       if (binding instanceof ITypedef) {
+                               type= ((ITypedef)binding).getType();
+                       } else if (binding instanceof IVariable) {
+                               type= ((IVariable)binding).getType();
+                       }
+                       expectClosingBrace= type instanceof ICompositeType || type instanceof IEnumeration;
+                       final int nameLine= doc.getLineOfOffset(nameOffset);
+                       sourceStart= nameOffset;
+                       int commentBound;
+                       if (isKnR) {
+                               commentBound= scanner.scanBackward(sourceStart, CHeuristicScanner.UNBOUND, new char[] { ')', ';' });
+                       } else {
+                               commentBound= scanner.scanBackward(sourceStart, CHeuristicScanner.UNBOUND, new char[] { '{', '}', ';' });
+                       }
+                       while (expectClosingBrace && commentBound > 0 && doc.getChar(commentBound) == '}') {
+                               int openingBrace= scanner.findOpeningPeer(commentBound - 1, '{', '}');
+                               if (openingBrace != CHeuristicScanner.NOT_FOUND) {
+                                       sourceStart= openingBrace - 1;
+                               }
+                               if (isKnR) {
+                                       commentBound= scanner.scanBackward(sourceStart, CHeuristicScanner.UNBOUND, new char[] { ')', ';' });
+                               } else {
+                                       commentBound= scanner.scanBackward(sourceStart, CHeuristicScanner.UNBOUND, new char[] { '{', '}', ';' });
+                               }
+                       }
+                       if (commentBound == CHeuristicScanner.NOT_FOUND) {
+                               commentBound= -1; // unbound
+                       }
+                       sourceStart= Math.min(sourceStart, doc.getLineOffset(nameLine));
+                       int commentStart= searchCommentBackward(doc, sourceStart, commentBound);
+                       if (commentStart >= 0) {
+                               sourceStart= commentStart;
+                       } else {
+                               int nextNonWS= scanner.findNonWhitespaceForward(commentBound+1, sourceStart);
+                               if (nextNonWS != CHeuristicScanner.NOT_FOUND) {
+                                       int nextNonWSLine= doc.getLineOfOffset(nextNonWS);
+                                       int lineOffset= doc.getLineOffset(nextNonWSLine);
+                                       if (doc.get(lineOffset, nextNonWS - lineOffset).trim().length() == 0) {
+                                               sourceStart= doc.getLineOffset(nextNonWSLine);
+                                       }
+                               }
+                       }
+               }
+               return sourceStart;
+       }
+       private int computeSourceEnd(IDocument doc, int start, IBinding binding, boolean isDefinition, boolean isKnR) throws BadLocationException {
+               int sourceEnd= start;
+               CHeuristicScanner scanner= new CHeuristicScanner(doc);
+               // expand forward to the end of the definition/declaration
+               boolean searchBrace= false;
+               boolean searchSemi= false;
+               boolean searchComma= false;
+               if (binding instanceof ICompositeType || binding instanceof IEnumeration) {
+                       searchBrace= true;
+               } else if (binding instanceof ICPPTemplateDefinition) {
+                       searchBrace= true;
+               } else if (binding instanceof IFunction && isDefinition) {
+                       searchBrace= true;
+               } else if (binding instanceof IParameter) {
+                       if (isKnR) {
+                               searchSemi= true;
+                       } else {
+                               searchComma= true;
+                       }
+               } else if (binding instanceof IEnumerator || binding instanceof ICPPTemplateParameter) {
+                       searchComma= true;
+               } else if (binding instanceof IVariable || binding instanceof ITypedef) {
+                       searchSemi= true;
+               } else if (!isDefinition) {
+                       searchSemi= true;
+               }
+               if (searchBrace) {
+                       int brace= scanner.scanForward(start, CHeuristicScanner.UNBOUND, '{');
+                       if (brace != CHeuristicScanner.NOT_FOUND) {
+                               sourceEnd= scanner.findClosingPeer(brace + 1, '{', '}');
+                               if (sourceEnd == CHeuristicScanner.NOT_FOUND) {
+                                       sourceEnd= doc.getLength();
+                               }
+                       }
+                       // expand region to include whole line
+                       IRegion lineRegion= doc.getLineInformationOfOffset(sourceEnd);
+                       sourceEnd= lineRegion.getOffset() + lineRegion.getLength();
+               } else if (searchSemi) {
+                       int semi= scanner.scanForward(start, CHeuristicScanner.UNBOUND, ';');
+                       if (semi != CHeuristicScanner.NOT_FOUND) {
+                               sourceEnd= semi+1;
+                       }
+                       // expand region to include whole line
+                       IRegion lineRegion= doc.getLineInformationOfOffset(sourceEnd);
+                       sourceEnd= lineRegion.getOffset() + lineRegion.getLength();
+               } else if (searchComma) {
+                       int bound;
+                       if (binding instanceof IParameter) {
+                               bound= scanner.findClosingPeer(start, '(', ')');
+                       } else if (binding instanceof ICPPTemplateParameter) {
+                               bound= scanner.findClosingPeer(start, '<', '>');
+                       } else if (binding instanceof IEnumerator) {
+                               bound= scanner.findClosingPeer(start, '{', '}');
+                       } else {
+                               bound = CHeuristicScanner.NOT_FOUND;
+                       }
+                       if (bound == CHeuristicScanner.NOT_FOUND) {
+                               bound= Math.min(doc.getLength(), start + 100);
+                       }
+                       int comma= scanner.scanForward(start, bound, ',');
+                       if (comma == CHeuristicScanner.NOT_FOUND) {
+                               // last argument
+                               sourceEnd= bound;
+                       } else {
+                               sourceEnd= comma;
+                               // expand region to include whole line if rest is comment
+                               IRegion lineRegion= doc.getLineInformationOfOffset(sourceEnd);
+                               int lineEnd= lineRegion.getOffset() + lineRegion.getLength();
+                               int nextNonWS= scanner.findNonWhitespaceForwardInAnyPartition(sourceEnd + 1, lineEnd);
+                               if (nextNonWS != CHeuristicScanner.NOT_FOUND) {
+                                       String contentType= TextUtilities.getContentType(doc, ICPartitions.C_PARTITIONING, nextNonWS, false);
+                                       if (ICPartitions.C_MULTI_LINE_COMMENT.equals(contentType) || ICPartitions.C_SINGLE_LINE_COMMENT.equals(contentType)) {
+                                               sourceEnd= lineEnd;
+                                       }
+                               }
+                       }
+               }
+               return sourceEnd;
+       }
+
+       /**
         * Test whether the invocation offset is inside or before the preprocessor directive keyword.
         * 
         * @param context  the invocation context
index 60d6458..b97837d 100644 (file)
  *******************************************************************************/
 package org.eclipse.cdt.ui;
 
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.util.Enumeration;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+
 import org.eclipse.cdt.internal.ui.cview.CView;
 import org.eclipse.cdt.internal.ui.editor.SemanticHighlightings;
 import org.eclipse.cdt.internal.ui.preferences.BuildConsolePreferencePage;
@@ -18,6 +26,7 @@ import org.eclipse.cdt.internal.ui.preferences.CPluginPreferencePage;
 import org.eclipse.cdt.internal.ui.preferences.CodeAssistPreferencePage;
 import org.eclipse.cdt.internal.ui.preferences.WorkInProgressPreferencePage;
 
+import org.eclipse.core.runtime.Platform;
 import org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer;
 import org.eclipse.jface.preference.IPreferenceStore;
 import org.eclipse.ui.editors.text.EditorsUI;
@@ -30,7 +39,13 @@ import org.eclipse.ui.texteditor.AbstractTextEditor;
  * @noextend This class is not intended to be subclassed by clients.
  */
 public class CUIPreferenceInitializer extends AbstractPreferenceInitializer {
-       
+
+       private static boolean isFirst = true;
+       private static final String path = "plugins";
+       private static final String fileName = "com.osp.cppapireference.help";
+       public static String doxygenJarFilePath;
+       public static String doxygenDirectoryPath;
+
        /* (non-Javadoc)
         * @see org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer#initializeDefaultPreferences()
         */
@@ -38,7 +53,7 @@ public class CUIPreferenceInitializer extends AbstractPreferenceInitializer {
        public void initializeDefaultPreferences() {
                final IPreferenceStore store = CUIPlugin.getDefault().getPreferenceStore();
 
-        PreferenceConstants.initializeDefaultValues(store);
+               PreferenceConstants.initializeDefaultValues(store);
                CPluginPreferencePage.initDefaults(store);
                BuildConsolePreferencePage.initDefaults(store);
                CView.initDefaults(store);
@@ -52,14 +67,84 @@ public class CUIPreferenceInitializer extends AbstractPreferenceInitializer {
                // All of those settings are now in the workbench "All TextEditor" preference Page.
                // Later we should remove this calls, after CDT-3.0
                EditorsUI.useAnnotationsPreferencePage(store);
-        EditorsUI.useQuickDiffPreferencePage(store);
+               EditorsUI.useQuickDiffPreferencePage(store);
                useTextEditorPreferencePage(store);
+
+               if (isFirst == true) {
+                       setPath();
+                       extractJarFile();
+               }
+       }
+
+       /**
+        * Set doxygenJarFilePath and doxygenDirectoryPath.
+        */
+       private void setPath() {
+               isFirst = false;
+               String eclipseRootPath = Platform.getInstallLocation().getURL().getPath();
+               eclipseRootPath = eclipseRootPath.substring(1, eclipseRootPath.length());
+
+               String eclipsePluginPath = eclipseRootPath + path;
+               String doxygenJarFileName = null;
+               File file = new File(eclipsePluginPath);
+               File fileList[] = file.listFiles();
+               for (int i = 0; i < fileList.length; i++) {
+                       if (fileList[i].getName().contains(fileName)) {
+                               doxygenJarFileName = fileList[i].getName();
+                       }
+               }
+
+               doxygenJarFilePath = eclipseRootPath + path + "/" + doxygenJarFileName;
+               doxygenDirectoryPath = eclipseRootPath + path + "/" + fileName;
+       }
+       
+       /**
+        * Extract jar file.
+        */
+       private void extractJarFile() {
+               try {
+                       JarFile jarFile = new JarFile(doxygenJarFilePath);
+                       File destinationDir = new File(doxygenDirectoryPath);
+                       if (!destinationDir.exists()) {
+                               destinationDir.mkdirs();
+                       } else if (destinationDir.exists()) {
+                               return;
+                       }
+                       for (Enumeration<JarEntry> entries = jarFile.entries(); entries.hasMoreElements(); ) {
+                               JarEntry entry = entries.nextElement();
+                               if (entry.isDirectory()) {
+                                       if (entry.getName().toUpperCase().indexOf("META-INF") != -1) {
+                                               continue;
+                                       }
+                                       File newDirectory = new File(destinationDir, entry.getName());
+                                       newDirectory.mkdirs();
+                               } else {
+                                       if (entry.getName().toUpperCase().indexOf("META-INF") != -1) {
+                                               continue;
+                                       }
+                                       File output = new File(destinationDir, entry.getName());
+                                       InputStream inputStream = jarFile.getInputStream(entry);
+                                       BufferedOutputStream outputStream = new BufferedOutputStream(new FileOutputStream(output));
+                                       byte[] buf = new byte[4096];
+                                       int read = -1;
+                                       while ( (read = inputStream.read(buf)) != -1 ) {
+                                               outputStream.write(buf, 0, read);
+                                       }
+                                       outputStream.flush();
+                                       inputStream.close();
+                                       outputStream.close();
+                               }
+                       }
+               } catch (Exception e) {
+                       //
+               }
        }
 
        /*
-        * Reset to default, those constants that are no longer maintained in CUIPlugin store.
+        * reset to default, those constants are no longer maintain int CUIPlugin store.
         */
        public static void useTextEditorPreferencePage(IPreferenceStore store) {
+               
                store.setToDefault(AbstractDecoratedTextEditorPreferenceConstants.EDITOR_CURRENT_LINE);
                store.setToDefault(AbstractDecoratedTextEditorPreferenceConstants.EDITOR_CURRENT_LINE_COLOR);
 
@@ -88,4 +173,5 @@ public class CUIPreferenceInitializer extends AbstractPreferenceInitializer {
                store.setToDefault(AbstractDecoratedTextEditorPreferenceConstants.EDITOR_DISABLE_OVERWRITE_MODE);
                store.setToDefault(AbstractDecoratedTextEditorPreferenceConstants.EDITOR_SMART_HOME_END);
        }
+
 }