package org.openswing.swing.miscellaneous.client; import java.applet.*; import java.beans.*; import java.util.*; import java.awt.*; import java.awt.event.*; import javax.swing.*; import org.openswing.swing.client.*; import org.openswing.swing.mdi.client.*; import org.openswing.swing.util.client.*; /** * <p>Title: OpenSwing Framework</p> * <p>Description: this class allows to show an iconifable window, i.e. a window that can contains any kind of graphics component within it, * since it inherits from JPanel. As default behavior, it is composed of a top panel and a main panel: * - top panel may contain: an optional title icon, a title (showed in bold style) and two buttons: a "reduce to icon" button and a "close" button, both can be hidden * - main panel is this, i.e. any content manually added to this is showed inside this main panel. * Window can be reduced to icon by pressing the "reduce to icon" button or by double clicking inside the top panel (if no "reduce to icon" button is visible). * Window can be closed by pressing the "close" button or by clicking inside the main panel (if no "close" button is visible). * As default settings, this panel has a dimension of 300 x 150 pixels. * Window location can be defined in several ways: * - using absolute location, by using this.setLocation method * - by anchoring the window to the TOP/BOTTOM/INSIDE_BOTTOM/INSIDE_TOP of another component, through setAnchorWindow() method.</p> * Several events fired by this window can be listened, through the method: addIconifableWindowListener. * <p>Copyright: Copyright (C) 2006 Mauro Carniel</p> * * <p> This file is part of OpenSwing Framework. * This library is free software; you can redistribute it and/or * modify it under the terms of the (LGPL) Lesser General Public * License as published by the Free Software Foundation; * * GNU LESSER GENERAL PUBLIC LICENSE * Version 2.1, February 1999 * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * The author may be contacted at: * maurocarniel@tin.it</p> * * @author Mauro Carniel * @version 1.0 */ public class IconifableWindow extends JPanel { /** window */ private JWindow window; /** title to show inside this panel */ private LabelControl title = new LabelControl(); /** anchor the window to the top of the specified component */ public static final int TOP = 0; /** anchor the window to the bottom of the specified component */ public static final int BOTTOM = 1; /** anchor the window inside the specified component at the bottom */ public static final int INSIDE_BOTTOM = 2; /** anchor the window inside the specified component at the top */ public static final int INSIDE_TOP = 3; /** component to anchor to */ private JComponent anchorComponent; /** anchor type: TOP or BOTTOM or INSIDE_BOTTOM or INSIDE_TOP */ protected int constraint; /** define if a close button must be showed (<code>false</code> = window will be closed by simply click the mouse inside it); default value: <code>false</code> */ private boolean showCloseButton; /** define if a reduce to icon button must be showed (<code>true</code> means that the iconified window will be enlarged by clicking on it); default value: <code>false</code> */ private boolean showReduceToIconButton; /** panel that contains the title and "close" and "reduce to icon" buttons */ private JPanel topPanel = new JPanel() { public void paint(Graphics g) { super.paint(g); if (showCloseButton || showReduceToIconButton || title.getLabel()!=null && !title.getLabel().equals("") || titleImageName!=null && !titleImageName.equals("")) { g.setColor(Color.lightGray); g.drawLine(0, getHeight() - 1, getWidth(), getHeight() - 1); } } }; /** close window button */ private ImagePanel closeButton = new ImagePanel(); /** reduce window to icon button */ private ImagePanel reduceToIconButton = new ImagePanel(); /** restore window to original dimension button */ private ImagePanel restoreButton = new ImagePanel(); /** last window dimension (before reducing it to icon) */ private Dimension lastWindowDimension = null; /** window height, when it is iconified */ private int iconHeight = 21; /** listeners of type IconifableWindowListener */ private ArrayList iconifableWindowListeners = new ArrayList(); /** title image name (optional), to show at the left of the title */ private String titleImageName; /** title image */ private ImagePanel titleImage = new ImagePanel(); /** flag used to define if the window can be closed (when the close button is hidden and user has clicked with the mouse inside it); default value: false */ private boolean allowsCloseWindow = false; public IconifableWindow() { setBackground(new Color(240,240,240)); title.setFont(new Font(title.getFont().getName(),Font.BOLD,title.getFont().getSize())); titleImage.setOpaque(false); titleImage.setScrollBarsPolicy(closeButton.SCROLLBAR_NEVER); titleImage.setBorder(BorderFactory.createEmptyBorder()); topPanel.setOpaque(false); topPanel.setLayout(new GridBagLayout()); closeButton.setImageName("closealert.gif"); closeButton.setOpaque(false); closeButton.setBorder(BorderFactory.createEmptyBorder()); closeButton.setScrollBarsPolicy(closeButton.SCROLLBAR_NEVER); closeButton.addMouseListener(new MouseAdapter() { public void mouseClicked(MouseEvent e) { hideWindow(); } }); restoreButton.setImageName("maximizealert.gif"); restoreButton.setOpaque(false); restoreButton.setBorder(BorderFactory.createEmptyBorder()); restoreButton.setScrollBarsPolicy(restoreButton.SCROLLBAR_NEVER); restoreButton.addMouseListener(new MouseAdapter() { public void mouseClicked(MouseEvent e) { restoreWindow(); } }); reduceToIconButton.setImageName("reducealert.gif"); reduceToIconButton.setOpaque(false); reduceToIconButton.setBorder(BorderFactory.createEmptyBorder()); reduceToIconButton.setScrollBarsPolicy(reduceToIconButton.SCROLLBAR_NEVER); reduceToIconButton.addMouseListener(new MouseAdapter() { public void mouseClicked(MouseEvent e) { reduceToIcon(); } }); lastWindowDimension = new Dimension(300,150); super.setSize(lastWindowDimension); super.setFocusable(false); setBackground(UIManager.getColor("Label.background")); super.setPreferredSize(new Dimension(300,150)); addMouseListener(new MouseAdapter() { public void mouseClicked(MouseEvent e) { if (SwingUtilities.isLeftMouseButton(e) && !showCloseButton && allowsCloseWindow) { hideWindow(); } } }); title.addMouseListener(new MouseAdapter() { public void mouseClicked(MouseEvent e) { if (SwingUtilities.isLeftMouseButton(e) && e.getClickCount()==2 && !showReduceToIconButton) { if (window.getSize().height!=iconHeight) { reduceToIcon(); } else { restoreWindow(); } } } }); topPanel.addMouseListener(new MouseAdapter() { public void mouseClicked(MouseEvent e) { if (SwingUtilities.isLeftMouseButton(e) && e.getClickCount()==2 && !showReduceToIconButton) { if (window.getSize().height!=iconHeight) { reduceToIcon(); } else { restoreWindow(); } } } }); } /** * Method invoked by "reduce to icon" or "restore" buttons to prepare top panel content, according to window settings. * @param iconifyWindow <code>true</code> to insert the "restore" button inside the top panel, <code>false</code> to insert the "reduce to icon" button inside the top panel */ protected final void setupTopPanel(boolean windowIconified) { topPanel.removeAll(); if (titleImageName!=null && !titleImageName.equals("")) topPanel.add(titleImage, new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0 ,GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(2,2,2,2), 0, 0)); if (title.getLabel()!=null && !title.getLabel().equals("")) topPanel.add(title, new GridBagConstraints(1, 0, 1, 1, 1.0, 0.0 ,GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(2,2,2,2), 0, 0)); if (windowIconified) { if (showReduceToIconButton) topPanel.add(restoreButton, new GridBagConstraints(2, 0, 1, 1, 0.0, 0.0 ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(2,2,2,2), 0, 0)); if (showCloseButton) topPanel.add(closeButton, new GridBagConstraints(3, 0, 1, 1, 0.0, 0.0 ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(2,2,2,2), 0, 0)); } else { if (showReduceToIconButton) topPanel.add(reduceToIconButton, new GridBagConstraints(2, 0, 1, 1, 0.0, 0.0 ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(2,2,2,2), 0, 0)); if (showCloseButton) topPanel.add(closeButton, new GridBagConstraints(3, 0, 1, 1, 0.0, 0.0 ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(2,2,2,2), 0, 0)); } topPanel.setSize(window.getSize().width,topPanel.getHeight()); topPanel.revalidate(); topPanel.repaint(); } /** * Show a window that contains this. */ public final void showWindow() { closeButton.setBackground(this.getBackground()); reduceToIconButton.setBackground(this.getBackground()); restoreButton.setBackground(this.getBackground()); if (window!=null) { hideWindow(); } Component topLevelAncestor = null; if (anchorComponent!=null) topLevelAncestor = getTopLevelAncestor(anchorComponent); else topLevelAncestor = getTopLevelAncestor(getParent()); if (topLevelAncestor!=null) { if (topLevelAncestor instanceof Frame) { window = new JWindow((Frame)topLevelAncestor); } else if (topLevelAncestor instanceof Window) { window = new JWindow((Window)topLevelAncestor); } else { Window frame = ClientUtils.getParentWindow((JComponent)topLevelAncestor); window = new JWindow(frame); } // move window if ancestor component has been resized/moved... topLevelAncestor.addComponentListener(new ComponentAdapter() { /** * Invoked when the component's size changes. */ public void componentResized(ComponentEvent e) { if (lastWindowDimension!=null) lastWindowDimension = new Dimension( anchorComponent.getSize().width, lastWindowDimension.height ); // update size for all window's content pane containers... if (window!=null) { Container c = window.getContentPane(); while(c!=null && !(c.equals(window))) { c.setSize(window.getWidth(),c.getHeight()); c = c.getParent(); } } // update size of content pane children... for(int j=0;j<window.getContentPane().getComponentCount();j++) { window.getContentPane().getComponents()[j].setSize( new Dimension( window.getWidth(), window.getContentPane().getComponents()[j].getHeight() ) ); ((JComponent)window.getContentPane().getComponents()[j]).revalidate(); } locateWindow(); } /** * Invoked when the component's position changes. */ public void componentMoved(ComponentEvent e) { if (lastWindowDimension!=null) lastWindowDimension = new Dimension( anchorComponent.getSize().width, lastWindowDimension.height ); // update size for all window's content pane containers... if (window!=null) { Container c = window.getContentPane(); while(c!=null && !(c.equals(window))) { c.setSize(window.getWidth(),c.getHeight()); c = c.getParent(); } } // update size of content pane children... for(int j=0;j<window.getContentPane().getComponentCount();j++) { window.getContentPane().getComponents()[j].setSize( new Dimension( window.getWidth(), window.getContentPane().getComponents()[j].getHeight() ) ); ((JComponent)window.getContentPane().getComponents()[j]).revalidate(); } locateWindow(); } }); } else window = new JWindow(); window.addMouseListener(new MouseAdapter() { public void mouseClicked(MouseEvent e) { if (SwingUtilities.isLeftMouseButton(e) && !showCloseButton && allowsCloseWindow) { hideWindow(); } } }); // set window current size... if (lastWindowDimension!=null) window.setSize(lastWindowDimension); // set window location... if (anchorComponent!=null && (constraint==TOP || constraint==BOTTOM || constraint==INSIDE_TOP || constraint==INSIDE_BOTTOM)) { locateWindow(); // move window if parent component has been resized/moved... anchorComponent.addComponentListener(new ComponentAdapter() { /** * Invoked when the component's size changes. */ public void componentResized(ComponentEvent e) { if (lastWindowDimension!=null) lastWindowDimension = new Dimension( anchorComponent.getSize().width, lastWindowDimension.height ); // update size for all window's content pane containers... if (window!=null) { Container c = window.getContentPane(); while(c!=null && !(c.equals(window))) { c.setSize(window.getWidth(),c.getHeight()); c = c.getParent(); } } // update size of content pane children... for(int j=0;j<window.getContentPane().getComponentCount();j++) { window.getContentPane().getComponents()[j].setSize( new Dimension( window.getWidth(), window.getContentPane().getComponents()[j].getHeight() ) ); ((JComponent)window.getContentPane().getComponents()[j]).revalidate(); } locateWindow(); } /** * Invoked when the component's position changes. */ public void componentMoved(ComponentEvent e) { locateWindow(); } }); } // set window content... ((JComponent)window.getContentPane()).setBorder(BorderFactory.createLineBorder(Color.lightGray)); window.getContentPane().setLayout(new BorderLayout()); window.getContentPane().setBackground(this.getBackground()); window.getContentPane().add(this,BorderLayout.CENTER); // add top panel to the window... setupTopPanel(false); window.getContentPane().add(topPanel, BorderLayout.NORTH); fireWindowEvent(IconifableWindowListener.WINDOW_CREATED); showWindowInternally(); window.toFront(); } /** * Set window location, according to window current size (lastWindowDimension) and anchored component position and constraint. */ private void locateWindow() { Component topLevelAncestor = getTopLevelAncestor(anchorComponent); Point location = null; if (topLevelAncestor!=null && topLevelAncestor instanceof JWindow) location = topLevelAncestor.getLocationOnScreen(); else if (topLevelAncestor!=null && topLevelAncestor instanceof MDIFrame) { int x = topLevelAncestor.getLocation().x; int y = topLevelAncestor.getLocation().y; Container c = anchorComponent; while(!(c.equals(topLevelAncestor))) { x += c.getLocation().x; y += c.getLocation().y; c = c.getParent(); } location = new Point(x,y); } else location = anchorComponent.getLocationOnScreen(); if (constraint==TOP) location.y = location.y-window.getHeight(); else if (constraint==BOTTOM) location.y = location.y+anchorComponent.getSize().height+1; else if (constraint==INSIDE_BOTTOM) { location.y = location.y+anchorComponent.getSize().height-window.getHeight(); } else if (constraint==INSIDE_TOP) { location.y = location.y+1; } if (location.x<0) location.x = 0; if (location.y<0) location.y = 0; window.setLocation(location); } /** * This method shows the window. */ protected void showWindowInternally() { window.setVisible(true); fireWindowEvent(IconifableWindowListener.WINDOW_SHOWED); } /** * Manually hide the window. */ public final void hideWindow() { if (window!=null) { window.getContentPane().removeAll(); window.setVisible(false); window.dispose(); fireWindowEvent(IconifableWindowListener.WINDOW_CLOSED); } } /** * Anchor the window to the specified component. * @param component component used to calculate window location * @param constraint anchor type: TOP or BOTTOM or INSIDE_BOTTOM or INSIDE_TOP */ public final void anchorWindow(JComponent anchorComponent,int constraint) { this.anchorComponent = anchorComponent; this.constraint = constraint; } /** * Sets the size of the window, when it is maximized. */ public final void setWindowMaximumSize(Dimension lastWindowDimension) { this.lastWindowDimension = lastWindowDimension; // if (window!=null && window.isVisible()) { // window.setSize(lastWindowDimension); // this.revalidate(); // ((JComponent)window.getContentPane()).revalidate(); // } } /** * @return size of the window, when it is maximized */ public final Dimension getWindowMaximumSize() { return lastWindowDimension; } /** * @return define if a close button must be showed (<code>false</code> = window will be closed by simply click mouse inside it) */ public final boolean isShowCloseButton() { return showCloseButton; } /** * Define if a close button must be showed (<code>false</code> = window will be closed by simply click mouse inside it); default value: <code>false</code>. * @param showCloseButton define if a close button must be showed (<code>false</code> = window will be closed by simply mouse click inside it) */ public final void setShowCloseButton(boolean showCloseButton) { this.showCloseButton = showCloseButton; } /** * @return define if a reduce to icon button must be showed (<code>true</code> means that the iconified window will be enlarged by clicking on it) */ public final boolean isShowReduceToIconButton() { return showReduceToIconButton; } /** * Define if a reduce to icon button must be showed (<code>true</code> means that the iconified window will be enlarged by clicking on it); default value: <code>false</code>. * @param showReduceToIconButton define if a reduce to icon button must be showed (<code>true</code> means that the iconified window will be enlarged by clicking on it) */ public final void setShowReduceToIconButton(boolean showReduceToIconButton) { this.showReduceToIconButton = showReduceToIconButton; } /** * @param component component to analyze * @return parent component (Window or Frame) */ private final Component getTopLevelAncestor(Component component) { if (component == null) return null; for (Component p = component; p != null; p = p.getParent()) if (p instanceof Window || p instanceof Applet) return p; return null; } /** * Set the title text to show inside this panel. * @param title text to show inside this panel; it will be translated, according to language settings */ public final void setTitle(String title) { this.title.setLabel(title); } /** * @return title text to show inside this panel */ public final String getTitle() { return this.title.getLabel(); } /** * @return window height, when it is iconified */ public final int getIconHeight() { return iconHeight; } /** * Set window height, when it is iconified. * @param iconHeight window height, when it is iconified */ public final void setIconHeight(int iconHeight) { this.iconHeight = iconHeight; } /** * Add an IconifableWindowListener to this window. * @param listener listener of events fired by this window */ public final void addIconifableWindowListener(IconifableWindowListener listener) { iconifableWindowListeners.add(listener); } /** * Remove an IconifableWindowListener to this window. * @param listener listener of events fired by this window that must be removed */ public final void removeIconifableWindowListener(IconifableWindowListener listener) { iconifableWindowListeners.remove(listener); } /** * @return title image name (optional) */ public final String getTitleImageName() { return titleImageName; } /** * Set the title image name (optional), to show at the left of the title. * @param titleImageName title image name (optional) */ public final void setTitleImageName(String titleImageName) { this.titleImageName = titleImageName; if (!Beans.isDesignTime()) { titleImage.setImageName(titleImageName); } } /** * Fire the specified window event. * @param event window event to fire */ protected final void fireWindowEvent(int event) { for(int i=0;i<iconifableWindowListeners.size();i++) ((IconifableWindowListener)iconifableWindowListeners.get(i)).windowEvent(this,event); } /** * @return iconifable window; null if showWindow() method has not been yet called */ public final JWindow getWindow() { return window; } /** * Set top panel background color. * @param color top panel background color */ public final void setTopPanelBackground(Color color) { topPanel.setBackground(color); topPanel.setOpaque(color!=null); } /** * @return top panel background color */ public final Color getTopPanelBackground() { return topPanel.getBackground(); } /** * Reduce the window to icon. * Note that the window must already be visible ("showWindow" method must be invoked before). */ public final void reduceToIcon() { if (window!=null) { if (window.getSize().height!=iconHeight) { window.setSize(lastWindowDimension.width,iconHeight); setupTopPanel(true); locateWindow(); // set window location, according to window current size (lastWindowDimension) and anchored component position and constraint // window.setLocation(window.getLocation().x,window.getLocation().y+lastWindowDimension.height-iconHeight); this.revalidate(); ((JComponent)window.getContentPane()).revalidate(); fireWindowEvent(IconifableWindowListener.WINDOW_REDUCED_TO_ICON); } } } /** * Restore window to its original dimension. */ public final void restoreWindow() { if (window!=null) { if (lastWindowDimension!=null && lastWindowDimension.height!=iconHeight) { // window.setLocation(window.getLocation().x,window.getLocation().y-lastWindowDimension.height+iconHeight); // this.dim = lastWindowDimension; window.setSize(lastWindowDimension); setupTopPanel(false); locateWindow(); // set window location, according to window current size (lastWindowDimension) and anchored component position and constraint this.revalidate(); ((JComponent)window.getContentPane()).revalidate(); fireWindowEvent(IconifableWindowListener.WINDOW_RESTORED); } } } /** * @return define if the window can be closed (when the close button is hidden and user has clicked with the mouse inside it) */ public final boolean isAllowsCloseWindow() { return allowsCloseWindow; } /** * Define if the window can be closed (when the close button is hidden and user has clicked with the mouse inside it). * @param allowsCloseWindow boolean define if the window can be closed */ public final void setAllowsCloseWindow(boolean allowsCloseWindow) { this.allowsCloseWindow = allowsCloseWindow; } /** * @return constraint applied between window and anchored component; possible values: TOP, BOTTOM, INSIDE_BOTTOM, INSIDE_TOP */ public final int getConstraint() { return constraint; } }