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 }