blob: 8f32a1c9baa7eb8247f351ff06e4109df5d6da1c [file] [log] [blame]
/*=============================================================================#
# Copyright (c) 2008, 2021 Stephan Wahlbrink and others.
#
# This program and the accompanying materials are made available under the
# terms of the Eclipse Public License 2.0 which is available at
# https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
# which is available at https://www.apache.org/licenses/LICENSE-2.0.
#
# SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
#
# Contributors:
# Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
#=============================================================================*/
package org.eclipse.statet.ecommons.text.ui;
import static org.eclipse.statet.jcommons.lang.ObjectUtils.nonNullAssert;
import static org.eclipse.statet.jcommons.lang.ObjectUtils.nonNullLateInit;
import org.eclipse.jface.internal.text.html.BrowserInformationControlInput;
import org.eclipse.jface.internal.text.html.HTMLPrinter;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.swt.graphics.FontData;
import org.eclipse.statet.jcommons.lang.Disposable;
import org.eclipse.statet.jcommons.lang.NonNullByDefault;
import org.eclipse.statet.jcommons.lang.Nullable;
import org.eclipse.statet.internal.ltk.ui.LTKUIPlugin;
/**
*
*/
@NonNullByDefault
public class DefaultBrowserInformationInput extends BrowserInformationControlInput {
public static final int FORMAT_NONE= 0;
public static final int FORMAT_TEXT_INPUT= 1;
public static final int FORMAT_SOURCE_INPUT= 2;
public static final int FORMAT_HTMLBODY_INPUT= 3;
public static final int FORMAT_HTMLSOURCE_INPUT= 4;
private static @Nullable Formatter FORMATTER;
private static class Formatter implements IPropertyChangeListener, Disposable {
private String stylesheet= nonNullLateInit();
public Formatter() {
JFaceResources.getFontRegistry().addListener(this);
LTKUIPlugin.getInstance().addStoppingListener(this);
updateStyleSheet();
}
@Override
public void dispose() {
JFaceResources.getFontRegistry().removeListener(this);
FORMATTER= null;
}
@Override
public void propertyChange(final PropertyChangeEvent event) {
if (event.getProperty().equals(JFaceResources.DIALOG_FONT)) {
updateStyleSheet();
}
}
private void updateStyleSheet() {
String style =
// Font definitions
"html { font-family: sans-serif; font-size: 9pt; font-style: normal; font-weight: normal; }\n" +
"body, h1, h2, h3, h4, h5, h6, p, table, td, caption, th, ul, ol, dl, li, dd, dt { font-size: 1em; }\n" +
"pre { font-family: monospace; }\n" +
// Margins
"html { margin: 0px; padding: 0px }" +
"body { overflow: auto; margin-top: 0.25em; margin-bottom: 0.5em; margin-left: 0.25em; margin-right: 0.25em; }\n" +
"h1 { margin-top: 0.3em; margin-bottom: 0.04em; }\n" +
"h2 { margin-top: 2em; margin-bottom: 0.25em; }\n" +
"h3 { margin-top: 1.7em; margin-bottom: 0.25em; }\n" +
"h4 { margin-top: 2em; margin-bottom: 0.3em; }\n" +
"h5 { margin-top: 0px; margin-bottom: 0px; }\n" +
"p { margin-top: 1em; margin-bottom: 1em; }\n" +
// "pre { margin-left: 0.6em; }\n" +
"ul { margin-top: 0px; margin-bottom: 1em; }\n" +
"li { margin-top: 0px; margin-bottom: 0px; }\n" +
"li p { margin-top: 0px; margin-bottom: 0px; }\n" +
"ol { margin-top: 0px; margin-bottom: 1em; }\n" +
"dl { margin-top: 0px; margin-bottom: 1em; }\n" +
"dt { margin-top: 0px; margin-bottom: 0px; font-weight: bold; }\n" +
"dd { margin-top: 0px; margin-bottom: 0px; }\n" +
// Styles and colors
"a:link { color: #0000FF; }\n" +
"a:hover { color: #000080; }\n" +
"a:visited { text-decoration: underline; }\n" +
"h4 { font-style: italic; }\n" +
"strong { font-weight: bold; }\n" +
"em { font-style: italic; }\n" +
"var { font-style: italic; }\n" +
"th { font-weight: bold; }\n";
try {
final FontData[] fontData= JFaceResources.getFontRegistry().getFontData(JFaceResources.DIALOG_FONT);
if (fontData != null && fontData.length > 0) {
style= style.replace("9pt", fontData[0].getHeight() + "pt");
style= style.replace("sans-serif", "sans-serif, '" + fontData[0].getName() + "'");
}
}
catch (final Throwable e) {
}
this.stylesheet= style;
}
String format(String content, final int formatting,
final int tabSize) {
final String stylesheet= this.stylesheet;
final StringBuilder sb;
switch (formatting) {
case FORMAT_NONE:
return content;
case FORMAT_TEXT_INPUT:
content= HTMLPrinter.convertToHTMLContent(content);
sb= new StringBuilder(content.length() + stylesheet.length() + 500);
sb.append(content);
break;
case FORMAT_HTMLBODY_INPUT:
sb= new StringBuilder(content.length() + stylesheet.length() + 500);
sb.append(content);
break;
case FORMAT_SOURCE_INPUT:
content= HTMLPrinter.convertToHTMLContent(content);
//$FALL-THROUGH$
case FORMAT_HTMLSOURCE_INPUT:
sb= new StringBuilder((int)(content.length() * 1.066) + stylesheet.length() + 500);
sb.append("<pre>"); //$NON-NLS-1$
{ final String spaces= " ".repeat(tabSize); //$NON-NLS-1$
int fromIdx= 0;
int tabIdx;
while ((tabIdx= content.indexOf('\t', fromIdx)) >= 0) {
sb.append(content, fromIdx, tabIdx);
sb.append(spaces);
fromIdx= tabIdx + 1;
}
sb.append(content, fromIdx, content.length());
}
sb.append("</pre>"); //$NON-NLS-1$
break;
default:
throw new IllegalArgumentException("Unsupported format"); //$NON-NLS-1$
}
HTMLPrinter.insertPageProlog(sb, 0, this.stylesheet);
HTMLPrinter.addPageEpilog(sb);
return sb.toString();
}
}
private final String name;
private final String html;
public DefaultBrowserInformationInput(final String name,
final String content, final int formatting,
final int tabSize,
final @Nullable BrowserInformationControlInput previous) {
super(previous);
this.name= nonNullAssert(name);
this.html= getFormatter().format(nonNullAssert(content), formatting, tabSize);
}
public DefaultBrowserInformationInput(final String name,
final String content, final int formatting,
final @Nullable BrowserInformationControlInput previous) {
this(name, content, formatting, 4, previous);
}
public DefaultBrowserInformationInput(final String name,
final String content, final int formatting,
final int tabSize) {
this(name, content, formatting, tabSize, null);
}
public DefaultBrowserInformationInput(final String name,
final String content, final int formatting) {
this(name, content, formatting, 4, null);
}
protected Formatter getFormatter() {
synchronized (DefaultBrowserInformationInput.class) {
var formatter= FORMATTER;
if (formatter == null) {
formatter= new Formatter();
FORMATTER= formatter;
}
return formatter;
}
}
@Override
public String getInputName() {
return this.name;
}
@Override
public Object getInputElement() {
return this.html;
}
@Override
public String getHtml() {
return this.html;
}
}