001package jmri.util.com.sun;
002
003import java.awt.event.ActionEvent;
004import javax.swing.JToggleButton;
005
006// import org.slf4j.Logger;
007// import org.slf4j.LoggerFactory;
008
009/**
010 * ToggleOrPressButtonModel handles the storage and maintenance of the
011 * state of the button.
012 * <p>
013 * Changes the state of the function
014 * depending on the locking state of the button.
015 * <p>
016 * Modified from http://developer.classpath.org/doc/javax/swing/JToggleButton-source.html
017 * <p>
018 * Updates the button state depending if is lockable.
019 * @since 4.19.6
020 * @author Steve Young
021 *
022 */
023public class ToggleOrPressButtonModel extends javax.swing.JToggleButton.ToggleButtonModel {
024
025    private final JToggleButton _button;
026    private boolean _isLockable;
027
028    /**
029     * Create a new ToggleOrPressButtonModel.
030     * @param button the button being controlled.
031     * @param startLockable true to start as a toggle button,
032     *                      false to start as a click on / release off button.
033     */
034    public ToggleOrPressButtonModel(JToggleButton button, boolean startLockable){
035        super();
036        _button = button;
037        _isLockable = startLockable;
038    }
039
040    /**
041     * Set button lockable state.
042     * <p>
043     * Lockable on - Normal Toggle button.
044     * Lockable off - push on, release off.
045     * <p>
046     * If button is set unlocked when pressed, is de-pressed.
047     * @param lockable true for lockable, else false.
048     */
049    public void setLockable(boolean lockable) {
050        _isLockable = lockable;
051        if (!_isLockable && isSelected()){
052            stateMask = ( stateMask | PRESSED ); // mark button pressed without creating event
053            setPressed(false); // depress button creating event.
054        }
055    }
056
057    /**
058     * Get if Button is Lockable.
059     * @return true if normal toggle button, false if push on release off.
060     */
061    public boolean getLockable() {
062        return _isLockable;
063    }
064
065    /**
066     * An external change has happened so we update.
067     * @param p new Selected state.
068     */
069    public void updateSelected(boolean p){
070        setSelected(p);
071    }
072
073    /**
074     * Sets the pressed state of the button.
075     * <p>
076     * The selected state
077     * of the button also changes following the button being pressed.
078     *
079     * @param p true if the button is pressed down.
080     */
081    @Override
082    public void setPressed(boolean p) {
083        // cannot change PRESSED state unless button is enabled
084        if (! isEnabled())
085          return;
086
087        // if this call does not represent a CHANGE in state, then return
088        if ((p && isPressed()) || (!p && !isPressed()))
089          return;
090
091        stateMask = ( p ? ( stateMask | PRESSED) : (stateMask & (~PRESSED)));
092
093        // The JDK first fires events in the following order:
094        // 1. ChangeEvent for selected
095        // 2. ChangeEvent for pressed
096        // 3. ActionEvent
097
098        if (_isLockable) { // if we were armed, we flip the selected state.
099            if (!p ) { // only change state on button release
100                setSelected (! isSelected()); // flip the selected state.
101                _button.setSelected(isSelected());
102            }
103        }
104        else {
105            setSelected(p);
106            _button.setSelected(isSelected());
107        }
108
109        // notify interested ChangeListeners
110        fireStateChanged();
111        fireActionPerformed(new ActionEvent(this,
112            ActionEvent.ACTION_PERFORMED, actionCommand));
113
114    }
115
116    // private final static Logger log = LoggerFactory.getLogger(ToggleOrPressButtonModel.class);
117
118}