View Javadoc

1   /*
2   Wotonomy: OpenStep design patterns for pure Java applications.
3   Copyright (C) 2000 Blacksmith, Inc.
4   
5   This library is free software; you can redistribute it and/or
6   modify it under the terms of the GNU Lesser General Public
7   License as published by the Free Software Foundation; either
8   version 2.1 of the License, or (at your option) any later version.
9   
10  This library is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  Lesser General Public License for more details.
14  
15  You should have received a copy of the GNU Lesser General Public
16  License along with this library; if not, see http://www.gnu.org
17  */
18  
19  package net.wotonomy.ui.swing.util;
20  
21  import java.awt.Component;
22  import java.awt.Container;
23  import java.awt.Image;
24  import java.awt.Rectangle;
25  import java.awt.Toolkit;
26  import java.awt.event.ActionEvent;
27  import java.awt.event.ActionListener;
28  import java.net.URL;
29  
30  import javax.swing.ImageIcon;
31  import javax.swing.JComponent;
32  import javax.swing.JLabel;
33  import javax.swing.JPanel;
34  import javax.swing.JRootPane;
35  import javax.swing.SwingUtilities;
36  import javax.swing.Timer;
37  
38  /***
39  * Visually highlights a component with the specified image for a brief period.
40  *
41  * @author michael@mpowers.net
42  * @author $Author: cgruber $
43  * @version $Revision: 904 $
44  * $Date: 2006-02-18 23:19:05 +0000 (Sat, 18 Feb 2006) $
45  */
46  public class ComponentHighlighter implements ActionListener
47  {
48      // lots of state to track
49      JRootPane rootPane;
50      JComponent component;
51      Component oldGlassPane;
52      JLabel imageLabel;
53      Timer timer;
54      JPanel glassPane;
55  
56  /***
57  * Alternate "Fire-and-forget" constructor loads an image from a URL.
58  * @param aComponent A Component that will be highlighted.
59  * @param aURL A URL pointing to an image.
60  */
61      public ComponentHighlighter( JComponent aComponent, URL aURL )
62      {
63          if ( aURL == null ) return;
64          init( aComponent, Toolkit.getDefaultToolkit().getImage( aURL ) );
65      }
66  
67  /***
68  * "Fire-and-forget" constructor.
69  * @param aComponent A Component that will be highlighted.
70  * @param anImage An image, preferably an animated GIF with transparency,
71  * that will slide along the length of the component.
72  */
73      public ComponentHighlighter( JComponent aComponent, Image anImage )
74      {
75          init( aComponent, anImage );
76      }
77  
78      protected void init( JComponent aComponent, Image anImage )
79      {
80          if ( ( aComponent == null ) || ( anImage == null ) ) return;
81  
82          component = aComponent;
83          rootPane = SwingUtilities.getRootPane( component );
84          oldGlassPane = rootPane.getGlassPane();
85  
86  		glassPane = new JPanel();
87  		rootPane.setGlassPane( glassPane );
88          glassPane.setVisible( true );
89          glassPane.setOpaque( false );
90          glassPane.setLayout( null );
91  
92          ImageIcon icon = new ImageIcon( anImage );
93  
94          imageLabel = new JLabel();
95          imageLabel.setIconTextGap( 0 );
96          imageLabel.setIcon( icon );
97          imageLabel.setSize( icon.getIconWidth(), icon.getIconHeight() );
98          glassPane.add( imageLabel );
99  
100         Rectangle bounds = component.getBounds();
101         if ( component.getParent() instanceof Component )
102         {
103             bounds = SwingUtilities.convertRectangle( (Container) component.getParent(),
104                 bounds, rootPane.getContentPane() );
105         }
106         imageLabel.setLocation(
107             bounds.x, bounds.y + bounds.height - imageLabel.getBounds().height );
108 
109         glassPane.revalidate();
110         glassPane.repaint();
111 
112         component.transferFocus(); // halts a caret, if necessary
113 
114         timer = new Timer( 80, this );
115         timer.setRepeats( true );
116         timer.start();
117     }
118 
119     public void actionPerformed( ActionEvent evt )
120     {
121         Rectangle bounds = imageLabel.getBounds();
122         Rectangle target = component.getBounds();
123         if ( component.getParent() instanceof Component )
124         {
125             target = SwingUtilities.convertRectangle( (Container) component.getParent(),
126                 target, rootPane.getContentPane() );
127         }
128 
129         if ( bounds.x + bounds.width > target.x + target.width )
130         { // clean up and end
131             timer.stop();
132             rootPane.setGlassPane( oldGlassPane );
133             component.requestFocus();
134             return;
135         }
136 
137         // else, slide to the right and continue
138         imageLabel.setLocation(
139             bounds.x + Math.max( bounds.width / 12, 1 ), bounds.y );
140         imageLabel.repaint();
141     }
142 }
143 
144 /*
145  * $Log$
146  * Revision 1.2  2006/02/18 23:19:05  cgruber
147  * Update imports and maven dependencies.
148  *
149  * Revision 1.1  2006/02/16 13:22:22  cgruber
150  * Check in all sources in eclipse-friendly maven-enabled packages.
151  *
152  * Revision 1.1.1.1  2000/12/21 15:51:18  mpowers
153  * Contributing wotonomy.
154  *
155  * Revision 1.2  2000/12/20 16:25:45  michael
156  * Added log to all files.
157  *
158  *
159  */
160