// License: GPL. For details, see LICENSE file. package org.openstreetmap.josm.gui.widgets; import java.awt.Dimension; import java.awt.Rectangle; import javax.swing.JEditorPane; import javax.swing.plaf.basic.BasicHTML; import javax.swing.text.View; /** * Creates a normal label that will wrap its contents if there less width than * required to print it in one line. Additionally the maximum width of the text * can be set using <code>setMaxWidth</code>. * * Note that this won't work if JMultilineLabel is put into a JScrollBox or * similar as the bounds will never change. Instead scrollbars will be displayed. * * @since 6340 */ public class JMultilineLabel extends JEditorPane { private int maxWidth = Integer.MAX_VALUE; private Rectangle oldbounds; private Dimension oldPreferred; /** * Constructs a normal label but adds HTML tags if not already done so. * Supports both newline characters (<code>\n</code>) as well as the HTML * <code><br></code> to insert new lines. * * Use setMaxWidth to limit the width of the label. * @param text The text to display */ public JMultilineLabel(String text) { this(text, false); } /** * Constructs a normal label but adds HTML tags if not already done so. * Supports both newline characters (<code>\n</code>) as well as the HTML * <code><br></code> to insert new lines. * * Use setMaxWidth to limit the width of the label. * @param text The text to display * @param allBold If {@code true}, makes all text to be displayed in bold */ public JMultilineLabel(String text, boolean allBold) { JosmEditorPane.makeJLabelLike(this, allBold); String html = text.trim().replaceAll("\n", "<br>"); if (!html.startsWith("<html>")) { html = "<html>" + html + "</html>"; } setFocusable(false); super.setText(html); } /** * Set the maximum width. Use this method instead of setMaximumSize because * this saves a little bit of overhead and is actually taken into account. * * @param width the maximum width */ public void setMaxWidth(int width) { this.maxWidth = width; } /** * Tries to determine a suitable height for the given contents and return that dimension. */ @Override public Dimension getPreferredSize() { // Without this check it will result in an infinite loop calling getPreferredSize. // Remember the old bounds and only recalculate if the size actually changed. if (oldPreferred != null && this.getBounds().equals(oldbounds)) { return oldPreferred; } oldbounds = this.getBounds(); Dimension superPreferred = super.getPreferredSize(); // Make it not larger than required int width = Math.min(superPreferred.width, maxWidth); // Calculate suitable width and height final View v = (View) super.getClientProperty(BasicHTML.propertyKey); if (v == null) { return superPreferred; } v.setSize(width, 0); int w = (int) Math.ceil(v.getPreferredSpan(View.X_AXIS)); int h = (int) Math.ceil(v.getPreferredSpan(View.Y_AXIS)); oldPreferred = new Dimension(w, h); return oldPreferred; } }