/* JLabelPanel.java This class defines a JPanel that contains stacked, labeled items. Created: 19 August 2004 Module By: Jonathan Abbey, jonabbey@arlut.utexas.edu ----------------------------------------------------------------------- Ganymede Directory Management System Copyright (C) 1996-2012 The University of Texas at Austin Contact information Author Email: ganymede_author@arlut.utexas.edu Email mailing list: ganymede@arlut.utexas.edu US Mail: Computer Science Division Applied Research Laboratories The University of Texas at Austin PO Box 8029, Austin TX 78713-8029 Telephone: (512) 835-3200 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ package arlut.csd.JDataComponent; import java.awt.BorderLayout; import java.awt.Component; import java.awt.Font; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import javax.swing.JPanel; import javax.swing.JLabel; import java.util.HashMap; import java.util.Map; /*------------------------------------------------------------------------------ class JLabelPanel ------------------------------------------------------------------------------*/ /** * <p>This panel contains labeled GUI components in a vertical stack * orientation. Each GUI component may be made visible or invisible * at will.</p> * * <p>All methods on a constructed JLabelPanel object should be called * on the GUI thread once the JLabelPanel has been added to a GUI * container.</p> * * @author Jonathan Abbey */ public class JLabelPanel extends JPanel { private JPanel bPanel = null; private JPanel gPanel = null; private GridBagLayout gbl; private GridBagConstraints gbc; private int row = 0; private Map<Component, JLabel> rowHash; private Font font = null; private float size = 0.0F; private int style = 0; /** * Insets for the left column in our JLabelPanel */ private Insets leftInsets = new java.awt.Insets(0,0,0,0); /** * Insets for the right column in our JLabelPanel */ private Insets rightInsets = new java.awt.Insets(0,0,0,0); /** * If true, we'll put in a JSpacer to keep the label cells * at a fixed size, even if certain rows are made invisible. */ private boolean enforceFixedSize = false; private int maximumLabelWidth = 0; private JSpacer spacer = null; /* -- */ public JLabelPanel() { super(); } public JLabelPanel(boolean doubleBuffer) { super(doubleBuffer); } private void setup() { // we want to be packed in the north west setLayout(new BorderLayout()); bPanel = new JPanel(); bPanel.setLayout(new BorderLayout()); gbl = new GridBagLayout(); gbc = new GridBagConstraints(); gPanel = new JPanel(); gPanel.setLayout(gbl); bPanel.add("West", gPanel); add("North", bPanel); row = 0; rowHash = new HashMap<Component, JLabel>(); } /** * If setFixedSizeLabelCells() is called with a true value, the * JLabelPanel will be configured so that it keeps the label column * wide enough to encompass all labels, whether they are on visible * rows or not. If it is called with a false value (or not called * at all.. the default is off), the hiding or revealing of rows may * cause shifting of the horizontal position of the fields on the * right column. */ public synchronized void setFixedSizeLabelCells(boolean tf) { if (gbl == null) { setup(); } if (tf && !enforceFixedSize) { gbc.gridwidth = 1; gbc.gridy = row; gbc.weightx = 0.0; gbc.gridx = 0; spacer = new JSpacer(maximumLabelWidth, 0); gbl.setConstraints(spacer,gbc); gPanel.add(spacer); row = row + 1; } enforceFixedSize = tf; if (!enforceFixedSize) { gPanel.remove(spacer); spacer = null; } } /** * Sets standardized insets around each label and component to be * added to this JLabelPanel. */ public synchronized void setInsets(int top, int left, int bottom, int right) { this.leftInsets = new java.awt.Insets(top,left,bottom,right); this.rightInsets = this.leftInsets; } /** * Sets standardized insets around each label and component to be * added to this JLabelPanel. */ public synchronized void setInsets(java.awt.Insets insets) { if (insets == null) { this.leftInsets = new java.awt.Insets(0,0,0,0); } else { this.leftInsets = insets; } this.rightInsets = this.leftInsets; } /** * Sets standardized insets around each label to be added to this * JLabelPanel. */ public synchronized void setLeftInsets(int top, int left, int bottom, int right) { this.leftInsets = new java.awt.Insets(top,left,bottom,right); } /** * Sets standardized insets around each label to be added to this * JLabelPanel. */ public synchronized void setLeftInsets(java.awt.Insets insets) { if (insets == null) { this.leftInsets = new java.awt.Insets(0,0,0,0); } else { this.leftInsets = insets; } } /** * Sets standardized insets around each component to be added to * this JLabelPanel. */ public synchronized void setRightInsets(int top, int left, int bottom, int right) { this.rightInsets = new java.awt.Insets(top,left,bottom,right); } /** * Sets standardized insets around each component to be added to * this JLabelPanel. */ public synchronized void setRightInsets(java.awt.Insets insets) { if (insets == null) { this.rightInsets = new java.awt.Insets(0,0,0,0); } else { this.rightInsets = insets; } } /** * This method sets the style of all the labels in this label * panel. The styles are taken from the {@link java.awt.Font * java.awt.Font} class's static int members, and include Font.BOLD, * Font.ITALIC, Font.PLAIN, or the sum of FONT.BOLD and * FONT.ITALIC. * * These are the old-school Java 1.1 styles, not the fancier Java * 1.2 stuff. */ public void setFontStyle(int style) { setFontStyleSize(style, size); } /** * This method sets the size of all the labels in this label * panel. If size is equal to 0.0, the default label font size * will be used instead. */ public void setFontSize(float size) { setFontStyleSize(style, size); } /** * This method sets the size of all the labels in this label * panel. If size is equal to 0.0, the default label font size * will be used instead. */ public synchronized void setFontStyleSize(int style, float size) { this.size = size; this.style = style; JLabel newLabel = new JLabel(); Font labelFont = newLabel.getFont(); if (size == 0.0F) { this.font = labelFont; } else { this.font = labelFont.deriveFont(size); } this.font = this.font.deriveFont(style); setFont(this.font); } /** * Returns the point size of the labels in this JLabelPanel. */ public synchronized float getFontSize() { if (this.size != 0.0F) { return this.size; } JLabel newLabel = new JLabel(); Font labelFont = newLabel.getFont(); return labelFont.getSize2D(); } /** * Sets the font for all labels in this JLabelPanel. */ public synchronized void setFont(Font font) { this.font = font; this.size = 0.0F; if (rowHash == null) { return; } int maxSize = 0; for (JLabel label: rowHash.values()) { label.setFont(font); label.invalidate(); if (label.getPreferredSize().width > maxSize) { maxSize = label.getPreferredSize().width; } } gPanel.invalidate(); bPanel.invalidate(); this.maximumLabelWidth = maxSize; if (spacer != null) { spacer.setSpacerSize(this.maximumLabelWidth, 0); } validate(); repaint(); } /** * For adding a labeled item. * * Each row that is added is placed below all rows above it. * * @param label The text to put in a label on the leftmost column for this row. May be null. * @param comp The component to add in the right column, after the label, if any. */ public void addRow(String label, Component comp) { addRow(label, comp, false, false, 1); } /** * For adding a labeled item that is to stretch horizontally * to fill the entire component column. * * Each row that is added is placed below all rows above it. * * @param label The text to put in a label on the leftmost column for this row. May be null. * @param comp The component to add in the right column, after the label, if any. */ public void addFillRow(String label, Component comp) { addRow(label, comp, true, false, 1); } /** * For adding a labeled item that is to stretch horizontally * to fill the entire panel, and more besides. * * Each row that is added is placed below all rows above it. * * @param label The text to put in a label on the leftmost column for this row. May be null. * @param comp The component to add in the right column, after the label, if any. * @param colsWidth The number of columns the component comp will * be stretched out to cover. Values greater than 1 may be used to * put component into its own right-edge alignment point, distinct * from other components added with differing colsWidth values */ public void addFillRow(String label, Component comp, int colsWidth) { addRow(label, comp, true, false, colsWidth); } /** * For adding a component that spans the label and item columns. * * Each row that is added is placed below all rows above it. * @param comp The component to add. */ public void addWideComponent(Component comp) { addRow(null, comp, false, true, 1); } /** * For adding a component that spans the label and item columns, and * that is to stretch horizontally to fill the entire panel. * * Each row that is added is placed below all rows above it. * * @param comp The component to add. */ public void addWideFillComponent(Component comp) { addRow(null, comp, true, true, 1); } /** * For adding a component that spans the label and item columns, and * that is to stretch horizontally to fill the entire panel. * * Each row that is added is placed below all rows above it. * * @param comp The component to add. * @param colsWidth The number of columns the component comp will * be stretched out to cover. Values greater than 1 may be used to * put component into its own right-edge alignment point, distinct * from other components added with differing colsWidth values */ public void addWideFillComponent(Component comp, int colsWidth) { addRow(null, comp, true, true, colsWidth); } /** * Private worker method for adding a possibly labeled component * to this JLabelPanel. * * Each row that is added is placed below all rows above it. * * @param label The text to put in a label on the leftmost column for this row. May be null. * @param comp The component to add in the right column, after the label, if any. * @param fill If true, the component will be allowed to stretch to * fill the remaining horizontal space in this panel. * @param wideComponent If true and if label is null, the comp will * be horizontally positioned starting in the label column rather * than the field column. */ private synchronized void addRow(String label, Component comp, boolean fill, boolean wideComponent, int colsWidth) { if (rowHash == null || gPanel == null) { this.setup(); } gbc.gridy = row; gbc.insets = this.leftInsets; if (label != null) { JLabel l = new JLabel(label); if (this.font != null) { l.setFont(font); } l.setLabelFor(comp); // for assistive technology use rowHash.put(comp, l); gbc.anchor = GridBagConstraints.NORTHWEST; gbc.fill = GridBagConstraints.NONE; gbc.weightx = 0.0; gbc.gridx = 0; gbc.gridwidth = 1; gbl.setConstraints(l, gbc); gPanel.add(l); if (l.getPreferredSize().width > this.maximumLabelWidth) { this.maximumLabelWidth = l.getPreferredSize().width; if (spacer != null) { spacer.setSpacerSize(this.maximumLabelWidth, 0); } } } gbc.anchor = GridBagConstraints.WEST; if (fill) { gbc.fill = GridBagConstraints.HORIZONTAL; } else { gbc.fill = GridBagConstraints.NONE; } if (label == null && wideComponent) { gbc.gridx = 0; } else { gbc.gridx = 1; } gbc.insets = this.rightInsets; gbc.weightx = 0.0; gbc.gridwidth = colsWidth; gbl.setConstraints(comp, gbc); gPanel.add(comp); row = row + 1; } /** * <p>For changing the number of columns the Component comp spans in * the JLabelPanel. Used to allow embedded object vector panels to * grow past the 2nd column boundary when expanded.</p> */ public synchronized void changeColumnContentWidth(Component comp, int colwidth) { gbc = gbl.getConstraints(comp); gbc.gridwidth = colwidth; gbl.setConstraints(comp, gbc); gPanel.validate(); } /** * <p>For making a given row visible or invisible. If b is set to * true, the given row will be made visible, if it is set to false, * the given row (and its label) will be made invisible, and the * JLabelPanel will pull any rows beneath it up to fill in the * space.</p> * * <p>Note that if a setFixedSizeLabelCells(true) call has been made * on this JLabelPanel, making a row invisible will not cause the * horizontal positioning of the second, field column to shift.</p> */ public synchronized void setRowVisible(Component comp, boolean b) { if (rowHash == null) { this.setup(); } JLabel label = rowHash.get(comp); comp.setVisible(b); if (label != null) { label.setVisible(b); } } /** * Removes the given component and its label from this * JLabelPanel. */ public synchronized void removeRow(Component comp) { if (rowHash == null) { return; // nothing added } gPanel.remove(comp); JLabel label = rowHash.get(comp); if (label != null) { gPanel.remove(label); } } /** * Does dissolution of this JLabelPanel. Useful to make sure we * don't keep hold of any lingering references to things. */ public synchronized void cleanup() { if (rowHash != null) { rowHash.clear(); rowHash = null; } removeAll(); if (gPanel != null) { gPanel.removeAll(); gPanel = null; } if (bPanel != null) { bPanel.removeAll(); bPanel = null; } gbl = null; gbc = null; spacer = null; } }