001/*
002 * feinrip
003 *
004 * Copyright (C) 2014 Richard "Shred" Körber
005 *   https://github.com/shred/feinrip
006 *
007 * This program is free software: you can redistribute it and/or modify
008 * it under the terms of the GNU General Public License as
009 * published by the Free Software Foundation, either version 3 of the
010 * License, or (at your option) any later version.
011 *
012 * This program is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
015 */
016package org.shredzone.feinrip.gui;
017
018import java.awt.BorderLayout;
019import java.awt.Component;
020import java.awt.Dimension;
021
022import javax.swing.JComponent;
023import javax.swing.JLabel;
024import javax.swing.JPanel;
025import javax.swing.SwingConstants;
026import javax.swing.border.Border;
027import javax.swing.border.EmptyBorder;
028
029/**
030 * A JLabelGroup is a {@link JLabel} set left to a {@link Component}.
031 *
032 * @author Richard "Shred" Körber
033 */
034public class JLabelGroup extends JPanel {
035    private static final long serialVersionUID = 3381504646372204060L;
036
037    private Component comp;
038    private JComponent label;
039    private JLabelGroup pred;
040
041    /**
042     * Utility method to set the height of a {@link JComponent} to its minimum.
043     */
044    public static void setMinimumHeight(JComponent comp) {
045        int height = comp.getMinimumSize().height;
046        comp.setMaximumSize(new Dimension(comp.getMaximumSize().width, height));
047        comp.setPreferredSize(new Dimension(comp.getPreferredSize().width, height));
048    }
049
050    /**
051     * Creates the first JLabelGroup of a chain.
052     *
053     * @param c
054     *            {@link Component} to be labelled
055     * @param text
056     *            Label text
057     */
058    public JLabelGroup(Component c, String text) {
059        this(c, text, null);
060    }
061
062    /**
063     * Creates a new JLabelGroup element.
064     *
065     * @param c
066     *            {@link Component} to be labelled
067     * @param text
068     *            Label text
069     * @param pred
070     *            Predecessor {@link JLabelGroup} instance, or {@code null}
071     */
072    public JLabelGroup(Component c, String text, JLabelGroup pred) {
073        this(c, new JLabel(text), pred);
074    }
075
076    /**
077     * Creates a new JLabelGroup label with a given label {@link JComponent}. Use this if
078     * you want to use a different label.
079     *
080     * @param c
081     *            {@link Component} to be labelled
082     * @param label
083     *            Label {@link JComponent}
084     * @param pred
085     *            Predecessor {@link JLabelGroup} instance, or {@code null}
086     */
087    public JLabelGroup(Component c, JComponent label, JLabelGroup pred) {
088        this.comp = c;
089        this.label = label;
090        this.pred = pred;
091
092        setVerticalAlignment(SwingConstants.CENTER);
093        if (label instanceof JLabel) {
094            ((JLabel) label).setLabelFor(comp);
095        }
096
097        setLayout(new BorderLayout());
098        add(label, BorderLayout.LINE_START);
099        add(comp, BorderLayout.CENTER);
100    }
101
102    /**
103     * Calculates the maximum label with of a {@link JLabelGroup} chain.
104     *
105     * @return Maximum width
106     */
107    protected int getMaximumWidth() {
108        if (pred != null) {
109            return Math.max(label.getMinimumSize().width, pred.getMaximumWidth());
110        } else {
111            return label.getMinimumSize().width;
112        }
113    }
114
115    /**
116     * Sets the vertical alignment of the label, using {@link SwingConstants}. Default is
117     * {@link SwingConstants#CENTER}.
118     */
119    public void setVerticalAlignment(int pos) {
120        Border border;
121
122        switch (pos) {
123            case SwingConstants.TOP:
124                border = new EmptyBorder(1, 0, 0, 5);
125                break;
126
127            case SwingConstants.BOTTOM:
128                border = new EmptyBorder(0, 0, 1, 5);
129                break;
130
131            default:
132                border = new EmptyBorder(0, 0, 0, 5);
133        }
134
135        label.setBorder(border);
136
137        if (label instanceof JLabel) {
138            ((JLabel) label).setVerticalAlignment(pos);
139        }
140    }
141
142    /**
143     * Recursively set the minimum width of this {@link JLabelGroup} chain. This method
144     * must be invoked on the <em>last</em> {@link JLabelGroup} of the chain.
145     *
146     * @param width
147     *            New minimum width
148     */
149    protected void setMinimumWidth(int width) {
150        Dimension dim = new Dimension(width, label.getMinimumSize().height);
151        label.setMinimumSize(dim);
152        label.setPreferredSize(dim);
153        if (pred != null) pred.setMinimumWidth(width);
154        invalidate();
155    }
156
157    /**
158     * Rearrange the {@link JLabelGroup} chain. All labels in this chain are set to the
159     * width of the broadest label. This method must be invoked on the <em>last</em>
160     * {@link JLabelGroup} of a chain!
161     */
162    public void rearrange() {
163        setMinimumWidth(getMaximumWidth());
164    }
165
166}