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;
}
}