001    /*
002     * $Id: JXGlassBox.java,v 1.4 2005/10/10 18:02:02 rbair Exp $
003     *
004     * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle,
005     * Santa Clara, California 95054, U.S.A. All rights reserved.
006     *
007     * This library is free software; you can redistribute it and/or
008     * modify it under the terms of the GNU Lesser General Public
009     * License as published by the Free Software Foundation; either
010     * version 2.1 of the License, or (at your option) any later version.
011     * 
012     * This library is distributed in the hope that it will be useful,
013     * but WITHOUT ANY WARRANTY; without even the implied warranty of
014     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
015     * Lesser General Public License for more details.
016     * 
017     * You should have received a copy of the GNU Lesser General Public
018     * License along with this library; if not, write to the Free Software
019     * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
020     */
021    
022    package org.jdesktop.swingx;
023    
024    import java.applet.Applet;
025    import java.awt.Color;
026    import java.awt.Component;
027    import java.awt.Container;
028    import java.awt.Dimension;
029    import java.awt.Graphics;
030    import java.awt.Point;
031    import java.awt.Rectangle;
032    import java.awt.Window;
033    import java.awt.event.ActionEvent;
034    import java.awt.event.ActionListener;
035    import java.awt.event.MouseAdapter;
036    import java.awt.event.MouseEvent;
037    
038    import javax.swing.JComponent;
039    import javax.swing.SwingConstants;
040    import javax.swing.SwingUtilities;
041    import javax.swing.Timer;
042    
043    
044    
045    
046    /**
047     * Component used to display transluscent user-interface content.
048     * This component and all of its content will be displayed with the specified
049     * "alpha" transluscency property value.  When this component is made visible,
050     * it's content will fade in until the alpha transluscency level is reached.
051     * <p>
052     * If the glassbox's &quot;dismissOnClick&quot; property is <code>true</code>
053     * (the default) then the glassbox will be made invisible when the user
054     * clicks on it.</p>
055     * <p>
056     * This component is particularly useful for displaying transient messages
057     * on the glasspane.</p>
058     *
059     * @author Amy Fowler
060     * @version 1.0
061     */
062    
063    public class JXGlassBox extends JXPanel {
064        private static final int SHOW_DELAY = 30; // ms
065        private static final int TIMER_INCREMENT = 10; // ms
066    
067        private float alphaStart = 0.01f;
068        private float alphaEnd = 0.8f;
069    
070        private Timer animateTimer;
071        private float alphaIncrement = 0.02f;
072    
073        private boolean dismissOnClick = false;
074        private MouseAdapter dismissListener = null;
075    
076        public JXGlassBox() {
077            setOpaque(false);
078            setAlpha(alphaStart);
079            setBackground(Color.white);
080            setDismissOnClick(true);
081    
082            animateTimer = new Timer(TIMER_INCREMENT, new ActionListener() {
083                public void actionPerformed(ActionEvent e) {
084                    setAlpha(getAlpha() + alphaIncrement);
085                }
086            });
087        }
088    
089        public JXGlassBox(float alpha) {
090            this();
091            setAlpha(alpha);
092        }
093    
094        public void setAlpha(float alpha) {
095            super.setAlpha(alpha);
096            this.alphaIncrement = (alphaEnd - alphaStart)/(SHOW_DELAY/TIMER_INCREMENT);
097        }
098    
099        public void setDismissOnClick(boolean dismissOnClick) {
100            boolean oldDismissOnClick = this.dismissOnClick;
101            this.dismissOnClick = dismissOnClick;
102            if (dismissOnClick && !oldDismissOnClick) {
103                if (dismissListener == null) {
104                    dismissListener = new MouseAdapter() {
105                        public void mouseClicked(MouseEvent e) {
106                            JComponent glassBox = JXGlassBox.this;
107                            JComponent parent = (JComponent) glassBox.getParent();
108                            Container toplevel = parent.getTopLevelAncestor();
109                            parent.remove(glassBox);
110                            toplevel.validate();
111                            toplevel.repaint();
112                        }
113                    };
114                }
115                addMouseListener(dismissListener);
116            }
117            else if (!dismissOnClick && oldDismissOnClick) {
118                removeMouseListener(dismissListener);
119            }
120        }
121    
122        public void paint(Graphics g) {
123            super.paint(g);
124            if (!animateTimer.isRunning() && getAlpha() < alphaEnd ) {
125                animateTimer.start();
126            }
127            if (animateTimer.isRunning() && getAlpha() >= alphaEnd) {
128                animateTimer.stop();
129            }
130        }
131    
132        public void setVisible(boolean visible) {
133            setAlpha(alphaStart);
134            super.setVisible(visible);
135        }
136    
137        private Container getTopLevel() {
138            Container p = getParent();
139            while (p != null && !(p instanceof Window || p instanceof Applet)) {
140                p = p.getParent();
141            }
142            return p;
143        }
144    
145        public void showOnGlassPane(Container glassPane, Component component,
146                                    int componentX, int componentY, int positionHint) {
147            Dimension boxPrefSize = getPreferredSize();
148            Dimension glassSize = glassPane.getSize();
149            Rectangle compRect = component.getBounds();
150            int boxX = 0;
151            int boxY = 0;
152            int boxWidth = Math.min(boxPrefSize.width, glassSize.width);
153            int boxHeight = Math.min(boxPrefSize.height, glassSize.height);
154    
155            Point compLocation = SwingUtilities.convertPoint(component.getParent(),
156                                                    compRect.x, compRect.y,
157                                                    glassPane);
158    
159            if (positionHint == SwingConstants.TOP) {
160                if (compLocation.x + componentX + boxWidth <= glassSize.width) {
161                    boxX = compLocation.x + componentX;
162                } else {
163                    boxX = glassSize.width - boxWidth;
164                }
165                boxY = compLocation.y - boxHeight;
166                if (boxY < 0) {
167                    if (compLocation.y + compRect.height <= glassSize.height) {
168                        boxY = compLocation.y + compRect.height;
169                    }
170                    else {
171                        boxY = 0;
172                    }
173                }
174            }
175    
176            glassPane.setLayout(null);
177            setBounds(boxX, boxY, boxWidth, boxHeight);
178            glassPane.add(this);
179            glassPane.setVisible(true);
180    
181            Container topLevel = getTopLevel();
182            topLevel.validate();
183            topLevel.repaint();
184    
185        }
186    
187        public void showOnGlassPane(Container glassPane, int originX, int originY) {
188            Dimension boxPrefSize = getPreferredSize();
189            Dimension glassSize = glassPane.getSize();
190            int boxX = 0;
191            int boxY = 0;
192            int boxWidth = 0;
193            int boxHeight = 0;
194    
195            boxWidth = Math.min(boxPrefSize.width, glassSize.width);
196            boxHeight = Math.min(boxPrefSize.height, glassSize.height);
197    
198            if (originY - boxHeight >= 0) {
199                boxY = originY - boxHeight;
200            } else if (originY + boxHeight <= glassSize.height) {
201                boxY = originY;
202            } else {
203                boxY = glassSize.height - boxHeight;
204            }
205    
206            if (originX + boxWidth <= glassSize.width) {
207                boxX = originX;
208            } else if (originX >= boxWidth) {
209                boxX = originX - boxWidth;
210            } else {
211                boxX = glassSize.width - boxWidth;
212            }
213    
214            glassPane.setLayout(null);
215            setBounds(boxX, boxY, boxWidth, boxHeight);
216            glassPane.add(this);
217            glassPane.setVisible(true);
218    
219            Container topLevel = getTopLevel();
220            topLevel.validate();
221            topLevel.repaint();
222        }
223    
224    }