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 }