1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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
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();
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 {
131 timer.stop();
132 rootPane.setGlassPane( oldGlassPane );
133 component.requestFocus();
134 return;
135 }
136
137
138 imageLabel.setLocation(
139 bounds.x + Math.max( bounds.width / 12, 1 ), bounds.y );
140 imageLabel.repaint();
141 }
142 }
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160