Ignore:
Timestamp:
2009-09-16T23:20:13+02:00 (15 years ago)
Author:
xeen
Message:

Rewrite JMultilineLabel to support HTML markup.
this closes #3500

Location:
trunk/src/org/openstreetmap/josm/gui
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/gui/ExtendedDialog.java

    r2141 r2154  
    135135     */
    136136    public void setContent(String message) {
    137         setContent(string2label(message), true);
     137        setContent(string2label(message), false);
    138138    }
    139139
     
    388388    private static JMultilineLabel string2label(String msg) {
    389389        JMultilineLabel lbl = new JMultilineLabel(msg);
    390         // Make it not wider than 2/3 of the screen
     390        // Make it not wider than 1/2 of the screen
    391391        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
    392         lbl.setMaxWidth(Math.round(screenSize.width*2/3));
     392        lbl.setMaxWidth(Math.round(screenSize.width*1/2));
    393393        return lbl;
    394394    }
  • trunk/src/org/openstreetmap/josm/gui/JMultilineLabel.java

    r2017 r2154  
    11// License: GPL. For details, see LICENSE file.
    2 
    3 // This class was taken from
    4 // http://forum.java.sun.com/thread.jspa?threadID=459705&messageID=2104021
    5 // - Removed hardcoded margin
    6 // -  Added constructor
    72
    83package org.openstreetmap.josm.gui;
    94
    105import java.awt.Dimension;
    11 import java.awt.Graphics;
    12 import java.awt.Graphics2D;
    13 import java.awt.Insets;
    14 import java.awt.font.FontRenderContext;
    15 import java.awt.font.LineBreakMeasurer;
    16 import java.awt.font.TextAttribute;
    17 import java.awt.font.TextLayout;
    18 import java.text.AttributedCharacterIterator;
    19 import java.text.AttributedString;
     6import java.awt.Rectangle;
    207
    21 import javax.swing.JComponent;
     8import javax.swing.JLabel;
     9import javax.swing.plaf.basic.BasicHTML;
     10import javax.swing.text.View;
    2211
    23 public class JMultilineLabel extends JComponent {
    24     private String text;
     12/**
     13 * Creates a normal label that will wrap its contents if there less width than
     14 * required to print it in one line. Additionally the maximum width of the text
     15 * can be set using <code>setMaxWidth</code>.
     16 *
     17 * Note that this won't work if JMultilineLabel is put into a JScrollBox or
     18 * similar as the bounds will never change. Instead scrollbars will be displayed.
     19 */
     20public class JMultilineLabel extends JLabel {
    2521    private int maxWidth = Integer.MAX_VALUE;
    26     private boolean justify;
    27     private final FontRenderContext frc = new FontRenderContext(null, false, false);
     22    private Dimension superPreferred = null;
     23    private Rectangle oldbounds = null;
     24    private Dimension oldPreferred = null;
    2825
    29     public JMultilineLabel(String description) {
     26    /**
     27     * Constructs a normal label but adds HTML tags if not already done so.
     28     * Supports both newline characters (<code>\n</code>) as well as the HTML
     29     * <code>&lt;br&gt;</code> to insert new lines.
     30     *
     31     * Use setMaxWidth to limit the width of the label.
     32     * @param text
     33     */
     34    public JMultilineLabel(String text)
     35    {
    3036        super();
    31         setText(description);
     37        text = text.trim().replaceAll("\n", "<br>");
     38        if(!text.startsWith("<html>")) {
     39            text = "<html>" + text + "</html>";
     40        }
     41        super.setText(text);
    3242    }
    3343
    34     private void morph() {
    35         revalidate();
    36         repaint();
     44    /**
     45     * Set the maximum width. Use this method instead of setMaximumSize because
     46     * this saves a little bit of overhead and is actually taken into account.
     47     *
     48     * @param width
     49     */
     50    public void setMaxWidth(int width) {
     51        this.maxWidth = width;
    3752    }
    3853
    39     public String getText() {
    40         return text;
    41     }
     54    /**
     55     * Tries to determine a suitable height for the given contents and return
     56     * that dimension.
     57     */
     58    @Override
     59    public Dimension getPreferredSize()
     60    {
     61        // Without this check it will result in an infinite loop calling
     62        // getPreferredSize. Remember the old bounds and only recalculate if
     63        // the size actually changed.
     64        if(this.getBounds().equals(oldbounds) && oldPreferred != null)
     65            return oldPreferred;
     66        oldbounds = this.getBounds();
    4267
    43     public void setText(String text) {
    44         String old = this.text;
    45         this.text = text;
    46         firePropertyChange("text", old, this.text);
    47         if ((old == null) ? text!=null : !old.equals(text))
    48             morph();
    49     }
     68        this.superPreferred = super.getPreferredSize();
     69        // Make it not larger than required
     70        int width = Math.min(superPreferred.width, maxWidth);
    5071
    51     public int getMaxWidth() {
    52         return maxWidth;
    53     }
     72        // Calculate suitable width and height
     73        final View v = (View) super.getClientProperty(BasicHTML.propertyKey);
    5474
    55     public void setMaxWidth(int maxWidth) {
    56         if (maxWidth <= 0)
    57             throw new IllegalArgumentException();
    58         int old = this.maxWidth;
    59         this.maxWidth = maxWidth;
    60         firePropertyChange("maxWidth", old, this.maxWidth);
    61         if (old !=  this.maxWidth)
    62             morph();
    63     }
     75        if(v == null)
     76            return superPreferred;
    6477
    65     public boolean isJustified() {
    66         return justify;
    67     }
     78        v.setSize(width, 0);
     79        int w = (int) Math.ceil(v.getPreferredSpan(View.X_AXIS));
     80        int h = (int) Math.ceil(v.getPreferredSpan(View.Y_AXIS));
    6881
    69     public void setJustified(boolean justify) {
    70         boolean old = this.justify;
    71         this.justify = justify;
    72         firePropertyChange("justified", old, this.justify);
    73         if (old != this.justify)
    74             repaint();
    75     }
    76 
    77     public Dimension getPreferredSize() {
    78         return paintOrGetSize(null, getMaxWidth());
    79     }
    80 
    81     public Dimension getMinimumSize() {
    82         return getPreferredSize();
    83     }
    84 
    85     protected void paintComponent(Graphics g) {
    86         super.paintComponent(g);
    87         paintOrGetSize((Graphics2D)g, getWidth());
    88     }
    89 
    90     private Dimension paintOrGetSize(Graphics2D g, int width) {
    91         Insets insets = getInsets();
    92         width -= insets.left + insets.right;
    93         float w = insets.left + insets.right;
    94         float x = insets.left, y=insets.top;
    95 
    96         if (width > 0 && text != null && text.length() > 0) {
    97             String[] lines = getText().split("\n");
    98             for(String line : lines) {
    99                 // Insert a space so new lines get rendered
    100                 if(line.length() == 0) line = " ";
    101                 AttributedString as = new AttributedString(line);
    102                 as.addAttribute(TextAttribute.FONT, getFont());
    103                 AttributedCharacterIterator aci = as.getIterator();
    104                 LineBreakMeasurer lbm = new LineBreakMeasurer(aci, frc);
    105                 float max = 0;
    106                 while (lbm.getPosition() < aci.getEndIndex()) {
    107                     TextLayout textLayout = lbm.nextLayout(width);
    108                     if (g != null && isJustified() && textLayout.getVisibleAdvance() > 0.80 * width)
    109                         textLayout = textLayout.getJustifiedLayout(width);
    110                     if (g != null)
    111                         textLayout.draw(g, x, y + textLayout.getAscent());
    112                     y += textLayout.getDescent() + textLayout.getLeading() + textLayout.getAscent();
    113                     max = Math.max(max, textLayout.getVisibleAdvance());
    114                 }
    115                 w = Math.max(max, w);
    116             }
    117         }
    118         return new Dimension((int)Math.ceil(w), (int)Math.ceil(y) + insets.bottom);
     82        oldPreferred = new Dimension(w, h);
     83        return oldPreferred;
    11984    }
    12085}
Note: See TracChangeset for help on using the changeset viewer.