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, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * ident "%Z%%M% %I% %E% SMI"
24 *
25 * Copyright (c) 1999-2000 by Sun Microsystems, Inc.
26 * All rights reserved.
27 */
28
29 import java.awt.*;
30 import java.awt.event.*;
31
32 /**
33 * Creates a panel with two buttons (+ and - side by side on it). The
34 * panel registers a DCListener with it that gets notified whenever
35 * these butons are clicked. <bold>The buttons may also be kept continously
36 * pressed for faster increments/decrements.</bold>
37 * <para>
38 * On a single click of the button, the listener is notified to
39 * increment/decrement itself by a small amount. When the button is kept
40 * pressed the following notifications are sent out for larger
41 * increments/decrements. (It is up to the listener to decide the
42 * increment/decrement corresponding to large/small.) Moreover, these
43 * notifications will be sent out much faster if the button is kept
44 * pressed.
45 */
46
47 // The panel waits for a period of BIG_SLEEP_TIME before the faster
48 // increments are sent out. They, in turn, are sent out after
49 // intervals of SMALL_SLEEP_TIME. Therfore, an instance of this class
50 // is associated with 2 timers - a longer one that starts off and then
51 // schedules the shorter one. The shorter one keeps scheduling itself
52 // every time it wakes up.
53
54 public class DCPanel extends Panel {
55
56 private Button plusButton;
57 private Button minusButton;
58
59 private DCListener listener = null;
60
61 private Timer bigTimer;
62 private Timer smallTimer;
63
64 private static int BIG_SLEEP_TIME = 1000;
65 private static int SMALL_SLEEP_TIME = 100;
66
67 private boolean incrementFlag;
68
69 public DCPanel() {
70
71 setLayout(new GridLayout(1, 2));
72
73 bigTimer = new BigTimer();
74 smallTimer = new SmallTimer();
75
76 bigTimer.start();
77 smallTimer.start();
78
79 plusButton = new DCButton("+");
80 minusButton = new DCButton("-");
81
82 add(plusButton);
83 add(minusButton);
84
85 }
86
87 /**
88 * Ensures that this component is not brought into focus by
89 * tabbing. This prevents the tab focus from moving in here instead
90 * of going to a text field.
91 * @return false always.
92 */
93 public boolean isFocusTraversable() {
94 return false;
95 }
96
97 /**
98 * Sets the listener for this tab.
99 * @param listener the DCListener that needs to be notified when the
100 * buttons on this panel are pressed.
101 * @return the old listener
102 */
103 public DCListener setListener(DCListener listener) {
104 DCListener oldListener = this.listener;
105 this.listener = listener;
106 return oldListener;
107 }
108
109 /**
110 * Removes the listener when it no longer need to be notified.
111 * @return the old listener
112 */
113 public DCListener removeListener() {
114 return setListener(null);
115 }
116
117 /**
118 * Kicks the times into action. Is called when a button is pressed.
119 */
120 private void startAction() {
121 bigTimer.request();
122 }
123
124 /**
125 * Stops the timers. Is called when a button is released.
126 */
127 private void stopAction() {
128 smallTimer.cancel();
129 bigTimer.cancel();
130 }
131
132 /**
133 * Notifies the listener about whether to increment or decrement and
134 * by how much.
135 * @param bigFlag true if the listener needs to increment/decrement
136 * by a large amount, false otherwise.
137 */
138 private void informListener(boolean bigFlag) {
139 // System.out.println("DCPanel.informListener: " + bigFlag);
140
141 if (listener != null) {
142
143 if (bigFlag) {
144 // request a big change
145 if (incrementFlag)
146 listener.bigIncrement();
147 else
148 listener.bigDecrement();
149 } else {
150 // request a small change
151 if (incrementFlag)
152 listener.increment();
153 else
154 listener.decrement();
155 }
156
157 }
158
159 } // informListener
160
161
162 // ***********************************************
163 // I N N E R C L A S S E S F O L L O W
164 // ***********************************************
165
166 /**
167 * A timer class since java does not have one.
168 */
169 private abstract class Timer extends Thread {
170 private boolean running = false;
171
172 /**
173 * Sleeps till the timer's services are requested using wait() and
174 * notify(). Then it does its task and goes back to sleep. And
175 * loops forever like this.
176 */
177 public void run() {
178 while (true) {
179 try {
180 synchronized (this) {
181 running = false;
182 // Wait till the timer is required
183 wait();
184 running = true;
185 }
186 doTask();
187 } catch (InterruptedException e) {}
188 } // while loop
189 } // run method
190
191 protected void doTask() {} // bug in java workshop
192
193 /**
194 * Wakes up the timer.
195 */
196 public synchronized void request() {
197 notify();
198 }
199
200 /**
201 * Cancels the timer if it is running.
202 */
203 public void cancel() {
204 if (running) {
205 interrupt();
206 }
207 }
208
209 }// class Timer
210
211 /**
212 * The first stage of timer - is a longer timer. Wait to see if the
213 * user really wants to amek the increments/decrements go by fast.
214 */
215 private class BigTimer extends Timer {
216
217 /**
218 * Sleep for the long amount of time. Then inform the listener
219 * to have a bigIncrement/bigDecrement. After that, your job is
220 * done, schedule the smaller (faster) timer from this point on.
221 */
222 protected void doTask() {
223 try {
224 sleep(BIG_SLEEP_TIME);
225 informListener(true);
226 smallTimer.request();
227 } catch (InterruptedException e) {
228 informListener(false);
229 }
230 }
231
232 } // class BigTimer
233
234
235 /**
236 * The second stage of timers. This timer keeps rescheduling itself
237 * everytime it wakes up. In between this, it sends a notification
238 * to the listener to do a big Increment/Decrement.
239 */
240 private class SmallTimer extends Timer {
241
242 protected void doTask() {
243 try {
244 // loop forever and keep rescheduling yourself
245 while (true) {
246 sleep(SMALL_SLEEP_TIME);
247 informListener(true);
248 }
249 } catch (InterruptedException e) {}
250 } // doTask method
251
252 } // class SmallTimer
253
254 /**
255 * A mouse listener to detect when a button has been
256 * pressed/released. One instance of this is bound to the plus
257 * button and the other instance to the minus button.
258 */
259 private class DCMouseListener extends MouseAdapter {
260 private boolean plusOrMinus;
261
262 /**
263 * Constructor for DCMouseListener.
264 * @param plusOrMinus true if this is a listener for the plus
265 * button, false if it is for the minus button.
266 */
267 public DCMouseListener(boolean plusOrMinus) {
268 this.plusOrMinus = plusOrMinus;
269 }
270
271 /**
272 * Kicks in when the mouse is pressed.
273 */
274 public void mousePressed(MouseEvent e) {
275 incrementFlag = plusOrMinus;
276 DCPanel.this.startAction();
277 }
278
279 /**
280 * Kicks in when the mouse is released.
281 */
282 public void mouseReleased(MouseEvent e) {
283 incrementFlag = plusOrMinus;
284 DCPanel.this.stopAction();
285 }
286 }
287
288 /**
289 * The button used by this DCPanel.
290 */
291 private class DCButton extends Button {
292 public DCButton(String text) {
293 super(text);
294 if (text.equals("+"))
295 addMouseListener(new DCMouseListener(true));
296 else
297 addMouseListener(new DCMouseListener(false));
298 }
299
300 /**
301 * Make the button non-focus traversable so that it cannot be
302 * tabbed in to.
303 */
304 public boolean isFocusTraversable() {
305 return false;
306 }
307
308 } // DCButton
309
310
311 /**
312 * Test method for DCPanel class to see appearance.
313 */
314 public static void main(String args[]) {
315 Frame f = new Frame("Testing DCPanel");
316 f.add(new DCPanel());
317 f.setBounds(new Rectangle(100, 100, 100, 100));
318 f.setVisible(true);
319 }
320
321 }