/** * Copyright 2005 Bushe Enterprises, Inc., Hopkinton, MA, USA, www.bushe.com * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.bushe.swing.action; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.lang.ref.WeakReference; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import javax.swing.AbstractButton; import javax.swing.Action; /** * Synchronizes the selected states between an action and a buttons or * menu items created from the action. * <p> * Both the Action and the button are stored as WeakReferences so as to not * leak memory (e.g., create loitering objects). If either is garbage * collected, the listener is removed on the other. * <p> * The ActionSelectionSynchronizer adds itself as an ItemListener to the button * and adds itself as a PropertyChangeListener on the action. When the button's * fires an ItemChangedEvent, ActionSelectionSynchronizer sets the action's * ActionManager.SELECTED property value to the button's selected property value * (if different). Simlarly, when the action's ActionManager.SELECTED property * is set, then the ActionSelectionSynchronizer sets the selected state on the * button (if different), which should then propogate to all the other buttons. */ class ActionSelectionSynchronizer implements PropertyChangeListener, ItemListener { private WeakReference buttonRef; private WeakReference actionRef; /** * Creates a synchronizer that keeps the button and action in sync * @param button AbstractButton the button to keep in sync * @param action Action the action to keep in sync */ public ActionSelectionSynchronizer(AbstractButton button, Action action) { if (button != null) { this.buttonRef = new WeakReference(button); button.addItemListener(this); } if (action != null) { this.actionRef = new WeakReference(action); action.addPropertyChangeListener(this); } } /** * Invoked when an item has been selected or deselected by the user. * @param e ItemEvent */ public void itemStateChanged(ItemEvent e) { if (!checkValidity()) { return; } AbstractButton button = (AbstractButton) buttonRef.get(); Action action = (Action) actionRef.get(); boolean buttonSelected = button.isSelected(); Object value = action.getValue(ActionManager.SELECTED); boolean changeNeeded = true; if (value instanceof Boolean) { boolean isActionSelected = ((Boolean) value).booleanValue(); if (e.getStateChange() == ItemEvent.SELECTED && isActionSelected) { changeNeeded = false; } else if (e.getStateChange() == ItemEvent.DESELECTED && !isActionSelected) { changeNeeded = false; } } if (changeNeeded) { action.putValue(ActionManager.SELECTED, new Boolean(buttonSelected)); } } public void propertyChange(PropertyChangeEvent evt) { if (!checkValidity()) { return; } String propertyName = evt.getPropertyName(); if (propertyName.equals(ActionManager.SELECTED)) { if (!checkValidity()) { return; } AbstractButton button = (AbstractButton) buttonRef.get(); Action action = (Action) actionRef.get(); boolean buttonSelected = button.isSelected(); Object value = action.getValue(ActionManager.SELECTED); if (value instanceof Boolean) { boolean actionSelected = ((Boolean) value).booleanValue(); if (actionSelected != buttonSelected) { button.setSelected(actionSelected); } } } } private boolean checkValidity() { if (buttonRef == null || actionRef == null || buttonRef.get() == null || actionRef.get() == null) { //has been garbage collected, remove self from action. //Doubt this would ever happen normally, but could if called directly removeListeners(); return false; } else { return true; } } private void removeListeners() { Action action = (Action)actionRef.get(); if (action != null) { action.removePropertyChangeListener(this); } actionRef = null; AbstractButton button = (AbstractButton)buttonRef.get(); if (button != null) { button.removeItemListener(this); } buttonRef = null; } }