/******************************************************************************* * Copyright (c) MOBAC developers * * 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 mobac.gui.components; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.Container; import java.awt.Cursor; import java.awt.Dimension; import java.awt.Font; import java.awt.GridBagLayout; import java.awt.LayoutManager; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import javax.swing.BorderFactory; import javax.swing.Box; import javax.swing.ImageIcon; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.border.Border; import mobac.utilities.GBC; import mobac.utilities.Utilities; /** * Bases upon "TitleContainer" from project "swivel" * http://code.google.com/p/swivel/ (LGPL license) * * A {@code TitleContainer} is a simple container that provides an easily * visible title. * */ public class JCollapsiblePanel extends JPanel { private static final long serialVersionUID = 1L; protected static final int DEFAULT_TITLE_PADDING = 3; protected static final Color DEFAULT_TITLE_BACKGROUND_COLOR = Color.LIGHT_GRAY; protected static final Color DEFAULT_TITLE_COLOR = Color.BLACK; private static ImageIcon arrowClosed; private static ImageIcon arrowOpen; static { try { arrowClosed = Utilities.loadResourceImageIcon("arrow_closed.png"); arrowOpen = Utilities.loadResourceImageIcon("arrow_open.png"); } catch (Exception e) { arrowClosed = new ImageIcon(); arrowOpen = new ImageIcon(); } } // title protected final JLabel titleIcon; protected final JLabel titleLabel; protected final JPanel titlePanel; // main component protected Container contentContainer; // collapsing protected final CollapsingMouseListener collapsingMouseListener; private boolean isCollapsed; /** * Constructs a {@code TitleContainer} that wraps the specified container. * * @param container * the main container */ public JCollapsiblePanel(Container container) { this(container, ""); } public JCollapsiblePanel(String title) { this(new JPanel(), title); } public JCollapsiblePanel(String title, LayoutManager layout) { this(new JPanel(layout), title); setName(title); } /** * Constructs a {@code TitleContainer} that wraps the specified component * and has the specified title. * * @param container * the main container * @param title * the title */ public JCollapsiblePanel(Container container, String title) { super(); setName(title); titleIcon = new JLabel(arrowOpen); titleLabel = new JLabel(title); titlePanel = new JPanel(new GridBagLayout()); // mainComponentPanel = new JPanel(new GridBagLayout()); collapsingMouseListener = new CollapsingMouseListener(); titleIcon.setMinimumSize(new Dimension(40, 40)); titleIcon.setPreferredSize(titleIcon.getPreferredSize()); // set collapse behavior titlePanel.addMouseListener(collapsingMouseListener); // look and feel setTitleBackgroundColor(DEFAULT_TITLE_BACKGROUND_COLOR); setTitleColor(DEFAULT_TITLE_COLOR); setTitleBarPadding(DEFAULT_TITLE_PADDING); // layout titlePanel.add(titleIcon, GBC.std()); titlePanel.add(titleLabel, GBC.std().insets(5, 0, 1, 0)); titlePanel.add(Box.createHorizontalGlue(), GBC.eol().fill()); setLayout(new BorderLayout()); add(titlePanel, BorderLayout.NORTH); add(container, BorderLayout.CENTER); setContentContainer(container); setBorder(BorderFactory.createEtchedBorder()); } /** * This method provides a programmatic way to collapse the container. * * @param collapsed * whether the container should be collapsed or shown */ public void setCollapsed(boolean collapsed) { if (isCollapsed == collapsed) { return; } if (collapsed) { titleIcon.setIcon(arrowClosed); // We have to make sure that the panel width does not shrink because // of the hidden content of contentContainer Dimension dcont = contentContainer.getLayout().preferredLayoutSize(contentContainer); Dimension pref = titlePanel.getPreferredSize(); titlePanel.setPreferredSize(new Dimension(dcont.width, pref.height)); } else { titleIcon.setIcon(arrowOpen); } contentContainer.setVisible(!collapsed); isCollapsed = collapsed; revalidate(); } /** * Gets whether the container is collapsed or not. * * @return whether the container is collapsed or not */ public boolean isCollapsed() { return isCollapsed; } /** * Sets the title of this container. * * @param title * the title */ public void setTitle(String title) { if (title != null) { titleLabel.setText(title); } else { titleLabel.setText(""); } } /** * Gets the this container's title. * * @return the title */ public String getTitle() { return titleLabel.getText(); } /** * Sets the main content container for this container. * * @param container * the main content container */ public void setContentContainer(Container container) { // don't need to do anything if the main component hasn't changed if (container == this.contentContainer) { return; } // remove the main component if (this.contentContainer != null) { remove(this.contentContainer); } // replace the main component this.contentContainer = container; add(container, BorderLayout.CENTER); // repaint main component revalidate(); } /** * Gets the main content container for this container. * * @return the main container */ public Container getContentContainer() { return contentContainer; } public void addContent(Component comp, Object constraints) { contentContainer.add(comp, constraints); } /** * Sets the title font. * * @param font * the title font */ public void setTitleFont(Font font) { super.setFont(font); if (titleLabel != null) { titleLabel.setFont(font); } } /** * Sets the background color of the title bar. * * @param color * the color */ public void setTitleBackgroundColor(Color color) { this.titlePanel.setBackground(color); } /** * Sets the title text color. * * @param color * the color */ public void setTitleColor(Color color) { this.titleLabel.setForeground(color); } /** * Sets the title bar padding in pixels. * * @param padding * the title bar padding in pixels */ public void setTitleBarPadding(int padding) { Border border = BorderFactory.createEmptyBorder(padding, padding, padding, padding); this.titlePanel.setBorder(border); } /** * Sets the visibility of the title bar. If the title bar is invisible, the * user will not be able to collapse or decollapse the container. * * @param visible * visibility of the title bar */ public void setTitleBarVisible(boolean visible) { this.titlePanel.setVisible(visible); } /** * Gets the visibility of the title bar. * * @return true if the title bar is visible, false otherwise */ public boolean isTitleBarVisible() { return this.titlePanel.isVisible(); } //-------------------------------------------------------------------------- /** * A {@code MouseListener} that changes the cursor when moved over the title * bar to indicate that it is clickable. Clicking the title bar collapses * the container. */ private class CollapsingMouseListener extends MouseAdapter { private final Cursor CLICK_ME_CURSOR = Cursor.getPredefinedCursor(Cursor.HAND_CURSOR); /** * Collapses or shows the titled component. * * {@inheritDoc} */ public void mousePressed(MouseEvent e) { setCollapsed(!JCollapsiblePanel.this.isCollapsed); } /** * Changes the cursor to indicate clickability. * * {@inheritDoc} */ public void mouseEntered(MouseEvent e) { titlePanel.setCursor(CLICK_ME_CURSOR); } /** * Changes the cursor back to the default. * * {@inheritDoc} */ public void mouseExited(MouseEvent e) { titlePanel.setCursor(Cursor.getDefaultCursor()); } } }