package com.jstatcom.component;

// source: http://codeguru.earthweb.com/java/articles/198.shtml
import java.awt.Dimension;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.util.StringTokenizer;

import javax.swing.Icon;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.plaf.basic.BasicGraphicsUtils;
import javax.swing.plaf.basic.BasicLabelUI;

/**
 * * Author: Zafir Anjum * http://codeguru.earthweb.com/java/articles/198.shtml * *
 * Use multi-line text in a JLabel. * To enable multi-line in a JLabel we have
 * to specify our own LabelUI * class that will render the multiple lines.
 * Although the code shown * below seems quite long, most of it is actually
 * Swing code being reused. * *
 */
public final class MultiLineLabelUI extends BasicLabelUI {
    static {
        labelUI = new MultiLineLabelUI();
    }

    static final int LEADING = SwingConstants.LEADING;

    static final int TRAILING = SwingConstants.TRAILING;

    static final int LEFT = SwingConstants.LEFT;

    static final int RIGHT = SwingConstants.RIGHT;

    static final int TOP = SwingConstants.TOP;

    static final int CENTER = SwingConstants.CENTER;

    protected String str;

    protected String[] strs;

    public static Dimension computeMultiLineDimension(FontMetrics fm,
            String[] strs) {
        int i, c, width = 0;
        for (i = 0, c = strs.length; i < c; i++)
            width = Math.max(width, SwingUtilities.computeStringWidth(fm,
                    strs[i]));
        return new Dimension(width, fm.getHeight() * strs.length);
    }

    protected void drawString(Graphics g, String s, int accChar, int textX,
            int textY) {
        if (s.indexOf('\n') == -1)
            BasicGraphicsUtils.drawString(g, s, accChar, textX, textY);
        else {
            String[] strs = splitStringByLines(s);
            int height = g.getFontMetrics().getHeight();
            // Only the first line can have the accel char
            BasicGraphicsUtils.drawString(g, strs[0], accChar, textX, textY);
            for (int i = 1; i < strs.length; i++)
                g.drawString(strs[i], textX, textY + (height * i));
        }
    }

    protected String layoutCL(JLabel label, FontMetrics fontMetrics,
            String text, Icon icon, Rectangle viewR, Rectangle iconR,
            Rectangle textR) {
        String s = layoutCompoundLabel(label, fontMetrics,
                splitStringByLines(text), icon, label.getVerticalAlignment(),
                label.getHorizontalAlignment(),
                label.getVerticalTextPosition(), label
                        .getHorizontalTextPosition(), viewR, iconR, textR,
                label.getIconTextGap());

        if (s.equals(""))
            return text;
        return s;
    }

    /**
     * Compute and return the location of the icons origin, the location of
     * origin of the text baseline, and a possibly clipped version of the
     * compound labels string. Locations are computed relative to the viewR
     * rectangle. This layoutCompoundLabel() does not know how to handle
     * LEADING/TRAILING values in horizontalTextPosition (they will default to
     * RIGHT) and in horizontalAlignment (they will default to CENTER). Use the
     * other version of layoutCompoundLabel() instead.
     */
    public static String layoutCompoundLabel(FontMetrics fm, String[] text,
            Icon icon, int verticalAlignment, int horizontalAlignment,
            int verticalTextPosition, int horizontalTextPosition,
            Rectangle viewR, Rectangle iconR, Rectangle textR, int textIconGap) {
        /*
         * Initialize the icon bounds rectangle iconR.
         */

        if (icon != null) {
            iconR.width = icon.getIconWidth();
            iconR.height = icon.getIconHeight();
        } else {
            iconR.width = iconR.height = 0;
        }

        /*
         * Initialize the text bounds rectangle textR. If a null or and empty
         * String was specified we substitute "" here and use 0,0,0,0 for textR.
         */

        // Fix for textIsEmpty sent by Paulo Santos
        boolean textIsEmpty = (text == null)
                || (text.length == 0)
                || (text.length == 1 && ((text[0] == null) || text[0]
                        .equals("")));

        String rettext = "";
        if (textIsEmpty) {
            textR.width = textR.height = 0;
        } else {
            Dimension dim = computeMultiLineDimension(fm, text);
            textR.width = dim.width;
            textR.height = dim.height;
        }

        /*
         * Unless both text and icon are non-null, we effectively ignore the
         * value of textIconGap. The code that follows uses the value of gap
         * instead of textIconGap.
         */

        int gap = (textIsEmpty || (icon == null)) ? 0 : textIconGap;

        if (!textIsEmpty) {

            /*
             * If the label text string is too wide to fit within the available
             * space "..." and as many characters as will fit will be displayed
             * instead.
             */

            int availTextWidth;

            if (horizontalTextPosition == CENTER) {
                availTextWidth = viewR.width;
            } else {
                availTextWidth = viewR.width - (iconR.width + gap);
            }

            if (textR.width > availTextWidth && text.length == 1) {
                String clipString = "...";
                int totalWidth = SwingUtilities.computeStringWidth(fm,
                        clipString);
                int nChars;
                for (nChars = 0; nChars < text[0].length(); nChars++) {
                    totalWidth += fm.charWidth(text[0].charAt(nChars));
                    if (totalWidth > availTextWidth) {
                        break;
                    }
                }
                rettext = text[0].substring(0, nChars) + clipString;
                textR.width = SwingUtilities.computeStringWidth(fm, rettext);
            }
        }

        /*
         * Compute textR.x,y given the verticalTextPosition and
         * horizontalTextPosition properties
         */

        if (verticalTextPosition == TOP) {
            if (horizontalTextPosition != CENTER) {
                textR.y = 0;
            } else {
                textR.y = -(textR.height + gap);
            }
        } else if (verticalTextPosition == CENTER) {
            textR.y = (iconR.height / 2) - (textR.height / 2);
        } else { // (verticalTextPosition == BOTTOM)
            if (horizontalTextPosition != CENTER) {
                textR.y = iconR.height - textR.height;
            } else {
                textR.y = (iconR.height + gap);
            }
        }

        if (horizontalTextPosition == LEFT) {
            textR.x = -(textR.width + gap);
        } else if (horizontalTextPosition == CENTER) {
            textR.x = (iconR.width / 2) - (textR.width / 2);
        } else { // (horizontalTextPosition == RIGHT)
            textR.x = (iconR.width + gap);
        }

        /*
         * labelR is the rectangle that contains iconR and textR. Move it to its
         * proper position given the labelAlignment properties.
         * 
         * To avoid actually allocating a Rectangle, Rectangle.union has been
         * inlined below.
         */
        int labelR_x = Math.min(iconR.x, textR.x);
        int labelR_width = Math.max(iconR.x + iconR.width, textR.x
                + textR.width)
                - labelR_x;
        int labelR_y = Math.min(iconR.y, textR.y);
        int labelR_height = Math.max(iconR.y + iconR.height, textR.y
                + textR.height)
                - labelR_y;

        int dx, dy;

        if (verticalAlignment == TOP) {
            dy = viewR.y - labelR_y;
        } else if (verticalAlignment == CENTER) {
            dy = (viewR.y + (viewR.height / 2))
                    - (labelR_y + (labelR_height / 2));
        } else { // (verticalAlignment == BOTTOM)
            dy = (viewR.y + viewR.height) - (labelR_y + labelR_height);
        }

        if (horizontalAlignment == LEFT) {
            dx = viewR.x - labelR_x;
        } else if (horizontalAlignment == RIGHT) {
            dx = (viewR.x + viewR.width) - (labelR_x + labelR_width);
        } else { // (horizontalAlignment == CENTER)
            dx = (viewR.x + (viewR.width / 2))
                    - (labelR_x + (labelR_width / 2));
        }

        /*
         * Translate textR and glypyR by dx,dy.
         */

        textR.x += dx;
        textR.y += dy;

        iconR.x += dx;
        iconR.y += dy;

        return rettext;
    }

    /**
     * Compute and return the location of the icons origin, the location of
     * origin of the text baseline, and a possibly clipped version of the
     * compound labels string. Locations are computed relative to the viewR
     * rectangle. The JComponents orientation (LEADING/TRAILING) will also be
     * taken into account and translated into LEFT/RIGHT values accordingly.
     */
    public static String layoutCompoundLabel(JComponent c, FontMetrics fm,
            String[] text, Icon icon, int verticalAlignment,
            int horizontalAlignment, int verticalTextPosition,
            int horizontalTextPosition, Rectangle viewR, Rectangle iconR,
            Rectangle textR, int textIconGap) {
        boolean orientationIsLeftToRight = true;
        int hAlign = horizontalAlignment;
        int hTextPos = horizontalTextPosition;

        if (c != null) {
            if (!(c.getComponentOrientation().isLeftToRight())) {
                orientationIsLeftToRight = false;
            }
        }

        // Translate LEADING/TRAILING values in horizontalAlignment
        // to LEFT/RIGHT values depending on the components orientation
        switch (horizontalAlignment) {
        case LEADING:
            hAlign = (orientationIsLeftToRight) ? LEFT : RIGHT;
            break;
        case TRAILING:
            hAlign = (orientationIsLeftToRight) ? RIGHT : LEFT;
            break;
        }

        // Translate LEADING/TRAILING values in horizontalTextPosition
        // to LEFT/RIGHT values depending on the components orientation
        switch (horizontalTextPosition) {
        case LEADING:
            hTextPos = (orientationIsLeftToRight) ? LEFT : RIGHT;
            break;
        case TRAILING:
            hTextPos = (orientationIsLeftToRight) ? RIGHT : LEFT;
            break;
        }

        return layoutCompoundLabel(fm, text, icon, verticalAlignment, hAlign,
                verticalTextPosition, hTextPos, viewR, iconR, textR,
                textIconGap);
    }

    protected void paintDisabledText(JLabel l, Graphics g, String s, int textX,
            int textY) {
        int accChar = l.getDisplayedMnemonic();
        g.setColor(l.getBackground());
        drawString(g, s, accChar, textX, textY);
    }

    protected void paintEnabledText(JLabel l, Graphics g, String s, int textX,
            int textY) {
        int accChar = l.getDisplayedMnemonic();
        g.setColor(l.getForeground());
        drawString(g, s, accChar, textX, textY);
    }

    private String[] splitStringByLines(String str) {
        if (str == null)
            return strs;
        if (str.equals(this.str))
            return strs;

        this.str = str;

        int lines = 1;
        int i, c;
        for (i = 0, c = str.length(); i < c; i++) {
            if (str.charAt(i) == '\n')
                lines++;
        }
        strs = new String[lines];
        StringTokenizer st = new StringTokenizer(str, "\n");

        int line = 0;
        while (st.hasMoreTokens())
            strs[line++] = st.nextToken();

        return strs;
    }
}
 

Ads help maintain this website.