/*
* Jajuk
* Copyright (C) The Jajuk Team
* http://jajuk.info
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*/
package org.jajuk.ui.widgets;
import java.awt.AWTEvent;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.InputEvent;
import javax.swing.Action;
import javax.swing.DefaultButtonModel;
import javax.swing.Icon;
import javax.swing.UIManager;
import javax.swing.plaf.ButtonUI;
/**
* A specialized button, firing successive <code>ActionEvent</code>'s as long
* as the button remains pressed.
*/
public class JPressButton extends JajukButton {
/** Generated serialVersionUID. */
private static final long serialVersionUID = 1L;
/** The Constant DEFAULT_INTERVAL. */
private static final long DEFAULT_INTERVAL = 250;
/** The interval between successive fireActionPerformed() calls. */
private long actionInterval;
/** Re-use the L&F component of a normal <code>JButton</code>. */
private static final String UI_CLASS_ID = "ButtonUI";
/**
* Creates a button with no set text or icon and a default action interval.
*/
public JPressButton() {
this(null, null, DEFAULT_INTERVAL);
}
/**
* Creates a button with no set text or icon.
*
* @param actionInterval the interval between 2 successive actionperformed calls.
*/
public JPressButton(long actionInterval) {
this(null, null, actionInterval);
}
/**
* Creates a button with an icon and a default action interval.
*
* @param icon the Icon image to display on the button
*/
public JPressButton(Icon icon) {
this(null, icon, DEFAULT_INTERVAL);
}
/**
* Creates a button with an icon.
*
* @param icon the Icon image to display on the button
* @param actionInterval
*/
public JPressButton(Icon icon, long actionInterval) {
this(null, icon, actionInterval);
}
/**
* Creates a button with text and a default action interval.
*
* @param text the text of the button
*/
public JPressButton(String text) {
this(text, null, DEFAULT_INTERVAL);
}
/**
* Creates a button with text.
*
* @param text the text of the button
* @param actionInterval
*/
public JPressButton(String text, long actionInterval) {
this(text, null, actionInterval);
}
/**
* Creates a button where properties are taken from the <code>Action</code>
* supplied. The default action interval is used.
*
* @param a the <code>Action</code> used to specify the new button
*/
public JPressButton(Action a) {
this(a, DEFAULT_INTERVAL);
setAction(a);
}
/**
* Creates a button where properties are taken from the <code>Action</code>
* supplied.
*
* @param a the <code>Action</code> used to specify the new button
* @param actionInterval
*/
public JPressButton(Action a, long actionInterval) {
this();
this.actionInterval = actionInterval;
setAction(a);
}
/**
* Creates a button with initial text and an icon and a default action
* interval.
*
* @param text the text of the button
* @param icon the Icon image to display on the button
*/
public JPressButton(String text, Icon icon) {
this(text, icon, DEFAULT_INTERVAL);
}
/**
* Creates a button with initial text and an icon.
*
* @param text the text of the button
* @param icon the Icon image to display on the button
* @param actionInterval
*/
public JPressButton(String text, Icon icon, long actionInterval) {
this.actionInterval = actionInterval;
// Create the model
setModel(new PressButtonModel(this));
// initialize
init(text, icon);
// Set border
setRolloverEnabled(true);
}
/**
* Gets the action interval.
*
* @return the used interval between two successive calls to actionPerformed.
*/
public long getActionInterval() {
return actionInterval;
}
/**
* Sets the action interval.
*
* @param actionInterval sets the interval between two successive calls to actionPerformed.
*/
public void setActionInterval(long actionInterval) {
this.actionInterval = actionInterval;
}
/**
* Resets the UI property to a value from the current look and feel.
*
* @see javax.swing.JComponent#updateUI
*/
@Override
public void updateUI() {
setUI((ButtonUI) UIManager.getUI(this));
}
/**
* Returns a string that specifies the name of the L&F class that renders this
* component.
*
* @return the string "ButtonUI"
*
* @see javax.swing.JComponent#getUIClassID
* @see javax.swing.UIDefaults#getUI
*/
@Override
public String getUIClassID() {
return UI_CLASS_ID;
}
/**
* Button model for the <code>PressButton</code>. The model launches a
* thread when the button remains pressed. The ends whenever the button
* releases.
*
* @see ActionThread
*/
public static class PressButtonModel extends DefaultButtonModel {
/** Generated serialVersionUID. */
private static final long serialVersionUID = 1L;
private ActionThread thread;
private final JPressButton button;
/**
* Instantiates a new press button model.
*
* @param button
*/
public PressButtonModel(JPressButton button) {
this.button = button;
}
/* (non-Javadoc)
* @see javax.swing.DefaultButtonModel#setPressed(boolean)
*/
@Override
public void setPressed(boolean b) {
if ((isPressed() == b) || !isEnabled()) {
return;
}
if (b) {
stateMask |= PRESSED;
} else {
stateMask &= ~PRESSED;
}
if (isArmed()) {
int modifiers = 0;
AWTEvent currentEvent = EventQueue.getCurrentEvent();
if (currentEvent instanceof InputEvent) {
modifiers = ((InputEvent) currentEvent).getModifiers();
} else if (currentEvent instanceof ActionEvent) {
modifiers = ((ActionEvent) currentEvent).getModifiers();
}
if (isPressed() && thread == null) {
thread = button.new ActionThread(new ActionEvent(button, ActionEvent.ACTION_PERFORMED,
getActionCommand(), EventQueue.getMostRecentEventTime(), modifiers));
thread.start();
} else if (!isPressed() && thread != null) {
thread.setActive(false);
thread.interrupt();
thread = null;
}
}
fireStateChanged();
}
}
/**
* Thread extension. While alive, fires an <code>actionPerformed</code>
* event at a certain interval.
*/
private class ActionThread extends Thread {
private final ActionEvent evt;
private boolean active = true;
private final long interval;
/**
* Instantiates a new action thread.
*
* @param evt
*/
public ActionThread(ActionEvent evt) {
this(evt, DEFAULT_INTERVAL);
}
/**
* Instantiates a new action thread.
*
* @param evt
* @param interval
*/
public ActionThread(ActionEvent evt, long interval) {
super("JPressButton Action Thread");
this.interval = interval;
this.evt = evt;
}
/**
* Sets the active.
*
* @param active the new active
*/
public void setActive(boolean active) {
this.active = active;
}
/* (non-Javadoc)
* @see java.lang.Thread#run()
*/
@Override
public void run() {
while (active) {
try {
fireActionPerformed(evt);
Thread.sleep(interval);
} catch (InterruptedException e) {
// Ignore
}
}
}
}
}