001 // License: GPL. For details, see LICENSE file. 002 003 package org.openstreetmap.josm.gui; 004 005 import java.awt.Dimension; 006 import java.awt.Rectangle; 007 008 import javax.swing.JLabel; 009 import javax.swing.plaf.basic.BasicHTML; 010 import javax.swing.text.View; 011 012 /** 013 * Creates a normal label that will wrap its contents if there less width than 014 * required to print it in one line. Additionally the maximum width of the text 015 * can be set using <code>setMaxWidth</code>. 016 * 017 * Note that this won't work if JMultilineLabel is put into a JScrollBox or 018 * similar as the bounds will never change. Instead scrollbars will be displayed. 019 */ 020 public class JMultilineLabel extends JLabel { 021 private int maxWidth = Integer.MAX_VALUE; 022 private Dimension superPreferred = null; 023 private Rectangle oldbounds = null; 024 private Dimension oldPreferred = null; 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 033 */ 034 public JMultilineLabel(String text) 035 { 036 super(); 037 text = text.trim().replaceAll("\n", "<br>"); 038 if(!text.startsWith("<html>")) { 039 text = "<html>" + text + "</html>"; 040 } 041 super.setText(text); 042 } 043 044 /** 045 * Set the maximum width. Use this method instead of setMaximumSize because 046 * this saves a little bit of overhead and is actually taken into account. 047 * 048 * @param width 049 */ 050 public void setMaxWidth(int width) { 051 this.maxWidth = width; 052 } 053 054 /** 055 * Tries to determine a suitable height for the given contents and return 056 * that dimension. 057 */ 058 @Override 059 public Dimension getPreferredSize() 060 { 061 // Without this check it will result in an infinite loop calling 062 // getPreferredSize. Remember the old bounds and only recalculate if 063 // the size actually changed. 064 if(this.getBounds().equals(oldbounds) && oldPreferred != null) 065 return oldPreferred; 066 oldbounds = this.getBounds(); 067 068 this.superPreferred = super.getPreferredSize(); 069 // Make it not larger than required 070 int width = Math.min(superPreferred.width, maxWidth); 071 072 // Calculate suitable width and height 073 final View v = (View) super.getClientProperty(BasicHTML.propertyKey); 074 075 if(v == null) 076 return superPreferred; 077 078 v.setSize(width, 0); 079 int w = (int) Math.ceil(v.getPreferredSpan(View.X_AXIS)); 080 int h = (int) Math.ceil(v.getPreferredSpan(View.Y_AXIS)); 081 082 oldPreferred = new Dimension(w, h); 083 return oldPreferred; 084 } 085 }