1.什么是JDT的hover。
见下图:
2. hover中的不同的字体,和颜色是如何显示出来的。
其实在对应的hover中,返回的是String类型,内容是html,然后通过org.eclipse.swt.browser.Browser显示出来的。
3.工作原理:
3.1 add MouseTracker to current SourceViewer, when you open java file.
org.eclipse.jdt.internal.ui.javaeditor.CompilationUnitEditor$AdaptedSourceViewer
--> org.eclipse.jdt.internal.ui.javaeditor.CompilationUnitEditor$AdaptedSourceViewer
/** * After this method has been executed the caller knows that any installed text hover has been installed. */ private void ensureHoverControlManagerInstalled() { if (fTextHovers != null && !fTextHovers.isEmpty() && fHoverControlCreator != null && fTextHoverManager == null) { fTextHoverManager= new TextViewerHoverManager(this, fHoverControlCreator); fTextHoverManager.install(this.getTextWidget()); fTextHoverManager.setSizeConstraints(TEXT_HOVER_WIDTH_CHARS, TEXT_HOVER_HEIGHT_CHARS, false, true); fTextHoverManager.setInformationControlReplacer(new StickyHoverManager(this)); } }--> org.eclipse.jface.text.TextViewerHoverManager
public void install(Control subjectControl) { if (fSubjectControl != null && !fSubjectControl.isDisposed() && fSubjectControlDisposeListener != null) fSubjectControl.removeDisposeListener(fSubjectControlDisposeListener); fSubjectControl= subjectControl; if (fSubjectControl != null) fSubjectControl.addDisposeListener(getSubjectControlDisposeListener()); if (fInformationControlCloser != null) fInformationControlCloser.setSubjectControl(subjectControl); setEnabled(true); fDisposed= false; }--> org.eclipse.jface.text.TextViewerHoverManager
public void setEnabled(boolean enabled) { boolean was= isEnabled(); super.setEnabled(enabled); boolean is= isEnabled(); if (was != is && fMouseTracker != null) { if (is) fMouseTracker.start(getSubjectControl()); else fMouseTracker.stop(); } }
--> org.eclipse.jface.text.AbstractHoverInformationControlManager$MouseTracker
public void start(Control subjectControl) { fSubjectControl= subjectControl; if (fSubjectControl != null && !fSubjectControl.isDisposed()) fSubjectControl.addMouseTrackListener(this); fIsInRestartMode= false; fIsComputing= false; fMouseLostWhileComputing= false; fShellDeactivatedWhileComputing= false; }
3.2 when you hover mouse on target SourceViewer, it will show hover
org.eclipse.jface.text.AbstractHoverInformationControlManager$MouseTracker
public void mouseHover(MouseEvent event) { if (fIsComputing || fIsInRestartMode || (fSubjectControl != null && !fSubjectControl.isDisposed() && fSubjectControl.getShell() != fSubjectControl.getShell().getDisplay().getActiveShell())) { if (DEBUG) System.out.println("AbstractHoverInformationControlManager...mouseHover: @ " + event.x + "/" + event.y + " : hover cancelled: fIsComputing= " + fIsComputing + ", fIsInRestartMode= " + fIsInRestartMode); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ return; } fIsInRestartMode= true; fIsComputing= true; fMouseLostWhileComputing= false; fShellDeactivatedWhileComputing= false; fHoverEventStateMask= event.stateMask; fHoverEvent= event; fHoverArea= new Rectangle(event.x - EPSILON, event.y - EPSILON, 2 * EPSILON, 2 * EPSILON ); if (fHoverArea.x < 0) fHoverArea.x= 0; if (fHoverArea.y < 0) fHoverArea.y= 0; setSubjectArea(fHoverArea); if (fSubjectControl != null && !fSubjectControl.isDisposed()) { fSubjectControl.addMouseMoveListener(this); fSubjectControl.getShell().addShellListener(this); } doShowInformation(); }
--> org.eclipse.jface.text.AbstractInformationControlManager
protected void doShowInformation() { fSubjectArea= null; fInformation= null; computeInformation(); }
--> org.eclipse.jface.text.TextViewerHoverManager
protected void computeInformation() { //create a thread(Text Viewer Hover Presenter) to show hover }...
--> org.eclipse.jface.text.AbstractInformationControlManager.internalShowInformationControl(Rectangle, Object) to create control to show the text.
private void internalShowInformationControl(Rectangle subjectArea, Object information) { if (this instanceof InformationControlReplacer) { ((InformationControlReplacer) this).showInformationControl(subjectArea, information); return; } IInformationControl informationControl= getInformationControl(); if (informationControl != null) { Point sizeConstraints= computeSizeConstraints(fSubjectControl, fSubjectArea, informationControl); if (informationControl instanceof IInformationControlExtension3) { IInformationControlExtension3 iControl3= (IInformationControlExtension3) informationControl; Rectangle trim= iControl3.computeTrim(); sizeConstraints.x += trim.width; sizeConstraints.y += trim.height; } informationControl.setSizeConstraints(sizeConstraints.x, sizeConstraints.y); if (informationControl instanceof IInformationControlExtension2) ((IInformationControlExtension2)informationControl).setInput(information); else informationControl.setInformation(information.toString()); if (informationControl instanceof IInformationControlExtension) { IInformationControlExtension extension= (IInformationControlExtension)informationControl; if (!extension.hasContents()) return; } Point size= null; Point location= null; Rectangle bounds= restoreInformationControlBounds(); if (bounds != null) { if (bounds.x > -1 && bounds.y > -1) location= Geometry.getLocation(bounds); if (bounds.width > -1 && bounds.height > -1) size= Geometry.getSize(bounds); } if (size == null) size= informationControl.computeSizeHint(); if (fEnforceAsMinimalSize) size= Geometry.max(size, sizeConstraints); if (fEnforceAsMaximalSize) size= Geometry.min(size, sizeConstraints); if (location == null) location= computeInformationControlLocation(subjectArea, size); Rectangle controlBounds= Geometry.createRectangle(location, size); cropToClosestMonitor(controlBounds); location= Geometry.getLocation(controlBounds); size= Geometry.getSize(controlBounds); informationControl.setLocation(location); informationControl.setSize(size.x, size.y); showInformationControl(subjectArea); } }
--> org.eclipse.jface.text.AbstractInformationControlManager
protected void showInformationControl(Rectangle subjectArea) { fInformationControl.setVisible(true); if (fInformationControl == null) return; // could already be disposed if setVisible(..) runs the display loop if (fTakesFocusWhenVisible) fInformationControl.setFocus(); if (fInformationControlCloser != null) fInformationControlCloser.start(subjectArea); }
org.eclipse.jdt.internal.ui.text.java.hover.JavadocHover$HoverControlCreator
public IInformationControl doCreateInformationControl(Shell parent) { String tooltipAffordanceString= fAdditionalInfoAffordance ? JavaPlugin.getAdditionalInfoAffordanceString() : EditorsUI.getTooltipAffordanceString(); if (BrowserInformationControl.isAvailable(parent)) { String font= PreferenceConstants.APPEARANCE_JAVADOC_FONT; BrowserInformationControl iControl= new BrowserInformationControl(parent, font, tooltipAffordanceString) { /* * @see org.eclipse.jface.text.IInformationControlExtension5#getInformationPresenterControlCreator() */ @Override public IInformationControlCreator getInformationPresenterControlCreator() { return fInformationPresenterControlCreator; } }; addLinkListener(iControl); return iControl; } else { return new DefaultInformationControl(parent, tooltipAffordanceString); } }
4. 下面是System.out.println的html内容和在firefox下显示的效果。
<html><head><style CHARSET="ISO-8859-1" TYPE="text/css">/* Font definitions */html { font-family: 'Sans',sans-serif; font-size: 10pt; font-style: normal; font-weight: normal; }body, h1, h2, h3, h4, h5, h6, p, table, td, caption, th, ul, ol, dl, li, dd, dt { font-size: 1em; }pre { font-family: monospace; }/* Margins */body { overflow: auto; margin-top: 0px; margin-bottom: 0.5em; margin-left: 0.3em; margin-right: 0px; }h1 { margin-top: 0.3em; margin-bottom: 0.04em; } h2 { margin-top: 2em; margin-bottom: 0.25em; }h3 { margin-top: 1.7em; margin-bottom: 0.25em; }h4 { margin-top: 2em; margin-bottom: 0.3em; }h5 { margin-top: 0px; margin-bottom: 0px; }p { margin-top: 1em; margin-bottom: 1em; }pre { margin-left: 0.6em; }ul { margin-top: 0px; margin-bottom: 1em; margin-left: 1em; padding-left: 1em;}li { margin-top: 0px; margin-bottom: 0px; } li p { margin-top: 0px; margin-bottom: 0px; } ol { margin-top: 0px; margin-bottom: 1em; margin-left: 1em; padding-left: 1em; }dl { margin-top: 0px; margin-bottom: 1em; }dt { margin-top: 0px; margin-bottom: 0px; font-weight: bold; }dd { margin-top: 0px; margin-bottom: 0px; }/* Styles and colors */a:link { color: #0000FF; }a:hover { color: #000080; }a:visited { text-decoration: underline; }a.header:link { text-decoration: none; color: #000000 }a.header:visited { text-decoration: none; color: #000000 }a.header:hover { text-decoration: underline; color: #000080; }h4 { font-style: italic; }strong { font-weight: bold; }em { font-style: italic; }var { font-style: italic; }th { font-weight: bold; }/* Workarounds for new Javadoc stylesheet (1.7) */ ul.blockList li.blockList, ul.blockListLast li.blockList { list-style:none;}ul.blockList ul.blockList ul.blockList ul.blockList li.blockListLast { list-style:none;}</style><base href='http://download.oracle.com/javase/7/docs/api/java/io/PrintStream.html'></head><body style="overflow:hidden;" text="#000000" bgcolor="#ffffbf"><h5><div style='word-wrap: break-word; position: relative; margin-left: 20px; padding-top: 2px; '><a href=''><!--[if lte IE 6]><![if gte IE 5.5]><span alt='Open Declaration' style="border:none; position: absolute; width: 16px; height: 16px; left: -21px; filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src='')"></span><![endif]><![endif]--><!--[if !IE]>--><img alt='Open Declaration' style='border:none; position: absolute; width: 16px; height: 16px; left: -21px; ' src='/><!--<![endif]--><!--[if gte IE 7]><img alt='Open Declaration' style='border:none; position: absolute; width: 16px; height: 16px; left: -21px; ' src='file:'/><![endif]--></a>void <a class='header' href=''>java</a>.<a class='header' href=''>io</a>.<a class='header' href=''>PrintStream</a>.println(<span style='font-weight:normal;'></span>int x)</div></h5><br><p>Prints an integer and then terminate the line. This method behaves as though it invokes <code><code><a href=''>print(int)</a></code></code> and then <code><code><a href=''>println()</a></code></code>.<dl><dt>Parameters:</dt><dd><b>x</b> The <code>int</code> to be printed.</dd></dl></body></html>
显示效果: