001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.gui.widgets; 003 004import java.awt.Color; 005import java.awt.Font; 006import java.io.IOException; 007import java.io.InputStream; 008import java.net.URL; 009import java.text.MessageFormat; 010 011import javax.swing.JEditorPane; 012import javax.swing.LookAndFeel; 013import javax.swing.UIDefaults; 014import javax.swing.UIManager; 015import javax.swing.text.html.StyleSheet; 016 017import org.openstreetmap.josm.gui.util.GuiHelper; 018import org.openstreetmap.josm.tools.HttpClient; 019import org.openstreetmap.josm.tools.LanguageInfo; 020 021/** 022 * Subclass of {@link JEditorPane} that adds a "native" context menu (cut/copy/paste/select all) 023 * and effectively uses JOSM user agent when performing HTTP request in {@link #setPage(URL)} method. 024 * @since 5886 025 */ 026public class JosmEditorPane extends JEditorPane { 027 028 /** 029 * Creates a new <code>JosmEditorPane</code>. 030 * The document model is set to <code>null</code>. 031 */ 032 public JosmEditorPane() { 033 TextContextualPopupMenu.enableMenuFor(this, true); 034 } 035 036 /** 037 * Creates a <code>JosmEditorPane</code> based on a specified URL for input. 038 * 039 * @param initialPage the URL 040 * @throws IOException if the URL is <code>null</code> or cannot be accessed 041 */ 042 public JosmEditorPane(URL initialPage) throws IOException { 043 this(); 044 setPage(initialPage); 045 } 046 047 /** 048 * Creates a <code>JosmEditorPane</code> based on a string containing 049 * a URL specification. 050 * 051 * @param url the URL 052 * @throws IOException if the URL is <code>null</code> or cannot be accessed 053 */ 054 public JosmEditorPane(String url) throws IOException { 055 this(); 056 setPage(url); 057 } 058 059 /** 060 * Creates a <code>JosmEditorPane</code> that has been initialized 061 * to the given text. This is a convenience constructor that calls the 062 * <code>setContentType</code> and <code>setText</code> methods. 063 * 064 * @param type mime type of the given text 065 * @param text the text to initialize with; may be <code>null</code> 066 * @throws NullPointerException if the <code>type</code> parameter 067 * is <code>null</code> 068 */ 069 public JosmEditorPane(String type, String text) { 070 this(); 071 setContentType(type); 072 setText(text); 073 } 074 075 @Override 076 protected InputStream getStream(URL page) throws IOException { 077 final HttpClient.Response conn = HttpClient.create(page).connect(); 078 String type = conn.getContentType(); 079 if (type != null) { 080 setContentType(type); 081 } 082 return conn.getContent(); 083 } 084 085 /** 086 * Adapts a {@link JEditorPane} to be used as a powerful replacement of {@link javax.swing.JLabel}. 087 * @param pane The editor pane to adapt 088 * @param allBold If {@code true}, makes all text to be displayed in bold 089 */ 090 public static void makeJLabelLike(JEditorPane pane, boolean allBold) { 091 pane.setContentType("text/html"); 092 pane.setOpaque(false); 093 pane.setEditable(false); 094 adaptForNimbus(pane); 095 096 JosmHTMLEditorKit kit = new JosmHTMLEditorKit(); 097 final Font f = UIManager.getFont("Label.font"); 098 final StyleSheet ss = new StyleSheet(); 099 ss.addRule((allBold ? "html" : "strong, b") + " {" + getFontRule(f) + '}'); 100 ss.addRule("a {text-decoration: underline; color: blue}"); 101 ss.addRule("h1 {" + getFontRule(GuiHelper.getTitleFont()) + '}'); 102 ss.addRule("ol {margin-left: 1cm; margin-top: 0.1cm; margin-bottom: 0.2cm; list-style-type: decimal}"); 103 ss.addRule("ul {margin-left: 1cm; margin-top: 0.1cm; margin-bottom: 0.2cm; list-style-type: disc}"); 104 if ("km".equals(LanguageInfo.getJOSMLocaleCode())) { 105 // Fix rendering problem for Khmer script 106 ss.addRule("p {" + getFontRule(UIManager.getFont("Label.font")) + '}'); 107 } 108 kit.setStyleSheet(ss); 109 pane.setEditorKit(kit); 110 } 111 112 /** 113 * Adapts a {@link JEditorPane} for Nimbus look and feel. 114 * See <a href="https://stackoverflow.com/q/15228336/2257172">this StackOverflow question</a>. 115 * @param pane The editor pane to adapt 116 * @since 6935 117 */ 118 public static void adaptForNimbus(JEditorPane pane) { 119 LookAndFeel currentLAF = UIManager.getLookAndFeel(); 120 if (currentLAF != null && "Nimbus".equals(currentLAF.getName())) { 121 Color bgColor = UIManager.getColor("Label.background"); 122 UIDefaults defaults = new UIDefaults(); 123 defaults.put("EditorPane[Enabled].backgroundPainter", bgColor); 124 pane.putClientProperty("Nimbus.Overrides", defaults); 125 pane.putClientProperty("Nimbus.Overrides.InheritDefaults", Boolean.TRUE); 126 pane.setBackground(bgColor); 127 } 128 } 129 130 private static String getFontRule(Font f) { 131 return MessageFormat.format( 132 "font-family: ''{0}'';font-size: {1,number}pt; font-weight: {2}; font-style: {3}", 133 f.getName(), 134 f.getSize(), 135 "bold", 136 f.isItalic() ? "italic" : "normal" 137 ); 138 } 139}