DCPanel.java revision 4d0eb50e691de4c20b1dd9976ad6839fede8a42d
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright (c) 1999-2000 by Sun Microsystems, Inc.
* All rights reserved.
*/
import java.awt.*;
import java.awt.event.*;
/**
* Creates a panel with two buttons (+ and - side by side on it). The
* panel registers a DCListener with it that gets notified whenever
* these butons are clicked. <bold>The buttons may also be kept continously
* pressed for faster increments/decrements.</bold>
* <para>
* On a single click of the button, the listener is notified to
* increment/decrement itself by a small amount. When the button is kept
* pressed the following notifications are sent out for larger
* increments/decrements. (It is up to the listener to decide the
* increment/decrement corresponding to large/small.) Moreover, these
* notifications will be sent out much faster if the button is kept
* pressed.
*/
// The panel waits for a period of BIG_SLEEP_TIME before the faster
// increments are sent out. They, in turn, are sent out after
// intervals of SMALL_SLEEP_TIME. Therfore, an instance of this class
// is associated with 2 timers - a longer one that starts off and then
// schedules the shorter one. The shorter one keeps scheduling itself
// every time it wakes up.
public class DCPanel extends Panel {
private Button plusButton;
private Button minusButton;
private DCListener listener = null;
private Timer bigTimer;
private Timer smallTimer;
private static int BIG_SLEEP_TIME = 1000;
private static int SMALL_SLEEP_TIME = 100;
private boolean incrementFlag;
public DCPanel() {
setLayout(new GridLayout(1, 2));
bigTimer = new BigTimer();
smallTimer = new SmallTimer();
bigTimer.start();
smallTimer.start();
plusButton = new DCButton("+");
minusButton = new DCButton("-");
add(plusButton);
add(minusButton);
}
/**
* Ensures that this component is not brought into focus by
* tabbing. This prevents the tab focus from moving in here instead
* of going to a text field.
* @return false always.
*/
public boolean isFocusable() {
return false;
}
/**
* Sets the listener for this tab.
* @param listener the DCListener that needs to be notified when the
* buttons on this panel are pressed.
* @return the old listener
*/
public DCListener setListener(DCListener listener) {
DCListener oldListener = this.listener;
this.listener = listener;
return oldListener;
}
/**
* Removes the listener when it no longer need to be notified.
* @return the old listener
*/
public DCListener removeListener() {
return setListener(null);
}
/**
* Kicks the times into action. Is called when a button is pressed.
*/
private void startAction() {
bigTimer.request();
}
/**
* Stops the timers. Is called when a button is released.
*/
private void stopAction() {
smallTimer.cancel();
bigTimer.cancel();
}
/**
* Notifies the listener about whether to increment or decrement and
* by how much.
* @param bigFlag true if the listener needs to increment/decrement
* by a large amount, false otherwise.
*/
private void informListener(boolean bigFlag) {
// System.out.println("DCPanel.informListener: " + bigFlag);
if (listener != null) {
if (bigFlag) {
// request a big change
if (incrementFlag)
listener.bigIncrement();
else
listener.bigDecrement();
} else {
// request a small change
if (incrementFlag)
listener.increment();
else
listener.decrement();
}
}
} // informListener
// ***********************************************
// I N N E R C L A S S E S F O L L O W
// ***********************************************
/**
* A timer class since java does not have one.
*/
private abstract class Timer extends Thread {
private boolean running = false;
/**
* Sleeps till the timer's services are requested using wait() and
* notify(). Then it does its task and goes back to sleep. And
* loops forever like this.
*/
public void run() {
while (true) {
try {
synchronized (this) {
running = false;
// Wait till the timer is required
wait();
running = true;
}
doTask();
} catch (InterruptedException e) {}
} // while loop
} // run method
protected void doTask() {} // bug in java workshop
/**
* Wakes up the timer.
*/
public synchronized void request() {
notify();
}
/**
* Cancels the timer if it is running.
*/
public void cancel() {
if (running) {
interrupt();
}
}
}// class Timer
/**
* The first stage of timer - is a longer timer. Wait to see if the
* user really wants to amek the increments/decrements go by fast.
*/
private class BigTimer extends Timer {
/**
* Sleep for the long amount of time. Then inform the listener
* to have a bigIncrement/bigDecrement. After that, your job is
* done, schedule the smaller (faster) timer from this point on.
*/
protected void doTask() {
try {
sleep(BIG_SLEEP_TIME);
informListener(true);
smallTimer.request();
} catch (InterruptedException e) {
informListener(false);
}
}
} // class BigTimer
/**
* The second stage of timers. This timer keeps rescheduling itself
* everytime it wakes up. In between this, it sends a notification
* to the listener to do a big Increment/Decrement.
*/
private class SmallTimer extends Timer {
protected void doTask() {
try {
// loop forever and keep rescheduling yourself
while (true) {
sleep(SMALL_SLEEP_TIME);
informListener(true);
}
} catch (InterruptedException e) {}
} // doTask method
} // class SmallTimer
/**
* A mouse listener to detect when a button has been
* pressed/released. One instance of this is bound to the plus
* button and the other instance to the minus button.
*/
private class DCMouseListener extends MouseAdapter {
private boolean plusOrMinus;
/**
* Constructor for DCMouseListener.
* @param plusOrMinus true if this is a listener for the plus
* button, false if it is for the minus button.
*/
public DCMouseListener(boolean plusOrMinus) {
this.plusOrMinus = plusOrMinus;
}
/**
* Kicks in when the mouse is pressed.
*/
public void mousePressed(MouseEvent e) {
incrementFlag = plusOrMinus;
DCPanel.this.startAction();
}
/**
* Kicks in when the mouse is released.
*/
public void mouseReleased(MouseEvent e) {
incrementFlag = plusOrMinus;
DCPanel.this.stopAction();
}
}
/**
* The button used by this DCPanel.
*/
private class DCButton extends Button {
public DCButton(String text) {
super(text);
if (text.equals("+"))
addMouseListener(new DCMouseListener(true));
else
addMouseListener(new DCMouseListener(false));
}
/**
* Make the button non-focus traversable so that it cannot be
* tabbed in to.
*/
public boolean isFocusable() {
return false;
}
} // DCButton
/**
* Test method for DCPanel class to see appearance.
*/
public static void main(String args[]) {
Frame f = new Frame("Testing DCPanel");
f.add(new DCPanel());
f.setBounds(new Rectangle(100, 100, 100, 100));
f.setVisible(true);
}
}