package uk.ac.rhul.cs.cl1.ui; import java.awt.BorderLayout; import java.awt.Component; import java.awt.Cursor; import java.awt.Font; import java.awt.LayoutManager; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.net.URL; import javax.swing.Icon; import javax.swing.ImageIcon; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.border.Border; /** * Collapsible panel for the GUI. * * This panel consists of a header label and a main area. When the user * clicks on the heading label, the main area is toggled (i.e. hidden if * it was shown, shown if it was hidden). * * @author tamas */ public class CollapsiblePanel extends JPanel { /** * The label in the header of the panel */ protected JLabel headerLabel = null; /** * The main component of the panel */ protected JComponent component = null; /** * Icon to be used in the collapsed state of the panel */ private Icon collapsedIcon = loadIcon("plus.gif"); /** * Icon to be used in the expanded state of the panel */ private Icon expandedIcon = loadIcon("minus.gif"); /** * Constructs a new collapsible panel with an empty title and a * default JPanel component being wrapped. */ public CollapsiblePanel() { this(""); } /** * Constructs a new collapsible panel with the given title and a * default JPanel component being wrapped. * * @param title the title of the panel */ public CollapsiblePanel(String title) { this(title, true); } /** * Constructs a new collapsible panel with the given title and a * default JPanel component being wrapped. * * @param title the title of the panel * @param expanded whether the panel is expanded */ public CollapsiblePanel(String title, boolean expanded) { this(new JPanel(), title, expanded); } /** * Constructs a new collapsible panel with the given title and the * given component as contents. * * @param component the component being wrapped by the panel * @param title the title of the panel */ public CollapsiblePanel(JComponent component, String title) { this(component, title, true); } /** * Constructs a new collapsible panel with the given title and the * given component as contents. * * @param component the component being wrapped by the panel * @param title the title of the panel * @param expanded whether the panel is expanded */ public CollapsiblePanel(JComponent component, String title, boolean expanded) { super(); super.setLayout(new BorderLayout()); headerLabel = new JLabel(title); headerLabel.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); headerLabel.setFont(headerLabel.getFont().deriveFont(Font.BOLD)); super.add(headerLabel, BorderLayout.NORTH); this.setWrappedComponent(component); this.setExpanded(expanded); headerLabel.addMouseListener(new MouseAdapter() { public void mouseClicked(MouseEvent e) { setExpanded(!isExpanded()); } }); } /** * Dispatches the method call to the wrapped component */ @Override public Component add(Component comp) { return this.component.add(comp); } /** * Dispatches the method call to the wrapped component */ @Override public Component add(Component comp, int index) { return this.component.add(comp, index); } /** * Dispatches the method call to the wrapped component */ @Override public void add(Component comp, Object constraints) { this.component.add(comp, constraints); } /** * Dispatches the method call to the wrapped component */ @Override public void add(Component comp, Object constraints, int index) { this.component.add(comp, constraints, index); } /** * Returns the icon shown on the panel when it is collapsed. */ public Icon getCollapsedIcon() { return collapsedIcon; } /** * Returns the icon shown on the panel when it is expanded. */ public Icon getExpandedIcon() { return expandedIcon; } /** * Returns the component wrapped by this panel */ public JComponent getWrappedComponent() { return this.component; } /** * Loads an icon from the resources corresponding to the panel */ protected ImageIcon loadIcon(String name) { URL url; url = CollapsiblePanel.class.getResource("resources/"+name); if (url == null) url = CollapsiblePanel.class.getResource("../resources/"+name); if (url == null) return null; return new ImageIcon(url); } /** * Returns whether the panel is expanded * * @return whether the panel is expanded */ public boolean isExpanded() { if (component == null) return false; return component.isVisible(); } /** * Sets the border of the internally wrapped component */ public void setBorder(Border border) { if (component != null) component.setBorder(border); } /** * Sets the icon shown when the panel is collapsed. */ public void setCollapsedIcon(Icon icon) { this.collapsedIcon = icon; refreshIcon(); } /** * Sets the icon shown when the panel is expanded. */ public void setExpandedIcon(Icon icon) { this.expandedIcon = icon; refreshIcon(); } /** * Sets the layout of the internally wrapped component */ public void setLayout(LayoutManager mgr) { if (component != null) component.setLayout(mgr); } /** * Sets the central component of the panel */ public void setWrappedComponent(JComponent component) { this.component = component; super.add(component, BorderLayout.CENTER); } /** * Sets whether the panel is expanded * * In collapsed state, the main component of the panel is not shown, * only the label. In expanded state, both the main component and * the header are shown. * * @param expanded whether the panel is expanded */ public void setExpanded(boolean expanded) { if (component != null) component.setVisible(expanded); refreshIcon(); } /** * Refreshes the icon on the panel. */ private void refreshIcon() { headerLabel.setIcon(isExpanded() ? expandedIcon : collapsedIcon); } }