package com.onaro.util.jfc; import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.Font; import java.awt.Insets; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JPanel; import org.apache.commons.lang3.StringUtils; import com.onaro.commons.beans.IPropertyChangeSupport; /** * UI component for showing/hiding a component using a collapsible section. The section consists * of an arrow icon indicating whether the section is expanded or collapsed and header text that the user * can click on to expand/collapse the section. When the section is expanded the child component is displayed, * indented from the section's justification. This class has the following bound properties: {@link #PROP_EXPANDED}, * {@link #PROP_HEADER_TEXT}, {@link #PROP_CHILD_COMPONENT}. */ public class CollapsibleSection extends JPanel implements IPropertyChangeSupport { private static final long serialVersionUID = 1L; /** * Property used for notification of changes to the CollapsibleSection's expansion state */ public static final String PROP_EXPANDED = Accordion.PROP_EXPANDED; /** * Property used for notification of changes to the CollapsibleSection's header text */ public static final String PROP_HEADER_TEXT = "headerText"; //$NON-NLS-1$ /** * Property used for notification of changes to the CollapsibleSection's child component */ public static final String PROP_CHILD_COMPONENT = "childComponent"; //$NON-NLS-1$ protected final Accordion accordion; protected final JLabel spacerLabel; protected JComponent childComponent; /** * Create a collapsible section with the given child component to display when * in the expanded state. The section is collapsed by default (can be changed * using {@link #setExpanded(boolean)}). * * @param headerText the text to display in the section header (the clickable text used to * expand/collapse the section). * @param childComponent the component that's shown when the section is expanded. */ public CollapsibleSection(String headerText, JComponent childComponent) { this(headerText); setChildComponent(childComponent); } /** * Create a collapsible section without specifying the child component. The child * component must be specified later using {@link #setChildComponent(JComponent)} for * the collapsible section to be useful. The section is collapsed by default (can be changed * using {@link #setExpanded(boolean)}). * @param headerText the text to display in the section header (the clickable text used to * expand/collapse the section). */ public CollapsibleSection(String headerText) { JButton sectionHeader = new ButtonField(headerText); sectionHeader.setMargin(new Insets(1, 1, 1, 1)); sectionHeader.setFont(sectionHeader.getFont().deriveFont(Font.BOLD)); accordion = new Accordion(sectionHeader); accordion.addPropertyChangeListener (PROP_EXPANDED, new PropertyChangeListener() { @Override public void propertyChange (PropertyChangeEvent event) { spacerLabel.setVisible(accordion.isExpanded()); if (childComponent != null) { childComponent.setVisible (accordion.isExpanded()); } validate(); setPreferredSize(getMinimumSize()); firePropertyChange(PROP_EXPANDED, event.getOldValue(), event.getNewValue()); } }); spacerLabel = new JLabel(); Dimension size = new Dimension(20, 1); spacerLabel.setSize(size); spacerLabel.setMinimumSize(size); spacerLabel.setPreferredSize(size); spacerLabel.setMaximumSize(size); spacerLabel.setVisible(accordion.isExpanded()); setLayout(new BorderLayout()); add(sectionHeader, BorderLayout.NORTH); add(spacerLabel, BorderLayout.WEST); setPreferredSize(getMinimumSize()); } /** * Set the expansion state of the collapsible section * @param expanded true to expand the section, false to collapse */ public void setExpanded(boolean expanded) { accordion.setExpanded(expanded); } /** * Get the expansion state of the collapsible section. * @return true if the section is expanded, false if collapsed */ public boolean isExpanded() { return accordion.isExpanded(); } /** * Set the component to display within the collapsible section when expanded. * @param childComponent the component to display */ public void setChildComponent(JComponent childComponent) { if (this.childComponent == childComponent) { return; } JComponent oldComponent = this.childComponent; if (oldComponent != null) { remove(oldComponent); } this.childComponent = childComponent; add(this.childComponent, BorderLayout.CENTER); this.childComponent.setVisible(accordion.isExpanded()); validate(); setPreferredSize(getMinimumSize()); firePropertyChange(PROP_CHILD_COMPONENT, oldComponent, childComponent); } /** * Get the component that's displayed in the collapsible section when expanded. * @return the display component */ public JComponent getChildComponent() { return childComponent; } /** * Set the text shown in the section header (the clickable text used to expand/collapse the section). * @param headerText the text for the header */ public void setHeaderText(String headerText) { String oldText = getHeaderText(); if (StringUtils.equals(oldText, headerText)) { return; } accordion.getController().setText(headerText); firePropertyChange(PROP_HEADER_TEXT, oldText, headerText); } /** * Get the text shown in the section header (the clickable text used to expand/collapse the section). * @return the text for the header */ public String getHeaderText() { return accordion.getController().getText(); } }