001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.gui.widgets; 003 004import java.awt.Dimension; 005import java.awt.Rectangle; 006 007import javax.swing.JEditorPane; 008import javax.swing.plaf.basic.BasicHTML; 009import javax.swing.text.View; 010 011/** 012 * Creates a normal label that will wrap its contents if there less width than 013 * required to print it in one line. Additionally the maximum width of the text 014 * can be set using <code>setMaxWidth</code>. 015 * 016 * Note that this won't work if JMultilineLabel is put into a JScrollBox or 017 * similar as the bounds will never change. Instead scrollbars will be displayed. 018 * 019 * @since 6340 020 */ 021public class JMultilineLabel extends JEditorPane { 022 private int maxWidth = Integer.MAX_VALUE; 023 private Rectangle oldbounds; 024 private Dimension oldPreferred; 025 026 /** 027 * Constructs a normal label but adds HTML tags if not already done so. 028 * Supports both newline characters (<code>\n</code>) as well as the HTML 029 * <code><br></code> to insert new lines. 030 * 031 * Use setMaxWidth to limit the width of the label. 032 * @param text The text to display 033 */ 034 public JMultilineLabel(String text) { 035 this(text, false); 036 } 037 038 /** 039 * Constructs a normal label but adds HTML tags if not already done so. 040 * Supports both newline characters (<code>\n</code>) as well as the HTML 041 * <code><br></code> to insert new lines. 042 * 043 * Use setMaxWidth to limit the width of the label. 044 * @param text The text to display 045 * @param allBold If {@code true}, makes all text to be displayed in bold 046 */ 047 public JMultilineLabel(String text, boolean allBold) { 048 this(text, allBold, false); 049 } 050 051 /** 052 * Constructs a normal label but adds HTML tags if not already done so. 053 * Supports both newline characters (<code>\n</code>) as well as the HTML 054 * <code><br></code> to insert new lines. 055 * 056 * Use setMaxWidth to limit the width of the label. 057 * @param text The text to display 058 * @param allBold If {@code true}, makes all text to be displayed in bold 059 * @param focusable indicates whether this label is focusable 060 * @since 13157 061 */ 062 public JMultilineLabel(String text, boolean allBold, boolean focusable) { 063 JosmEditorPane.makeJLabelLike(this, allBold); 064 String html = text.trim().replaceAll("\n", "<br>"); 065 if (!html.startsWith("<html>")) { 066 html = "<html>" + html + "</html>"; 067 } 068 setFocusable(focusable); 069 super.setText(html); 070 } 071 072 /** 073 * Set the maximum width. Use this method instead of setMaximumSize because 074 * this saves a little bit of overhead and is actually taken into account. 075 * 076 * @param width the maximum width 077 */ 078 public void setMaxWidth(int width) { 079 this.maxWidth = width; 080 } 081 082 /** 083 * Tries to determine a suitable height for the given contents and return that dimension. 084 */ 085 @Override 086 public Dimension getPreferredSize() { 087 // Without this check it will result in an infinite loop calling getPreferredSize. 088 // Remember the old bounds and only recalculate if the size actually changed. 089 if (oldPreferred != null && this.getBounds().equals(oldbounds)) { 090 return oldPreferred; 091 } 092 oldbounds = this.getBounds(); 093 094 Dimension superPreferred = super.getPreferredSize(); 095 // Make it not larger than required 096 int width = Math.min(superPreferred.width, maxWidth); 097 098 // Calculate suitable width and height 099 final View v = (View) super.getClientProperty(BasicHTML.propertyKey); 100 101 if (v == null) { 102 return superPreferred; 103 } 104 105 v.setSize(width, 0); 106 int w = (int) Math.ceil(v.getPreferredSpan(View.X_AXIS)); 107 int h = (int) Math.ceil(v.getPreferredSpan(View.Y_AXIS)); 108 109 oldPreferred = new Dimension(w, h); 110 return oldPreferred; 111 } 112}