blob: f37251c7574a229de44bbeb487dbfd4c4ecd0866 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2007, 2012 Oracle. 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:
* Oracle - initial API and implementation
******************************************************************************/
package org.eclipse.jpt.common.utility.internal.model.value.swing;
import org.eclipse.jpt.common.utility.Filter;
import org.eclipse.jpt.common.utility.internal.Transformer;
import org.eclipse.jpt.common.utility.internal.model.value.FilteringWritablePropertyValueModel;
import org.eclipse.jpt.common.utility.internal.model.value.TransformationWritablePropertyValueModel;
import org.eclipse.jpt.common.utility.model.value.ModifiablePropertyValueModel;
/**
* This {@link javax.swing.ButtonModel} can be used to keep a listener
* (e.g. a {@link javax.swing.JRadioButton}) in synch with a (typically shared)
* {@link org.eclipse.jpt.common.utility.model.value.PropertyValueModel}
* that holds one value out of a set of values.
* <p>
* <strong>NB:</strong> Do <em>not</em> use this model with a
* {@link javax.swing.ButtonGroup}, since the
* shared value holder and the wrappers built by this adapter will
* keep the appropriate radio button checked. Also, this allows
* us to uncheck all the radio buttons in a group when the shared
* value is <code>null</code>.
*/
public class RadioButtonModelAdapter
extends ToggleButtonModelAdapter
{
// ********** constructors **********
/**
* Constructor - the value holder is required.
*/
public RadioButtonModelAdapter(ModifiablePropertyValueModel<Object> valueHolder, Object buttonValue, boolean defaultValue) {
super(buildBooleanHolder(valueHolder, buttonValue), defaultValue);
}
/**
* Constructor - the value holder is required.
* The default value will be false.
*/
public RadioButtonModelAdapter(ModifiablePropertyValueModel<Object> valueHolder, Object buttonValue) {
super(buildBooleanHolder(valueHolder, buttonValue));
}
// ********** static methods **********
/**
* Build up a set of wrappers that will convert the
* specified value holder and button value to/from a boolean.
*
* If the value holder's value matches the button value,
* the wrapper will return true. Likewise, if the value holder's
* value is set to true, the wrapper will set the value holder's
* value to the button value.
*/
public static ModifiablePropertyValueModel<Boolean> buildBooleanHolder(ModifiablePropertyValueModel<Object> valueHolder, Object buttonValue) {
ModifiablePropertyValueModel<Object> filteringPVM = new FilteringWritablePropertyValueModel<Object>(valueHolder, Filter.Transparent.instance(), new SetRadioButtonFilter(buttonValue));
return new TransformationWritablePropertyValueModel<Object, Boolean>(filteringPVM, new RadioButtonTransformer(buttonValue), new ReverseRadioButtonTransformer(buttonValue));
}
// ********** overrides **********
/**
* The user cannot de-select a radio button - the user
* can only *select* a radio button. Only the model can
* cause a radio button to be de-selected. We use the
* ARMED flag to indicate whether we are being de-selected
* by the user.
*/
@Override
public void setSelected(boolean b) {
// do not allow the user to de-select a radio button
// radio buttons can
if ((b == false) && this.isArmed()) {
return;
}
super.setSelected(b);
}
// ********** filters **********
/**
* This filter will only pass through a new value to the wrapped
* value model when it matches the configured button value.
*/
public static class SetRadioButtonFilter
implements Filter<Object>
{
private Object buttonValue;
public SetRadioButtonFilter(Object buttonValue) {
super();
this.buttonValue = buttonValue;
}
/**
* pass through the value to the wrapped property value model
* *only* when it matches our button value
*/
public boolean accept(Object value) {
return (value != null) && value.equals(this.buttonValue);
}
}
// ********** transformers **********
/**
* This transformer will convert a value to {@link Boolean#TRUE}
* when it matches the configured button value.
*/
public static class RadioButtonTransformer
implements Transformer<Object, Boolean>
{
private Object buttonValue;
public RadioButtonTransformer(Object buttonValue) {
super();
this.buttonValue = buttonValue;
}
/**
* If the specified value matches the button value return {@link Boolean#TRUE},
* if it is some other value return {@link Boolean#FALSE};
* but if it is <code>null</code> simply pass it through because it will
* cause the button model's default value to be used
*/
public Boolean transform(Object value) {
return (value == null) ? null : Boolean.valueOf(value.equals(this.buttonValue));
}
}
/**
* This transformer will convert {@link Boolean#TRUE} to the configured
* button value and {@link Boolean#FALSE} to <code>null</code>.
*/
public static class ReverseRadioButtonTransformer
implements Transformer<Boolean, Object>
{
private Object buttonValue;
public ReverseRadioButtonTransformer(Object buttonValue) {
super();
this.buttonValue = buttonValue;
}
/**
* If the specified value is {@link Boolean#TRUE},
* pass through the our button value;
* otherwise pass through <code>null</code>.
*/
public Object transform (Boolean value) {
return (value.booleanValue()) ? this.buttonValue : null;
}
}
}