blob: 2639bbe8e375ff675bc595101738d8d3fbd7dcd8 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2005 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
******************************************************************************/
package org.eclipse.jface.commands;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.eclipse.core.commands.IState;
import org.eclipse.core.commands.IStateListener;
import org.eclipse.jface.menus.IMenuStateIds;
/**
* <p>
* A piece of boolean state grouped with other boolean states. Of these states,
* only one may have a value of {@link Boolean#TRUE} at any given point in time.
* The values of all other states must be {@link Boolean#FALSE}.
* </p>
* <p>
* If this state is registered using {@link IMenuStateIds#STYLE}, then it will
* control the presentation of the command if displayed in the menus, tool bars
* or status line.
* </p>
* <p>
* Clients may instantiate or extend this interface.
* </p>
* <p>
* <strong>EXPERIMENTAL</strong>. This class or interface has been added as
* part of a work in progress. There is a guarantee neither that this API will
* work nor that it will remain the same. Please do not use this API without
* consulting with the Platform/UI team.
* </p>
*
* @since 3.2
*/
public class RadioState extends ToggleState {
/**
* The manager of radio groups within the application. This ensures that
* only one member of a radio group is active at any one time, and tracks
* group memberships.
*/
private static final class RadioStateManager {
/**
* A group of radio states with the same identifier.
*/
private static final class RadioGroup implements IStateListener {
/**
* The active state. If there is no active state, then this value is
* <code>null</code>.
*/
private RadioState active = null;
/**
* The current members in this group. If there are no members, then
* this value is <code>nlistenerull</code>.
*/
private Set members = null;
/**
* Activates a memeber. This checks to see if there are any other
* active members. If there are, they are deactivated.
*
* @param state
* The state that should become active; must not be
* <code>null</code>.
*/
private final void activateMember(final RadioState state) {
if (active != state) {
active.setValue(Boolean.FALSE);
}
active = state;
}
/**
* Adds a member to this radio group. If the state being added is
* active, then it replaces the currently active group memeber as
* the active state.
*
* @param state
* The state to add; must not be <code>null</code>.
*/
private final void addMember(final RadioState state) {
if (members == null) {
members = new HashSet(5);
}
members.add(state);
state.addListener(this);
final Object value = state.getValue();
if (value instanceof Boolean) {
if (((Boolean) value).booleanValue()) {
activateMember(state);
}
}
}
public final void handleStateChange(final IState state,
final Object oldValue) {
final Object newValue = state.getValue();
if (newValue instanceof Boolean) {
if (((Boolean) newValue).booleanValue()) {
activateMember((RadioState) state);
}
}
}
/**
* Removes a member from this radio group. If the state was the
* active state, then there will be no active state.
*
* @param state
* The state to remove; must not be <code>null</code>.
*/
private final void removeMember(final RadioState state) {
state.removeListener(this);
if (active == state) {
active = null;
}
if (members == null) {
return;
}
members.remove(state);
}
}
/**
* The map of radio states indexed by identifier (<code>String</code>).
* The radio states is either a single <code>RadioState</code>
* instance or a <code>Collection</code> of <code>RadioState</code>
* instances.
*/
private static Map radioStatesById = null;
/**
* Activates a particular state within a given group.
*
* @param identifier
* The identifier of the group to which the state belongs;
* must not be <code>null</code>.
* @param state
* The state to activate; must not be <code>null</code>.
*/
private static final void activateGroup(final String identifier,
final RadioState state) {
if (radioStatesById == null) {
return;
}
final Object currentValue = radioStatesById.get(identifier);
if (currentValue instanceof RadioGroup) {
final RadioGroup radioGroup = (RadioGroup) currentValue;
radioGroup.activateMember(state);
}
}
/**
* Registers a piece of state with the radio manager.
*
* @param identifier
* The identifier of the radio group; must not be
* <code>null</code>.
* @param state
* The state to register; must not be <code>null</code>.
*/
private static final void registerState(final String identifier,
final RadioState state) {
if (radioStatesById == null) {
radioStatesById = new HashMap();
}
final Object currentValue = radioStatesById.get(identifier);
final RadioGroup radioGroup;
if (currentValue instanceof RadioGroup) {
radioGroup = (RadioGroup) currentValue;
} else {
radioGroup = new RadioGroup();
}
radioGroup.addMember(state);
}
/**
* Unregisters a piece of state from the radio manager.
*
* @param identifier
* The identifier of the radio group; must not be
* <code>null</code>.
* @param state
* The state to unregister; must not be <code>null</code>.
*/
private static final void unregisterState(final String identifier,
final RadioState state) {
if (radioStatesById == null) {
return;
}
final Object currentValue = radioStatesById.get(identifier);
if (currentValue instanceof RadioGroup) {
final RadioGroup radioGroup = (RadioGroup) currentValue;
radioGroup.removeMember(state);
}
}
}
/**
* The identifier of the radio group to which this state belongs. This value
* may be <code>null</code> if this state doesn't really belong to a group
* (yet).
*/
private String radioGroupIdentifier = null;
/**
* Unregisters this state from the manager, which detaches the listeners.
*/
public void dispose() {
setRadioGroupIdentifier(null);
}
/**
* Sets the identifier of the radio group for this piece of state. If the
* identifier is cleared, then the state is unregistered.
*
* @param identifier
* The identifier of the radio group for this state; may be
* <code>null</code> if the identifier is being cleared.
*
*/
public final void setRadioGroupIdentifier(final String identifier) {
if (identifier == null) {
RadioStateManager.unregisterState(radioGroupIdentifier, this);
radioGroupIdentifier = null;
} else {
radioGroupIdentifier = identifier;
RadioStateManager.registerState(identifier, this);
}
}
/**
* Sets the value for this object. This notifies the radio state manager of
* the change.
*
* @param value
* The new value; should be a <code>Boolean</code>.
*/
public void setValue(final Object value) {
if (!(value instanceof Boolean)) {
throw new IllegalArgumentException(
"RadioState takes a Boolean as a value"); //$NON-NLS-1$
}
if (((Boolean) value).booleanValue() && (radioGroupIdentifier != null)) {
RadioStateManager.activateGroup(radioGroupIdentifier, this);
}
super.setValue(value);
}
}