1 /* |
|
2 * CDDL HEADER START |
|
3 * |
|
4 * The contents of this file are subject to the terms of the |
|
5 * Common Development and Distribution License (the "License"). |
|
6 * You may not use this file except in compliance with the License. |
|
7 * |
|
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE |
|
9 * or http://www.opensolaris.org/os/licensing. |
|
10 * See the License for the specific language governing permissions |
|
11 * and limitations under the License. |
|
12 * |
|
13 * When distributing Covered Code, include this CDDL HEADER in each |
|
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. |
|
15 * If applicable, add the following below this CDDL HEADER, with the |
|
16 * fields enclosed by brackets "[]" replaced with your own identifying |
|
17 * information: Portions Copyright [yyyy] [name of copyright owner] |
|
18 * |
|
19 * CDDL HEADER END |
|
20 */ |
|
21 |
|
22 /* |
|
23 * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved. |
|
24 */ |
|
25 |
|
26 package com.oracle.solaris.vp.panel.swing.view; |
|
27 |
|
28 import java.awt.*; |
|
29 import java.awt.image.BufferedImage; |
|
30 import javax.swing.*; |
|
31 import org.jdesktop.animation.timing.*; |
|
32 import com.oracle.solaris.vp.panel.common.control.*; |
|
33 import com.oracle.solaris.vp.util.swing.GraphicsUtil; |
|
34 import com.oracle.solaris.vp.util.swing.glass.ImageCaptureGlassPane; |
|
35 |
|
36 public class ScrollingTransitionHandler |
|
37 implements NavigationListener, TimingTarget { |
|
38 |
|
39 // |
|
40 // Enums |
|
41 // |
|
42 |
|
43 public enum Direction { |
|
44 NORTH, SOUTH, EAST, WEST |
|
45 } |
|
46 |
|
47 // |
|
48 // Inner classes |
|
49 // |
|
50 |
|
51 @SuppressWarnings({"serial"}) |
|
52 public static class ImageScrollGlassPane extends ImageCaptureGlassPane { |
|
53 // |
|
54 // Instance data |
|
55 // |
|
56 |
|
57 private Direction direction; |
|
58 private JViewport viewport = new JViewport(); |
|
59 private JLabel beforeLabel = new JLabel(); |
|
60 private JLabel afterLabel = new JLabel(); |
|
61 private JPanel view = new JPanel(new BorderLayout()); |
|
62 |
|
63 // |
|
64 // Constructors |
|
65 // |
|
66 |
|
67 public ImageScrollGlassPane(Direction direction) { |
|
68 this.direction = direction; |
|
69 |
|
70 switch (direction) { |
|
71 case NORTH: |
|
72 view.add(beforeLabel, BorderLayout.NORTH); |
|
73 view.add(afterLabel, BorderLayout.SOUTH); |
|
74 break; |
|
75 |
|
76 case SOUTH: |
|
77 view.add(beforeLabel, BorderLayout.SOUTH); |
|
78 view.add(afterLabel, BorderLayout.NORTH); |
|
79 break; |
|
80 |
|
81 case WEST: |
|
82 view.add(beforeLabel, BorderLayout.WEST); |
|
83 view.add(afterLabel, BorderLayout.EAST); |
|
84 break; |
|
85 |
|
86 case EAST: |
|
87 view.add(beforeLabel, BorderLayout.EAST); |
|
88 view.add(afterLabel, BorderLayout.WEST); |
|
89 break; |
|
90 } |
|
91 |
|
92 viewport.setView(view); |
|
93 scroll(0); |
|
94 |
|
95 JLabel label = getLabel(); |
|
96 label.setLayout(null); |
|
97 label.add(viewport); |
|
98 } |
|
99 |
|
100 // |
|
101 // ImageScrollGlassPane methods |
|
102 // |
|
103 |
|
104 public void scroll(float fraction) { |
|
105 if (fraction < 0) { |
|
106 fraction = 0f; |
|
107 } else if (fraction > 1) { |
|
108 fraction = 1f; |
|
109 } |
|
110 |
|
111 Rectangle r = viewport.getViewRect(); |
|
112 |
|
113 switch (direction) { |
|
114 case NORTH: |
|
115 r.y = (int)(fraction * r.height); |
|
116 break; |
|
117 |
|
118 case SOUTH: |
|
119 r.y = (int)((1f - fraction) * r.height); |
|
120 break; |
|
121 |
|
122 case WEST: |
|
123 r.x = (int)(fraction * r.width); |
|
124 break; |
|
125 |
|
126 case EAST: |
|
127 r.x = (int)((1f - fraction) * r.width); |
|
128 break; |
|
129 } |
|
130 |
|
131 view.scrollRectToVisible(r); |
|
132 } |
|
133 |
|
134 public void setAfterImage(BufferedImage image) { |
|
135 afterLabel.setIcon(image == null ? null : new ImageIcon(image)); |
|
136 } |
|
137 |
|
138 public void setBeforeImage(BufferedImage image) { |
|
139 beforeLabel.setIcon(image == null ? null : new ImageIcon(image)); |
|
140 } |
|
141 |
|
142 public void setViewBounds(Rectangle rectangle) { |
|
143 viewport.setBounds(rectangle); |
|
144 } |
|
145 }; |
|
146 |
|
147 // |
|
148 // Instance data |
|
149 // |
|
150 |
|
151 private JComponent component; |
|
152 private ImageScrollGlassPane glass; |
|
153 private Animator animator = new Animator(500, this); |
|
154 private boolean running; |
|
155 |
|
156 // |
|
157 // Constructors |
|
158 // |
|
159 |
|
160 public ScrollingTransitionHandler( |
|
161 JComponent component, Direction direction) { |
|
162 |
|
163 this.component = component; |
|
164 |
|
165 glass = new ImageScrollGlassPane(direction); |
|
166 } |
|
167 |
|
168 // |
|
169 // NavigationListener methods |
|
170 // |
|
171 |
|
172 @Override |
|
173 public void navigationStarted(NavigationStartEvent event) { |
|
174 if (!running) { |
|
175 running = true; |
|
176 Rectangle bounds = SwingUtilities.convertRectangle( |
|
177 component.getParent(), component.getBounds(), |
|
178 component.getRootPane()); |
|
179 |
|
180 glass.setViewBounds(bounds); |
|
181 glass.setBeforeImage(GraphicsUtil.paintToImage(component)); |
|
182 |
|
183 // Hide component, then take a snapshot of the resulting root pane |
|
184 component.setVisible(false); |
|
185 component.getRootPane().setGlassPane(glass); |
|
186 |
|
187 // Display the snapshot in the glass pane, then reshow the component |
|
188 glass.setVisible(true); |
|
189 component.setVisible(true); |
|
190 } |
|
191 } |
|
192 |
|
193 @Override |
|
194 public void navigationStopped(NavigationStopEvent event) { |
|
195 // We are presumably on the event queue thread. So, let navigation |
|
196 // complete so that the new component is shown before we try to paint it |
|
197 // to an image. Once done, start the animation. |
|
198 EventQueue.invokeLater( |
|
199 new Runnable() { |
|
200 @Override |
|
201 public void run() { |
|
202 glass.setAfterImage(GraphicsUtil.paintToImage(component)); |
|
203 glass.scroll(0); |
|
204 animator.start(); |
|
205 } |
|
206 }); |
|
207 running = false; |
|
208 } |
|
209 |
|
210 // |
|
211 // TimingTarget methods |
|
212 // |
|
213 |
|
214 @Override |
|
215 public void begin() { |
|
216 // No implementation here -- setup should occur before the animator is |
|
217 // started since the clock is ticking at this point. A design flaw in |
|
218 // the timing framework? Perhaps. |
|
219 } |
|
220 |
|
221 @Override |
|
222 public void end() { |
|
223 glass.setVisible(false); |
|
224 glass.setBeforeImage(null); |
|
225 glass.setAfterImage(null); |
|
226 } |
|
227 |
|
228 @Override |
|
229 public void repeat() { |
|
230 } |
|
231 |
|
232 @Override |
|
233 public void timingEvent(float fraction) { |
|
234 glass.scroll(fraction); |
|
235 } |
|
236 |
|
237 // |
|
238 // ScrollingTransitionHandler methods |
|
239 // |
|
240 |
|
241 public Animator getAnimator() { |
|
242 return animator; |
|
243 } |
|
244 } |
|