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