package org.korsakow.ide.ui.components; import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.AbstractButton; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JPanel; import javax.swing.UIManager; public class KCollapsiblePane extends KLayoutPanel { public static final String HEADER_UI_PROPERTY_OWNER_PANE = "org.korsakow.ide.ui.components.KCollapsiblePane.collapsiblePane"; final protected AbstractButton header; // made final because i'm too lazy to take care of the details involved in replacing the header protected JComponent content; protected JPanel contentPane; protected boolean autoMaxSize = false; public KCollapsiblePane() { this("", null); } public KCollapsiblePane(String headerText) { this(headerText, null); } public KCollapsiblePane(String headerText, JComponent content) { this(new Header(), content); setHeaderText(headerText); setContent(content); } public KCollapsiblePane(AbstractButton header, JComponent content) { super.setLayout(null); super.add(this.header = header); header.putClientProperty(HEADER_UI_PROPERTY_OWNER_PANE, this); contentPane = new JPanel(new BorderLayout());//new FlowLayout(FlowLayout.RIGHT)); contentPane.setOpaque(true); contentPane.setBackground(UIManager.getColor("CollapsiblePane.background")); super.add(contentPane); // contentPane.setBorder(BorderFactory.createEtchedBorder(EtchedBorder.LOWERED)); header.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { toggle(); } }); if (content != null) setContent(content); } protected void fireActionEvent() { ActionEvent event = new ActionEvent(this, 0, "expand"); for (ActionListener listener : listenerList.getListeners(ActionListener.class)) listener.actionPerformed(event); } public void addActionListener(ActionListener listener) { listenerList.add(ActionListener.class, listener); } /** * The Pane's preferred size always reflects is expanded state. This option * determines whether its maximum size is also set in accordance. * * Basically this was needed to make the component play nice in BoxLayouts * @param b */ public void setAutoSetMaxSize(boolean b) { autoMaxSize = b; } @Override public void doLayout() { Insets insets = getInsets(); Dimension size = getSize(); getHeader().setSize(size.width - (insets.left+insets.right), getHeader().getPreferredSize().height); getContentPane().setSize(size.width - (insets.left+insets.right), size.height - (insets.top + insets.bottom) - getHeader().getHeight()); getHeader().setLocation(insets.left, insets.top); getContentPane().setLocation(insets.left, getHeader().getSize().height + insets.top); } @Override public Dimension getPreferredSize() { if (isPreferredSizeSet()) return super.getPreferredSize(); Dimension pref = null; if (isExpanded()) { pref = getContentPane().getPreferredSize(); pref.height += header.getPreferredSize().getHeight(); } else { pref = getContentPane().getPreferredSize(); pref.height = getHeader().getPreferredSize().height; // pref.height += header.getPreferredSize().getHeight(); } Insets insets = getInsets(); pref.width += insets.left + insets.right; pref.height += insets.top + insets.bottom; return pref; } @Override public Dimension getMaximumSize() { if (isMaximumSizeSet()) return super.getMaximumSize(); Dimension d = getPreferredSize(); d.width = Short.MAX_VALUE; return d; } public void setHeaderText(String text) { header.setText(text); } public AbstractButton getHeader() { return header; } public void setContent(JComponent content) { getContentPane().removeAll(); this.content = content; if (content != null) getContentPane().add(content); revalidate(); repaint(); } public JComponent getContent() { return content; } public JPanel getContentPane() { return contentPane; } public boolean isExpanded() { return contentPane.isVisible(); } public void setExpanded(boolean expanded) { boolean wasExpanded = contentPane.isVisible(); if (expanded) { contentPane.setVisible(true); } else { contentPane.setVisible(false); } if (autoMaxSize) { Dimension d = getPreferredSize(); d.width = Integer.MAX_VALUE; setMaximumSize(d); } revalidate(); if (wasExpanded != expanded) fireActionEvent(); } public void toggle() { setExpanded(!isExpanded()); } public static class Header extends JButton { private static final String uiClassID = "CollapsiblePaneHeaderUI"; public Header() { } @Override public String getUIClassID() { return uiClassID; } } }