001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.gui.widgets; 003 004import java.awt.BorderLayout; 005import java.awt.Font; 006import java.text.MessageFormat; 007import java.util.Arrays; 008import java.util.Optional; 009 010import javax.swing.JEditorPane; 011import javax.swing.JPanel; 012import javax.swing.UIManager; 013import javax.swing.event.HyperlinkEvent; 014import javax.swing.event.HyperlinkListener; 015import javax.swing.text.html.StyleSheet; 016 017import org.openstreetmap.josm.tools.OpenBrowser; 018 019/** 020 * This panel can be used to display larger sections of formatted text in 021 * HTML. 022 * 023 * It displays HTML text in the same font as {@link javax.swing.JLabel}. Hyperlinks are rendered in 024 * blue and they are underlined. There is also a CSS rule for the HTML tag <strong> 025 * configured. 026 * @since 2688 027 */ 028public class HtmlPanel extends JPanel { 029 030 private static final HyperlinkListener defaultHyperlinkListener = e -> { 031 if (HyperlinkEvent.EventType.ACTIVATED.equals(e.getEventType()) && e.getURL() != null) { 032 OpenBrowser.displayUrl(e.getURL().toString()); 033 } 034 }; 035 036 private JosmEditorPane jepMessage; 037 038 protected final void build() { 039 setLayout(new BorderLayout()); 040 jepMessage = new JosmEditorPane("text/html", ""); 041 jepMessage.setOpaque(false); 042 jepMessage.setEditable(false); 043 Font f = UIManager.getFont("Label.font"); 044 StyleSheet ss = new StyleSheet(); 045 ss.addRule("body {" + MessageFormat.format( 046 "font-family: ''{0}'';font-size: {1,number}pt; font-weight: {2}; font-style: {3}", 047 f.getName(), 048 f.getSize(), 049 f.isBold() ? "bold" : "normal", 050 f.isItalic() ? "italic" : "normal" 051 ) + '}'); 052 ss.addRule("strong {" + MessageFormat.format( 053 "font-family: ''{0}'';font-size: {1,number}pt; font-weight: {2}; font-style: {3}", 054 f.getName(), 055 f.getSize(), 056 "bold", 057 f.isItalic() ? "italic" : "normal" 058 ) + '}'); 059 ss.addRule("a {text-decoration: underline; color: blue}"); 060 ss.addRule("ul {margin-left: 1cm; list-style-type: disc}"); 061 JosmHTMLEditorKit kit = new JosmHTMLEditorKit(); 062 kit.setStyleSheet(ss); 063 jepMessage.setEditorKit(kit); 064 065 add(jepMessage, BorderLayout.CENTER); 066 } 067 068 /** 069 * Constructs a new {@code HtmlPanel}. 070 */ 071 public HtmlPanel() { 072 build(); 073 } 074 075 /** 076 * Constructs a new {@code HtmlPanel} with the given HTML text. 077 * @param text the text to display 078 */ 079 public HtmlPanel(String text) { 080 this(); 081 setText(text); 082 } 083 084 /** 085 * Replies the editor pane used internally to render the HTML text. 086 * 087 * @return the editor pane used internally to render the HTML text. 088 */ 089 public JEditorPane getEditorPane() { 090 return jepMessage; 091 } 092 093 /** 094 * Sets the current text to display. <code>text</code> is a html fragment. 095 * If null, empty string is assumed. 096 * 097 * @param text the text to display 098 */ 099 public final void setText(String text) { 100 jepMessage.setText(Optional.ofNullable(text).orElse("")); 101 } 102 103 /** 104 * Opens hyperlinks on click. 105 * @since 13111 106 */ 107 public final void enableClickableHyperlinks() { 108 if (!Arrays.asList(jepMessage.getHyperlinkListeners()).contains(defaultHyperlinkListener)) { 109 jepMessage.addHyperlinkListener(defaultHyperlinkListener); 110 } 111 } 112}