/**
* Copyright (c) 2013-2016 Angelo ZERR.
* 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:
* Angelo Zerr <angelo.zerr@gmail.com> - initial API and implementation
*/
package tern.eclipse.ide.ui.utils;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import org.eclipse.core.runtime.Platform;
import org.eclipse.jface.internal.text.html.HTMLPrinter;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.swt.graphics.FontData;
import org.eclipse.swt.graphics.RGB;
import org.osgi.framework.Bundle;
import tern.eclipse.ide.internal.ui.TernUIMessages;
import tern.eclipse.ide.internal.ui.Trace;
import tern.eclipse.ide.ui.TernUIPlugin;
import tern.eclipse.jface.text.HoverLocationListener;
import tern.server.protocol.completions.Parameter;
import tern.server.protocol.completions.TernCompletionItem;
import tern.utils.StringUtils;
/**
* Provides a set of convenience methods for creating HTML info for tern content
* assist and hover.
*
*/
public class HTMLTernPrinter {
/**
* Style sheets content.
*/
private static String fgStyleSheet;
private static RGB colorInfoBackround = null;
private static RGB colorInfoForeground = null;
private HTMLTernPrinter() {
}
public static void setColorInfoBackround(RGB colorInfoBackround) {
HTMLTernPrinter.colorInfoBackround = colorInfoBackround;
}
public static void setColorInfoForeground(RGB colorInfoForeground) {
HTMLTernPrinter.colorInfoForeground = colorInfoForeground;
}
public static String getAdditionalProposalInfo(TernCompletionItem item,
Boolean guess) {
StringBuffer buffer = new StringBuffer();
ImageDescriptor descriptor = TernUIPlugin.getTernDescriptorManager()
.getImageDescriptor(item);
startPage(buffer, getTitle(item), descriptor);
// doc
addDocContent(buffer, item.getDoc());
startDefinitionList(buffer);
// parameters
addParametersContent(buffer, item.getParameters());
// return type
addReturnTypeContent(buffer, item.getJsType());
// origin
addOriginContent(buffer, item.getOrigin());
// guess?
addGuessContent(buffer, guess);
// url
addURLContent(buffer, item.getURL());
endDefinitionList(buffer);
endPage(buffer);
return buffer.toString();
}
public static void addGuessContent(StringBuffer buffer, Boolean guess) {
if (guess != null) {
addDefinitionListItem(buffer, "Guess?", guess.toString());
}
}
public static void addReturnTypeContent(StringBuffer buffer,
String returnType) {
if (!StringUtils.isEmpty(returnType)) {
buffer.append("<dt><b>Returns:</b></dt>");
buffer.append("<dd>");
buffer.append("<code>");
buffer.append(returnType);
buffer.append("</code>");
buffer.append("</dd>");
}
}
public static void addParametersContent(StringBuffer buffer,
List<Parameter> parameters) {
if (parameters != null) {
buffer.append("<dt><b>Parameters:</b></dt>");
for (Parameter parameter : parameters) {
buffer.append("<dd>");
if (!parameter.isRequired()) {
buffer.append("[");
}
buffer.append("<code>");
buffer.append(parameter.getName());
buffer.append("</code>");
if (!parameter.isRequired()) {
buffer.append("]");
}
buffer.append(" - ");
buffer.append("<code>");
buffer.append(parameter.getType());
buffer.append("</code>");
buffer.append("</dd>");
}
}
}
public static String getTitle(TernCompletionItem item) {
String title = item.hasDisplayName() ? item.getDisplayName() : item.getSignature();
StringBuilder buffer = new StringBuilder("<b>").append(
title).append("</b>");
return buffer.toString();
}
public static void addDocContent(StringBuffer buffer, String doc) {
buffer.append("<p>");
if (doc != null) {
buffer.append(doc);
}
buffer.append("</p>");
}
public static void endPage(StringBuffer buffer) {
HTMLPrinter
.insertPageProlog(buffer, 0, colorInfoForeground, colorInfoBackround, HTMLTernPrinter.getStyleSheet());
HTMLPrinter.addPageEpilog(buffer);
}
public static void addOriginContent(StringBuffer buffer, String origin) {
addLinkContent(buffer, "Origin", new StringBuilder(
HoverLocationListener.TERN_FILE_PROTOCOL).append(origin).toString(),
origin);
}
public static void addDefinitionListItem(StringBuffer buffer, String name,
String value) {
if (!StringUtils.isEmpty(value)) {
buffer.append("<dt><b>");
buffer.append(name);
buffer.append(":</b></dt>");
buffer.append("<dd>");
buffer.append(value);
buffer.append("</dd>");
}
}
public static void addDefinitionListItem(StringBuffer buffer, String name,
Collection<String> values) {
if (values != null && !values.isEmpty()) {
addDefinitionListItem(buffer, name,
Arrays.toString(values.toArray()));
}
}
public static void addURLContent(StringBuffer buffer, String url) {
if (!StringUtils.isEmpty(url)) {
addLinkContent(buffer, "See", url, url);
}
}
protected static void addLinkContent(StringBuffer buffer, String label,
String linkHref, String linkLabel) {
buffer.append("<dt><b>");
buffer.append(label);
buffer.append(":</b></dt>");
buffer.append("<dd>");
buffer.append("<a href=\"");
buffer.append(linkHref);
buffer.append("\" >");
buffer.append(linkLabel);
buffer.append("</a>");
buffer.append("</dd>");
}
public static void startDefinitionList(StringBuffer buffer) {
buffer.append("<dl>"); //$NON-NLS-1$
}
public static void endDefinitionList(StringBuffer buffer) {
buffer.append("</dl>"); //$NON-NLS-1$
}
/**
* Returns the Javadoc hover style sheet with the current Javadoc font from
* the preferences.
*
* @return the updated style sheet
* @since 3.4
*/
private static String getStyleSheet() {
if (fgStyleSheet == null) {
fgStyleSheet = loadStyleSheet("/TernHoverStyleSheet.css"); //$NON-NLS-1$
}
String css = fgStyleSheet;
if (css != null) {
FontData fontData = JFaceResources.getFontRegistry().getFontData(
JFaceResources.DIALOG_FONT)[0];
css = HTMLPrinter.convertTopLevelFont(css, fontData);
}
return css;
}
/**
* Loads and returns the style sheet associated with either Javadoc hover or
* the view.
*
* @param styleSheetName
* the style sheet name of either the Javadoc hover or the view
* @return the style sheet, or <code>null</code> if unable to load
* @since 3.4
*/
private static String loadStyleSheet(String styleSheetName) {
Bundle bundle = Platform.getBundle(TernUIPlugin.PLUGIN_ID);
URL styleSheetURL = bundle.getEntry(styleSheetName);
if (styleSheetURL == null)
return null;
BufferedReader reader = null;
try {
reader = new BufferedReader(new InputStreamReader(
styleSheetURL.openStream()));
StringBuffer buffer = new StringBuffer(1500);
String line = reader.readLine();
while (line != null) {
buffer.append(line);
buffer.append('\n');
line = reader.readLine();
}
FontData fontData = JFaceResources.getFontRegistry().getFontData(
JFaceResources.DIALOG_FONT)[0];
return HTMLPrinter.convertTopLevelFont(buffer.toString(), fontData);
} catch (IOException ex) {
Trace.trace(Trace.SEVERE, "Error while loading style sheets", ex);
return ""; //$NON-NLS-1$
} finally {
try {
if (reader != null)
reader.close();
} catch (IOException e) {
// ignore
}
}
}
public static void startPage(StringBuffer buf, String title,
ImageDescriptor descriptor) {
int imageWidth = 16;
int imageHeight = 16;
int labelLeft = 20;
int labelTop = 2;
// buf.append("<p>");
buf.append("<div style='word-wrap: break-word; position: relative; "); //$NON-NLS-1$
String imageSrcPath = getImageURL(descriptor);
if (imageSrcPath != null) {
buf.append("margin-left: ").append(labelLeft).append("px; "); //$NON-NLS-1$ //$NON-NLS-2$
buf.append("padding-top: ").append(labelTop).append("px; "); //$NON-NLS-1$ //$NON-NLS-2$
}
buf.append("'>"); //$NON-NLS-1$
if (imageSrcPath != null) {
String uri = HoverLocationListener.TERN_DEFINITION_PROTOCOL;
buf.append("<a href=\"");
buf.append(uri);
buf.append("\" >");
StringBuffer imageStyle = new StringBuffer(
"border:none; position: absolute; "); //$NON-NLS-1$
imageStyle.append("width: ").append(imageWidth).append("px; "); //$NON-NLS-1$ //$NON-NLS-2$
imageStyle.append("height: ").append(imageHeight).append("px; "); //$NON-NLS-1$ //$NON-NLS-2$
imageStyle.append("left: ").append(-labelLeft - 1).append("px; "); //$NON-NLS-1$ //$NON-NLS-2$
// hack for broken transparent PNG support in IE 6, see
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=223900 :
buf.append("<!--[if lte IE 6]><![if gte IE 5.5]>\n"); //$NON-NLS-1$
String tooltip = "alt='" + TernUIMessages.TernHover_openDeclaration + "' "; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
buf.append("<span ").append(tooltip).append("style=\"").append(imageStyle). //$NON-NLS-1$ //$NON-NLS-2$
append("filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src='").append(imageSrcPath).append("')\"></span>\n"); //$NON-NLS-1$ //$NON-NLS-2$
buf.append("<![endif]><![endif]-->\n"); //$NON-NLS-1$
buf.append("<!--[if !IE]>-->\n"); //$NON-NLS-1$
buf.append("<img ").append(tooltip).append("style='").append(imageStyle).append("' src='").append(imageSrcPath).append("'/>\n"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
buf.append("<!--<![endif]-->\n"); //$NON-NLS-1$
buf.append("<!--[if gte IE 7]>\n"); //$NON-NLS-1$
buf.append("<img ").append(tooltip).append("style='").append(imageStyle).append("' src='").append(imageSrcPath).append("'/>\n"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
buf.append("<![endif]-->\n"); //$NON-NLS-1$
// if (element != null) {
buf.append("</a>"); //$NON-NLS-1$
// }
}
buf.append(title);
buf.append("</div>"); //$NON-NLS-1$
buf.append("<hr />");
}
private static String getImageURL(ImageDescriptor descriptor) {
if (descriptor == null) {
return null;
}
String imageName = null;
URL imageUrl = TernUIPlugin.getTernDescriptorManager().getImageURL(
descriptor);
if (imageUrl != null) {
imageName = imageUrl.toExternalForm();
}
return imageName;
}
}