blob: 563fbf7e2fe9b458946fa795538330f9c68afdf2 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2006 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.jdt.internal.ui.infoviews;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringReader;
import java.net.URL;
import org.eclipse.core.runtime.FileLocator;
import org.eclipse.core.runtime.ListenerList;
import org.eclipse.core.runtime.Platform;
import org.eclipse.swt.SWT;
import org.eclipse.swt.SWTError;
import org.eclipse.swt.browser.Browser;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.events.ControlAdapter;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.dialogs.MessageDialogWithToggle;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.util.Assert;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.window.Window;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.BadPartitioningException;
import org.eclipse.jface.text.DefaultInformationControl;
import org.eclipse.jface.text.Document;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IDocumentExtension3;
import org.eclipse.jface.text.ITextSelection;
import org.eclipse.jface.text.ITypedRegion;
import org.eclipse.jface.text.TextPresentation;
import org.eclipse.jface.text.TextSelection;
import org.eclipse.jface.text.TextUtilities;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.texteditor.IAbstractTextEditorHelpContextIds;
import org.eclipse.ui.texteditor.IDocumentProvider;
import org.eclipse.ui.texteditor.ITextEditor;
import org.eclipse.jdt.core.IClassFile;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IMember;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.ui.JavaElementLabels;
import org.eclipse.jdt.ui.JavadocContentAccess;
import org.eclipse.jdt.ui.text.IJavaPartitions;
import org.eclipse.jdt.internal.ui.IJavaHelpContextIds;
import org.eclipse.jdt.internal.ui.JavaPlugin;
import org.eclipse.jdt.internal.ui.javaeditor.JavaEditor;
import org.eclipse.jdt.internal.ui.text.HTMLPrinter;
import org.eclipse.jdt.internal.ui.text.HTMLTextPresenter;
import org.osgi.framework.Bundle;
/**
* View which shows Javadoc for a given Java element.
*
* FIXME: As of 3.0 selectAll() and getSelection() is not working
* see https://bugs.eclipse.org/bugs/show_bug.cgi?id=63022
*
* @since 3.0
*/
public class JavadocView extends AbstractInfoView {
/**
* Preference key for the preference whether to show a dialog
* when the SWT Browser widget is not available.
* @since 3.0
*/
private static final String DO_NOT_WARN_PREFERENCE_KEY= "JavadocView.error.doNotWarn"; //$NON-NLS-1$
// see https://bugs.eclipse.org/bugs/show_bug.cgi?id=73558
private static final boolean WARNING_DIALOG_ENABLED= false;
/** Flags used to render a label in the text widget. */
private static final long LABEL_FLAGS= JavaElementLabels.ALL_FULLY_QUALIFIED
| JavaElementLabels.M_PRE_RETURNTYPE | JavaElementLabels.M_PARAMETER_TYPES | JavaElementLabels.M_PARAMETER_NAMES | JavaElementLabels.M_EXCEPTIONS
| JavaElementLabels.F_PRE_TYPE_SIGNATURE | JavaElementLabels.T_TYPE_PARAMETERS;
/** The HTML widget. */
private Browser fBrowser;
/** The text widget. */
private StyledText fText;
/** The information presenter. */
private DefaultInformationControl.IInformationPresenter fPresenter;
/** The text presentation. */
private TextPresentation fPresentation= new TextPresentation();
/** The select all action */
private SelectAllAction fSelectAllAction;
/** The style sheet (css) */
private static String fgStyleSheet;
/** The Browser widget */
private boolean fIsUsingBrowserWidget;
private RGB fBackgroundColorRGB;
/**
* The Javadoc view's select all action.
*/
private class SelectAllAction extends Action {
/** The control. */
private Control fControl;
/** The selection provider. */
private SelectionProvider fSelectionProvider;
/**
* Creates the action.
*
* @param control the widget
* @param selectionProvider the selection provider
*/
public SelectAllAction(Control control, SelectionProvider selectionProvider) {
super("selectAll"); //$NON-NLS-1$
Assert.isNotNull(control);
Assert.isNotNull(selectionProvider);
fControl= control;
fSelectionProvider= selectionProvider;
// FIXME: see https://bugs.eclipse.org/bugs/show_bug.cgi?id=63022
setEnabled(!fIsUsingBrowserWidget);
setText(InfoViewMessages.SelectAllAction_label);
setToolTipText(InfoViewMessages.SelectAllAction_tooltip);
setDescription(InfoViewMessages.SelectAllAction_description);
PlatformUI.getWorkbench().getHelpSystem().setHelp(this, IAbstractTextEditorHelpContextIds.SELECT_ALL_ACTION);
}
/**
* Selects all in the view.
*/
public void run() {
if (fControl instanceof StyledText)
((StyledText)fControl).selectAll();
else {
// FIXME: see https://bugs.eclipse.org/bugs/show_bug.cgi?id=63022
// ((Browser)fControl).selectAll();
if (fSelectionProvider != null)
fSelectionProvider.fireSelectionChanged();
}
}
}
/**
* The Javadoc view's selection provider.
*/
private static class SelectionProvider implements ISelectionProvider {
/** The selection changed listeners. */
private ListenerList fListeners= new ListenerList(ListenerList.IDENTITY);
/** The widget. */
private Control fControl;
/**
* Creates a new selection provider.
*
* @param control the widget
*/
public SelectionProvider(Control control) {
Assert.isNotNull(control);
fControl= control;
if (fControl instanceof StyledText) {
((StyledText)fControl).addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
fireSelectionChanged();
}
});
} else {
// FIXME: see https://bugs.eclipse.org/bugs/show_bug.cgi?id=63022
// ((Browser)fControl).addSelectionListener(new SelectionAdapter() {
// public void widgetSelected(SelectionEvent e) {
// fireSelectionChanged();
// }
// });
}
}
/**
* Sends a selection changed event to all listeners.
*/
public void fireSelectionChanged() {
ISelection selection= getSelection();
SelectionChangedEvent event= new SelectionChangedEvent(this, selection);
Object[] selectionChangedListeners= fListeners.getListeners();
for (int i= 0; i < selectionChangedListeners.length; i++)
((ISelectionChangedListener)selectionChangedListeners[i]).selectionChanged(event);
}
/*
* @see org.eclipse.jface.viewers.ISelectionProvider#addSelectionChangedListener(org.eclipse.jface.viewers.ISelectionChangedListener)
*/
public void addSelectionChangedListener(ISelectionChangedListener listener) {
fListeners.add(listener);
}
/*
* @see org.eclipse.jface.viewers.ISelectionProvider#getSelection()
*/
public ISelection getSelection() {
if (fControl instanceof StyledText) {
IDocument document= new Document(((StyledText)fControl).getSelectionText());
return new TextSelection(document, 0, document.getLength());
} else {
// FIXME: see https://bugs.eclipse.org/bugs/show_bug.cgi?id=63022
return StructuredSelection.EMPTY;
}
}
/*
* @see org.eclipse.jface.viewers.ISelectionProvider#removeSelectionChangedListener(org.eclipse.jface.viewers.ISelectionChangedListener)
*/
public void removeSelectionChangedListener(ISelectionChangedListener listener) {
fListeners.remove(listener);
}
/*
* @see org.eclipse.jface.viewers.ISelectionProvider#setSelection(org.eclipse.jface.viewers.ISelection)
*/
public void setSelection(ISelection selection) {
// not supported
}
}
/*
* @see AbstractInfoView#internalCreatePartControl(Composite)
*/
protected void internalCreatePartControl(Composite parent) {
try {
fBrowser= new Browser(parent, SWT.NONE);
fIsUsingBrowserWidget= true;
} catch (SWTError er) {
/* The Browser widget throws an SWTError if it fails to
* instantiate properly. Application code should catch
* this SWTError and disable any feature requiring the
* Browser widget.
* Platform requirements for the SWT Browser widget are available
* from the SWT FAQ web site.
*/
IPreferenceStore store= JavaPlugin.getDefault().getPreferenceStore();
boolean doNotWarn= store.getBoolean(DO_NOT_WARN_PREFERENCE_KEY);
if (WARNING_DIALOG_ENABLED && !doNotWarn) {
String title= InfoViewMessages.JavadocView_error_noBrowser_title;
String message= InfoViewMessages.JavadocView_error_noBrowser_message;
String toggleMessage= InfoViewMessages.JavadocView_error_noBrowser_doNotWarn;
MessageDialogWithToggle dialog= MessageDialogWithToggle.openError(parent.getShell(), title, message, toggleMessage, false, null, null);
if (dialog.getReturnCode() == Window.OK)
store.setValue(DO_NOT_WARN_PREFERENCE_KEY, dialog.getToggleState());
}
fIsUsingBrowserWidget= false;
}
if (!fIsUsingBrowserWidget) {
fText= new StyledText(parent, SWT.V_SCROLL | SWT.H_SCROLL);
fText.setEditable(false);
fPresenter= new HTMLTextPresenter(false);
fText.addControlListener(new ControlAdapter() {
/*
* @see org.eclipse.swt.events.ControlAdapter#controlResized(org.eclipse.swt.events.ControlEvent)
*/
public void controlResized(ControlEvent e) {
setInput(fText.getText());
}
});
}
initStyleSheet();
getViewSite().setSelectionProvider(new SelectionProvider(getControl()));
}
private static void initStyleSheet() {
Bundle bundle= Platform.getBundle(JavaPlugin.getPluginId());
URL styleSheetURL= bundle.getEntry("/JavadocViewStyleSheet.css"); //$NON-NLS-1$
if (styleSheetURL == null)
return;
try {
styleSheetURL= FileLocator.toFileURL(styleSheetURL);
BufferedReader reader= new BufferedReader(new InputStreamReader(styleSheetURL.openStream()));
StringBuffer buffer= new StringBuffer(200);
String line= reader.readLine();
while (line != null) {
buffer.append(line);
buffer.append('\n');
line= reader.readLine();
}
fgStyleSheet= buffer.toString();
} catch (IOException ex) {
JavaPlugin.log(ex);
}
}
/*
* @see AbstractInfoView#createActions()
*/
protected void createActions() {
super.createActions();
fSelectAllAction= new SelectAllAction(getControl(), (SelectionProvider)getSelectionProvider());
}
/*
* @see org.eclipse.jdt.internal.ui.infoviews.AbstractInfoView#getSelectAllAction()
* @since 3.0
*/
protected IAction getSelectAllAction() {
// FIXME: see https://bugs.eclipse.org/bugs/show_bug.cgi?id=63022
if (fIsUsingBrowserWidget)
return null;
return fSelectAllAction;
}
/*
* @see org.eclipse.jdt.internal.ui.infoviews.AbstractInfoView#getCopyToClipboardAction()
* @since 3.0
*/
protected IAction getCopyToClipboardAction() {
// FIXME: see https://bugs.eclipse.org/bugs/show_bug.cgi?id=63022
if (fIsUsingBrowserWidget)
return null;
return super.getCopyToClipboardAction();
}
/*
* @see AbstractInfoView#setForeground(Color)
*/
protected void setForeground(Color color) {
getControl().setForeground(color);
}
/*
* @see AbstractInfoView#setBackground(Color)
*/
protected void setBackground(Color color) {
getControl().setBackground(color);
// Apply style sheet
fBackgroundColorRGB= color.getRGB();
if (getInput() == null) {
StringBuffer buffer= new StringBuffer(""); //$NON-NLS-1$
HTMLPrinter.insertPageProlog(buffer, 0, fBackgroundColorRGB, fgStyleSheet);
setInput(buffer.toString());
} else {
setInput(computeInput(getInput()));
}
}
/*
* @see org.eclipse.jdt.internal.ui.infoviews.AbstractInfoView#getBackgroundColorKey()
* @since 3.2
*/
protected String getBackgroundColorKey() {
return "org.eclipse.jdt.ui.JavadocView.backgroundColor"; //$NON-NLS-1$
}
/*
* @see AbstractInfoView#internalDispose()
*/
protected void internalDispose() {
fText= null;
fBrowser= null;
}
/*
* @see org.eclipse.ui.part.WorkbenchPart#setFocus()
*/
public void setFocus() {
getControl().setFocus();
}
/*
* @see AbstractInfoView#computeInput(Object)
*/
protected Object computeInput(Object input) {
if (getControl() == null || ! (input instanceof IJavaElement))
return null;
IJavaElement je= (IJavaElement)input;
String javadocHtml;
switch (je.getElementType()) {
case IJavaElement.COMPILATION_UNIT:
try {
javadocHtml= getJavadocHtml(((ICompilationUnit)je).getTypes());
} catch (JavaModelException ex) {
javadocHtml= null;
}
break;
case IJavaElement.CLASS_FILE:
try {
javadocHtml= getJavadocHtml(new IJavaElement[] {((IClassFile)je).getType()});
} catch (JavaModelException ex) {
javadocHtml= null;
}
break;
default:
javadocHtml= getJavadocHtml(new IJavaElement[] { je });
}
if (javadocHtml == null)
return ""; //$NON-NLS-1$
return javadocHtml;
}
/*
* @see AbstractInfoView#setInput(Object)
*/
protected void setInput(Object input) {
String javadocHtml= (String)input;
if (fIsUsingBrowserWidget) {
if (javadocHtml != null && javadocHtml.length() > 0) {
boolean RTL= (getSite().getShell().getStyle() & SWT.RIGHT_TO_LEFT) != 0;
if (RTL) {
StringBuffer buffer= new StringBuffer(javadocHtml);
HTMLPrinter.insertStyles(buffer, new String[] { "direction:rtl" } ); //$NON-NLS-1$
javadocHtml= buffer.toString();
}
}
fBrowser.setText(javadocHtml);
} else {
fPresentation.clear();
Rectangle size= fText.getClientArea();
try {
javadocHtml= ((DefaultInformationControl.IInformationPresenterExtension)fPresenter).updatePresentation(getSite().getShell(), javadocHtml, fPresentation, size.width, size.height);
} catch (IllegalArgumentException ex) {
// the javadoc might no longer be valid
return;
}
fText.setText(javadocHtml);
TextPresentation.applyTextPresentation(fPresentation, fText);
}
}
/**
* Returns the Javadoc in HTML format.
*
* @param result the Java elements for which to get the Javadoc
* @return a string with the Javadoc in HTML format.
*/
private String getJavadocHtml(IJavaElement[] result) {
StringBuffer buffer= new StringBuffer();
int nResults= result.length;
if (nResults == 0)
return null;
if (nResults > 1) {
for (int i= 0; i < result.length; i++) {
HTMLPrinter.startBulletList(buffer);
IJavaElement curr= result[i];
if (curr instanceof IMember)
HTMLPrinter.addBullet(buffer, getInfoText((IMember) curr));
HTMLPrinter.endBulletList(buffer);
}
} else {
IJavaElement curr= result[0];
if (curr instanceof IMember) {
IMember member= (IMember) curr;
// HTMLPrinter.addSmallHeader(buffer, getInfoText(member));
Reader reader;
try {
reader= JavadocContentAccess.getHTMLContentReader(member, true, true);
// Provide hint why there's no Javadoc
if (reader == null && member.isBinary()) {
IPackageFragmentRoot root= (IPackageFragmentRoot)member.getAncestor(IJavaElement.PACKAGE_FRAGMENT_ROOT);
if (root != null && root.getSourceAttachmentPath() == null && root.getAttachedJavadoc(null) == null)
reader= new StringReader(InfoViewMessages.JavadocView_noAttachedInformation);
}
} catch (JavaModelException ex) {
return null;
}
if (reader != null) {
HTMLPrinter.addParagraph(buffer, reader);
}
}
}
boolean flushContent= true;
if (buffer.length() > 0 || flushContent) {
HTMLPrinter.insertPageProlog(buffer, 0, fBackgroundColorRGB, fgStyleSheet);
HTMLPrinter.addPageEpilog(buffer);
return buffer.toString();
}
return null;
}
/**
* Gets the label for the given member.
*
* @param member the Java member
* @return a string containing the member's label
*/
private String getInfoText(IMember member) {
return JavaElementLabels.getElementLabel(member, LABEL_FLAGS);
}
/*
* @see org.eclipse.jdt.internal.ui.infoviews.AbstractInfoView#isIgnoringNewInput(org.eclipse.jdt.core.IJavaElement, org.eclipse.jface.viewers.ISelection)
* @since 3.2
*/
protected boolean isIgnoringNewInput(IJavaElement je, IWorkbenchPart part, ISelection selection) {
if (super.isIgnoringNewInput(je, part, selection)
&& part instanceof ITextEditor
&& selection instanceof ITextSelection) {
ITextEditor editor= (ITextEditor)part;
IDocumentProvider docProvider= editor.getDocumentProvider();
if (docProvider == null)
return false;
IDocument document= docProvider.getDocument(editor.getEditorInput());
if (!(document instanceof IDocumentExtension3))
return false;
try {
int offset= ((ITextSelection)selection).getOffset();
String partition= ((IDocumentExtension3)document).getContentType(IJavaPartitions.JAVA_PARTITIONING, offset, false);
return partition != IJavaPartitions.JAVA_DOC;
} catch (BadPartitioningException ex) {
return false;
} catch (BadLocationException ex) {
return false;
}
}
return false;
}
/*
* @see AbstractInfoView#findSelectedJavaElement(IWorkbenchPart)
*/
protected IJavaElement findSelectedJavaElement(IWorkbenchPart part, ISelection selection) {
IJavaElement element;
try {
element= super.findSelectedJavaElement(part, selection);
if (element == null && part instanceof JavaEditor && selection instanceof ITextSelection) {
JavaEditor editor= (JavaEditor)part;
ITextSelection textSelection= (ITextSelection)selection;
IDocumentProvider documentProvider= editor.getDocumentProvider();
if (documentProvider == null)
return null;
IDocument document= documentProvider.getDocument(editor.getEditorInput());
if (document == null)
return null;
ITypedRegion typedRegion= TextUtilities.getPartition(document, IJavaPartitions.JAVA_PARTITIONING, textSelection.getOffset(), false);
if (IJavaPartitions.JAVA_DOC.equals(typedRegion.getType()))
return TextSelectionConverter.getElementAtOffset((JavaEditor)part, textSelection);
else
return null;
} else
return element;
} catch (JavaModelException e) {
return null;
} catch (BadLocationException e) {
return null;
}
}
/*
* @see AbstractInfoView#getControl()
*/
protected Control getControl() {
if (fIsUsingBrowserWidget)
return fBrowser;
else
return fText;
}
/*
* @see org.eclipse.jdt.internal.ui.infoviews.AbstractInfoView#getHelpContextId()
* @since 3.1
*/
protected String getHelpContextId() {
return IJavaHelpContextIds.JAVADOC_VIEW;
}
}