/* * @(#)TristateButtonModel.java 5/20/2011 * * Copyright 2002 - 2011 JIDE Software Inc. All rights reserved. */ package com.jidesoft.swing; import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.InputEvent; /** * Model for TristateCheckBox. It introduces a mixed state to represent check box in the mixed selected state. * ActionEvent will be fired when the state is changed. */ public class TristateButtonModel extends JToggleButton.ToggleButtonModel { private static final long serialVersionUID = 9179129427948325126L; /** * Identifies the "mixed" bit in the bitmask, which indicates that the button is partial selected. */ public final static int MIXED = 1 << 7; public TristateButtonModel() { } public void setState(int state) { switch (state) { case TristateCheckBox.STATE_UNSELECTED: setSelected(false); break; case TristateCheckBox.STATE_SELECTED: setSelected(true); break; case TristateCheckBox.STATE_MIXED: setMixed(true); break; } } public int getState() { if (isMixed()) return TristateCheckBox.STATE_MIXED; else if (isSelected()) return TristateCheckBox.STATE_SELECTED; else return TristateCheckBox.STATE_UNSELECTED; } /** * We rotate between STATE_UNSELECTED, STATE_SELECTED and STATE_MIXED. Subclass can override this method to tell the * check box what next state is. Here is the default implementation. * <code><pre> * if (current == TristateCheckBox.STATE_UNSELECTED) { * return TristateCheckBox.STATE_SELECTED; * } * else if (current == TristateCheckBox.STATE_SELECTED) { * return TristateCheckBox.STATE_MIXED; * } * else if (current == TristateCheckBox.STATE_MIXED) { * return TristateCheckBox.STATE_UNSELECTED; * } * </code></pre> * * @param current the current state * @return the next state of the current state. */ protected int getNextState(int current) { if (current == TristateCheckBox.STATE_UNSELECTED) { return TristateCheckBox.STATE_SELECTED; } else if (current == TristateCheckBox.STATE_SELECTED) { return TristateCheckBox.STATE_MIXED; } else /*if (current == STATE_MIXED)*/ { return TristateCheckBox.STATE_UNSELECTED; } } @Override public void setPressed(boolean b) { if ((isPressed() == b) || !isEnabled()) { return; } if (!b && isArmed()) { updateState(); } if (b) { stateMask |= PRESSED; } else { stateMask &= ~PRESSED; } fireStateChanged(); if (!isPressed() && 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(); } fireActionPerformed( new ActionEvent(this, ActionEvent.ACTION_PERFORMED, getActionCommand(), EventQueue.getMostRecentEventTime(), modifiers)); } } /** * Updates the state when the mouse is clicked. The default implementation is * <pre><code> * setState(getNextState(getState())); * </code></pre> */ protected void updateState() { setState(getNextState(getState())); } @Override public void setSelected(boolean b) { boolean mixed = isMixed(); if (mixed) { stateMask &= ~MIXED; internalSetSelected(!isSelected()); } super.setSelected(b); } void internalSetSelected(boolean b) { if (b) { stateMask |= SELECTED; } else { stateMask &= ~SELECTED; } } public boolean isMixed() { return (stateMask & MIXED) != 0; } public void setMixed(boolean b) { if ((isMixed() == b)) { return; } if (b) { stateMask |= MIXED; stateMask |= SELECTED; // make it selected } else { stateMask &= ~MIXED; } fireStateChanged(); } }