Author: chatellier Date: 2010-12-03 10:45:54 +0000 (Fri, 03 Dec 2010) New Revision: 351 Log: Add new Accordion component Added: trunk/coser-ui/src/main/java/fr/ifremer/coser/ui/widgets/AccordionLayout.java trunk/coser-ui/src/main/java/fr/ifremer/coser/ui/widgets/AccordionPane.java trunk/coser-ui/src/main/java/fr/ifremer/coser/ui/widgets/AccordionPaneSubPanel.java Added: trunk/coser-ui/src/main/java/fr/ifremer/coser/ui/widgets/AccordionLayout.java =================================================================== --- trunk/coser-ui/src/main/java/fr/ifremer/coser/ui/widgets/AccordionLayout.java (rev 0) +++ trunk/coser-ui/src/main/java/fr/ifremer/coser/ui/widgets/AccordionLayout.java 2010-12-03 10:45:54 UTC (rev 351) @@ -0,0 +1,156 @@ +/* %%Ignore-License + * Copyright (C) 2007 Craig Knudsen + * + * AccordionPane is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 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 Lesser General Public + * License for more details. + * + * A copy of the GNU Lesser General Public License can be found at www.gnu.org. + * To receive a hard copy, you can write to: + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA. + */ + +package fr.ifremer.coser.ui.widgets; + +import java.awt.Component; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Insets; +import java.awt.LayoutManager; + +public class AccordionLayout implements LayoutManager { + + protected AccordionPane accordionPane; + + /** + * Constructs a AccordionLayout. + * + * @param accordionPane accordionPane + */ + public AccordionLayout(AccordionPane accordionPane) { + this.accordionPane = accordionPane; + } + + protected Dimension layoutSize(Container parent, boolean minimum) { + Dimension dim = new Dimension(0, 0); + synchronized (parent.getTreeLock()) { + int n = parent.getComponentCount(); + int cnt = 0; + for (int i = 0; i < n; i++) { + Component c = parent.getComponent(i); + if (c.isVisible()) { + Dimension d = (minimum) ? c.getMinimumSize() : c + .getPreferredSize(); + dim.height += d.height; + if (d.width > dim.width) { + dim.width = d.width; + } + } + cnt++; + if (cnt == accordionPane.children.size()) { + break; + } + } + } + Insets insets = parent.getInsets(); + dim.width += insets.left + insets.right; + dim.height += insets.top + insets.bottom; + return dim; + } + + /** + * Lays out the container. + */ + @Override + public void layoutContainer(Container parent) { + Insets insets = parent.getInsets(); + synchronized (parent.getTreeLock()) { + int n = parent.getComponentCount(); + Dimension pd = parent.getSize(); + // do layout + int cnt = 0; + int totalhei = pd.height - insets.top - insets.bottom; + int x = insets.left; + int y = insets.top; + int selInd = accordionPane.selected; + int numPanes = accordionPane.children.size(); + // Calculate the remainder and set it in the AccordionPane in case the + // JPanel was resized. + AccordionPaneSubPanel firstSubPanel = (AccordionPaneSubPanel) parent + .getComponent(0); + // Get height of title area + int remainder = totalhei + - (firstSubPanel.titlePanel.getHeight() * numPanes); + accordionPane.remainder = remainder; + for (int i = 0; i < n; i++) { + Component c = parent.getComponent(i); + AccordionPaneSubPanel subPanel = (AccordionPaneSubPanel) c; + // Get height of title area + int titleH = subPanel.titlePanel.getHeight(); + if (accordionPane.transitionStep > 0) { + // We're in the middle of the animation + if (subPanel.index == selInd) { + int hei = titleH + accordionPane.transitionStep; + c.setBounds(x, y, + pd.width - insets.left - insets.right, hei); + y += hei; + } else if (subPanel.index == accordionPane.previouslySelected) { + int hei = titleH + + (remainder - accordionPane.transitionStep); + c.setBounds(x, y, + pd.width - insets.left - insets.right, hei); + y += hei; + } else { + int hei = titleH; + c.setBounds(x, y, + pd.width - insets.left - insets.right, hei); + y += hei; + } + } else { + if (subPanel.index == selInd) { + int hei = titleH + remainder; + c.setBounds(x, y, + pd.width - insets.left - insets.right, hei); + y += hei; + } else { + int hei = titleH; + c.setBounds(x, y, + pd.width - insets.left - insets.right, hei); + y += hei; + } + } + cnt++; + if (cnt == numPanes) { + break; + } + } + } + } + + @Override + public Dimension minimumLayoutSize(Container parent) { + return layoutSize(parent, false); + } + + @Override + public Dimension preferredLayoutSize(Container parent) { + return layoutSize(parent, false); + } + + @Override + public void addLayoutComponent(String name, Component comp) { + + } + + @Override + public void removeLayoutComponent(Component comp) { + + } +} \ No newline at end of file Property changes on: trunk/coser-ui/src/main/java/fr/ifremer/coser/ui/widgets/AccordionLayout.java ___________________________________________________________________ Added: svn:keywords + Author Date Id Revision HeadURL Added: trunk/coser-ui/src/main/java/fr/ifremer/coser/ui/widgets/AccordionPane.java =================================================================== --- trunk/coser-ui/src/main/java/fr/ifremer/coser/ui/widgets/AccordionPane.java (rev 0) +++ trunk/coser-ui/src/main/java/fr/ifremer/coser/ui/widgets/AccordionPane.java 2010-12-03 10:45:54 UTC (rev 351) @@ -0,0 +1,268 @@ +/* %%Ignore-License + * Copyright (C) 2007 Craig Knudsen + * + * AccordionPane is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 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 Lesser General Public + * License for more details. + * + * A copy of the GNU Lesser General Public License can be found at www.gnu.org. + * To receive a hard copy, you can write to: + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA. + */ + +package fr.ifremer.coser.ui.widgets; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Graphics; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.ArrayList; +import java.util.List; + +import javax.swing.Icon; +import javax.swing.JPanel; +import javax.swing.Timer; + +/** + * The AccordionPane class implements a vertical accordion container, similar to + * those seen in many AJAX/DHTML frameworks. Multiple child panels are added, + * but only one of those will be visible at a time. The user can switch between + * visible panels by clicking on the title area of one of the inactive panels. + * + * @author Craig Knudsen, craig at k5n.us + */ +// TODO: add/remove ChangeListener support +// TODO: add support for setting icons +// TODO: tooltip text for titles +// TODO: enable/disable panels +public class AccordionPane extends JPanel { + + /** serialVersionUID. */ + private static final long serialVersionUID = -4266521429712806753L; + + protected List<AccordionPaneSubPanel> children; + protected int selected = -1; + protected int previouslySelected = -1; // used in animation transition + // background color for pane title + protected Color paneBackgroundColor; + // background color for current pane title + protected Color activePaneBackgroundColor; + protected Timer timer; + protected int transitionStep = 0; + protected int remainder = -1; + + /** + * Create a new AccordionPane object. After creating the AccordionPane, you + * will need to call addPanel to add UI components to it. + */ + public AccordionPane() { + this.children = new ArrayList<AccordionPaneSubPanel>(); + this.selected = -1; + this.setLayout(new AccordionLayout(this)); + this.paneBackgroundColor = super.getBackground(); + this.activePaneBackgroundColor = new Color(255, 255, 200); + } + + /** + * Set the background color for the active and inactive pane title areas. + * + * @param normalColor + * The color to use for the non-active panels + * @param activeColor + * The color to use for the currently selected panel + */ + public void setTitleBackgroundColors(Color normalColor, Color activeColor) { + this.paneBackgroundColor = normalColor; + this.activePaneBackgroundColor = activeColor; + repaint(); + } + + public void add(AccordionPaneSubPanel subPanel) { + subPanel.setAccordionPane(this); + subPanel.setIndex(this.children.size()); + this.children.add(subPanel); + super.add(subPanel); + } + + public void paint(Graphics g) { + // Do some initializing on the first paint call + if (this.selected < 0 && this.children.size() > 0) { + this.setSelected(0, false); + } + if (this.transitionStep >= this.remainder && this.remainder > 0 + && timer != null) { + this.timer.stop(); + this.timer = null; + System.out.println("Killed timer."); + } + super.paint(g); + } + + /** + * Set the currently active/selected pane. + * + * @param num + * The pane number to select (0 is first) + */ + public void setSelected(int num) { + setSelected(num, false); + } + + /** + * Set the currently active/selected pane. + * + * @param num + * The pane number to select (0 is first) + * @param showAnimation + * Show the animation transition from the previously selected pane to + * the newly selected pane. + */ + public void setSelected(int num, boolean showAnimation) { + if (num == selected) + return; + if (!showAnimation) { + this.previouslySelected = -1; + doLayout(); // fix echatellier 20101202 strange , add this to display + } + else + this.previouslySelected = selected; + this.selected = num; + for (int i = 0; i < children.size(); i++) { + AccordionPaneSubPanel subPanel = (AccordionPaneSubPanel) children + .get(i); + // subPanel.child.setVisible ( i == num + // || ( i == this.previouslySelected && showAnimation ) ); + subPanel.titlePanel + .setBackground(i == num ? this.activePaneBackgroundColor + : this.paneBackgroundColor); + } + if (this.previouslySelected >= 0 && showAnimation) { + ActionListener a = new ActionListener() { + public void actionPerformed(ActionEvent e) { + // Add another step in the animation transition + if (remainder - transitionStep < 10) { + transitionStep++; + } else if (remainder - transitionStep < 25) { + transitionStep += 3; + } else { + transitionStep += 10; + } + // System.out.println ( "transitionStep=" + transitionStep ); + if (transitionStep >= remainder) { + // We're done with the animation + transitionStep = -1; + timer.stop(); + } else { + timer.setInitialDelay(1); + timer.restart(); + } + doLayout(); + validate(); + repaint(); + } + }; + + if (timer != null) { + timer.stop(); + timer = null; + } + + // Animate the transition from one panel to another panel. + this.transitionStep = 0; + timer = new Timer(1, a); + timer.start(); + } + this.validate(); + this.repaint(); + } + + /** + * Get the index of the currently selected pane. + * + * @return the index of the currently selected pane + */ + public int getSelectedIndex() { + return this.selected; + } + + /** + * Get the number of panes in the AccordionPane. + * + * @return the number of panes + */ + public int getPaneCount() { + return this.children.size(); + } + + /** + * Set the text title at the specified location + * + * @param index + * the index number of the pane + * @param newTitle + * the new title for the specified pane. + */ + public void setTitleAt(int index, String newTitle) { + AccordionPaneSubPanel subPanel = (AccordionPaneSubPanel) this.children + .get(index); + subPanel.titleLabel.setText(newTitle); + } + + /** + * Get the text title at the specified location + * + * @param index + * the index number of the pane + * @return the text title of the specified pane + */ + public String getTitleAt(int index) { + AccordionPaneSubPanel subPanel = (AccordionPaneSubPanel) this.children + .get(index); + return subPanel.titleLabel.getText(); + } + + /** + * Set the icon for the specified location. + * + * @param index + * @param icon + */ + public void setIconAt(int index, Icon icon) { + AccordionPaneSubPanel subPanel = (AccordionPaneSubPanel) this.children + .get(index); + subPanel.titleLabel.setIcon(icon); + } + + /** + * Returns the component at index. + * + * @param index + * the index of the item being queried + * @return component + */ + public Component getComponentAt(int index) { + AccordionPaneSubPanel subPanel = (AccordionPaneSubPanel) this.children + .get(index); + return subPanel.child; + } + + /** + * Returns the currently selected component for this AccordionPane. + * + * @return the currently selected component + */ + public Component getSelectedComponent() { + AccordionPaneSubPanel subPanel = (AccordionPaneSubPanel) this.children + .get(this.selected); + return subPanel.child; + } + +} \ No newline at end of file Property changes on: trunk/coser-ui/src/main/java/fr/ifremer/coser/ui/widgets/AccordionPane.java ___________________________________________________________________ Added: svn:keywords + Author Date Id Revision HeadURL Added: trunk/coser-ui/src/main/java/fr/ifremer/coser/ui/widgets/AccordionPaneSubPanel.java =================================================================== --- trunk/coser-ui/src/main/java/fr/ifremer/coser/ui/widgets/AccordionPaneSubPanel.java (rev 0) +++ trunk/coser-ui/src/main/java/fr/ifremer/coser/ui/widgets/AccordionPaneSubPanel.java 2010-12-03 10:45:54 UTC (rev 351) @@ -0,0 +1,127 @@ +/* %%Ignore-License + * Copyright (C) 2007 Craig Knudsen + * + * AccordionPane is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 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 Lesser General Public + * License for more details. + * + * A copy of the GNU Lesser General Public License can be found at www.gnu.org. + * To receive a hard copy, you can write to: + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA. + */ + +package fr.ifremer.coser.ui.widgets; + +import java.awt.BorderLayout; +import java.awt.Component; +import java.awt.Cursor; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; + +import javax.swing.BorderFactory; +import javax.swing.JComponent; +import javax.swing.JLabel; +import javax.swing.JPanel; + +public class AccordionPaneSubPanel extends JPanel { + + /** serialVersionUID. */ + private static final long serialVersionUID = 4836598811061630517L; + + protected AccordionPane accordionPane; + + JPanel titlePanel; + JLabel titleLabel; + JComponent child; + int index; + static Cursor handCursor = null; + static int mousePressedInd = -1; + + public AccordionPaneSubPanel() { + this.setBorder(BorderFactory.createEtchedBorder()); + if (handCursor == null) + handCursor = new Cursor(Cursor.HAND_CURSOR); + + this.setLayout(new BorderLayout()); + } + + public void setAccordionPane(AccordionPane accordionPane) { + this.accordionPane = accordionPane; + + if (titlePanel != null) { + this.titlePanel.setBackground(accordionPane.paneBackgroundColor); + } + } + + public void setIndex(int index) { + this.index = index; + } + + public JPanel getTitlePanel() { + return titlePanel; + } + + public JLabel getTitleLabel() { + return titleLabel; + } + + public void setTitle(String title) { + this.titleLabel = new JLabel(title); + this.titlePanel = new JPanel(); + //this.titlePanel.setBorder(BorderFactory.createEmptyBorder(0, 0, 3, 3)); + this.titlePanel.setBorder(BorderFactory.createRaisedBevelBorder()); + this.titlePanel.setLayout(new BorderLayout()); + this.titlePanel.add(this.titleLabel, BorderLayout.WEST); + if (accordionPane != null) { + this.titlePanel.setBackground(accordionPane.paneBackgroundColor); + } + // Set cursor to hand cursor to indicate the user can select the title area + titlePanel.setCursor(handCursor); + this.add(titlePanel, BorderLayout.NORTH); + + // Add mouse listener for titlePanel so we can change the cursor and also + // listen for mouse click. + this.titlePanel.addMouseListener(new MouseListener() { + public void mouseEntered(MouseEvent me) { + } + + public void mouseExited(MouseEvent me) { + } + + public void mouseClicked(MouseEvent me) { + if (accordionPane.selected != index) { + accordionPane.setSelected(index); + } + } + + public void mousePressed(MouseEvent me) { + mousePressedInd = index; + } + + public void mouseReleased(MouseEvent me) { + if (mousePressedInd == index) { + if (accordionPane.selected != index) { + accordionPane.setSelected(index); + } + } + mousePressedInd = -1; + } + }); + + } + + public Component add(Component child) { + // child.setVisible ( false ); + this.add(child, BorderLayout.CENTER); + //validate(); + //repaint(); + return child; + } +} \ No newline at end of file Property changes on: trunk/coser-ui/src/main/java/fr/ifremer/coser/ui/widgets/AccordionPaneSubPanel.java ___________________________________________________________________ Added: svn:keywords + Author Date Id Revision HeadURL