Changeset 2154 in josm


Ignore:
Timestamp:
Sep 16, 2009 11:20:13 PM (4 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.