diff options
author | Matthew Hall | 2008-12-16 18:13:23 +0000 |
---|---|---|
committer | Matthew Hall | 2008-12-16 18:13:23 +0000 |
commit | e0a40df5db5e99336aa8bc767173160e8e26455b (patch) | |
tree | 56b3ff476e799feece1acd7f7ac7b16b0e9e5b9c /bundles/org.eclipse.core.databinding.observable/src/org/eclipse/core/databinding/observable/value | |
parent | 4ea4afd7c711806c85b8e80d37ea3af54f36907b (diff) | |
download | eclipse.platform.ui-e0a40df5db5e99336aa8bc767173160e8e26455b.tar.gz eclipse.platform.ui-e0a40df5db5e99336aa8bc767173160e8e26455b.tar.xz eclipse.platform.ui-e0a40df5db5e99336aa8bc767173160e8e26455b.zip |
FIXED - bug 249992: [Databinding] No radio button support with single property in JFace Databinding
https://bugs.eclipse.org/bugs/show_bug.cgi?id=249992
Diffstat (limited to 'bundles/org.eclipse.core.databinding.observable/src/org/eclipse/core/databinding/observable/value')
-rw-r--r-- | bundles/org.eclipse.core.databinding.observable/src/org/eclipse/core/databinding/observable/value/SelectObservableValue.java | 208 |
1 files changed, 208 insertions, 0 deletions
diff --git a/bundles/org.eclipse.core.databinding.observable/src/org/eclipse/core/databinding/observable/value/SelectObservableValue.java b/bundles/org.eclipse.core.databinding.observable/src/org/eclipse/core/databinding/observable/value/SelectObservableValue.java new file mode 100644 index 00000000000..8ea9a65dea3 --- /dev/null +++ b/bundles/org.eclipse.core.databinding.observable/src/org/eclipse/core/databinding/observable/value/SelectObservableValue.java @@ -0,0 +1,208 @@ +/******************************************************************************* + * Copyright (c) 2008 Matthew Hall 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: + * Matthew Hall - initial API and implementation (bug 249992) + ******************************************************************************/ + +package org.eclipse.core.databinding.observable.value; + +import org.eclipse.core.databinding.observable.Diffs; +import org.eclipse.core.databinding.observable.Realm; +import org.eclipse.core.internal.databinding.Util; + +/** + * An observable value which behaves similarly to the <select> and + * <option> HTML tags. A SelectObservableValue has a number of options + * added to it via the {@link #addOption(Object, IObservableValue)} method. The + * value of the SelectObservableValue is the value of whichever option's + * observable has a value of Boolean.TRUE, or null if none of the observable's + * values are Boolean.TRUE. + * + * @noextend This class is not intended to be subclassed by clients. + * + * @since 1.2 + */ +public class SelectObservableValue extends AbstractObservableValue { + private class Option { + private final Object value; + private final IObservableValue observable; + + public Option(Object value, IObservableValue observable) { + this.value = value; + this.observable = observable; + } + } + + private final Object valueType; + + private Option[] options; + private int selectionIndex = -1; // n/a while not hasListeners() + + private boolean updating = false; + + private IValueChangeListener listener = new IValueChangeListener() { + public void handleValueChange(ValueChangeEvent event) { + if (!updating) { + IObservableValue observable = event.getObservableValue(); + if (Boolean.TRUE.equals(observable.getValue())) { + notifyIfChanged(indexOfObservable(observable)); + } + } + } + }; + + /** + * Constructs a SelectObservableValue on the default realm. + */ + public SelectObservableValue() { + this(Realm.getDefault(), null); + } + + /** + * Constructs a SelectObservableValue on the specified realm. + * + * @param realm + * the realm + */ + public SelectObservableValue(Realm realm) { + this(realm, null); + } + + /** + * Constructs a SelectObservableValue on the default realm, with the given + * value type. + * + * @param valueType + * the value type + */ + public SelectObservableValue(Object valueType) { + this(Realm.getDefault(), valueType); + } + + /** + * Constructs a SelectObservableValue on the given realm, with the given + * value type. + * + * @param realm + * the realm + * @param valueType + * the value type + */ + public SelectObservableValue(Realm realm, Object valueType) { + super(realm); + this.valueType = valueType; + this.options = new Option[0]; + } + + protected void firstListenerAdded() { + super.firstListenerAdded(); + selectionIndex = indexOfValue(getLiveValue()); + for (int i = 0; i < options.length; i++) { + options[i].observable.addValueChangeListener(listener); + } + } + + protected void lastListenerRemoved() { + for (int i = 0; i < options.length; i++) { + options[i].observable.removeValueChangeListener(listener); + } + selectionIndex = -1; + super.lastListenerRemoved(); + } + + public Object getValueType() { + return valueType; + } + + private void notifyIfChanged(int index) { + if (hasListeners() && selectionIndex != index) { + Object oldValue = valueAtIndex(selectionIndex); + Object newValue = valueAtIndex(index); + selectionIndex = index; + fireValueChange(Diffs.createValueDiff(oldValue, newValue)); + } + } + + /** + * Adds an option to this SelectObservableValue. If the observable contains + * Boolean.TRUE + * + * @param value + * The value associated with the provided observable + * @param observable + * an observable of value type Boolean.class or Boolean.TYPE + */ + public void addOption(Object value, IObservableValue observable) { + checkRealm(); + + Option option = new Option(value, observable); + addOption(option); + + if (hasListeners()) { + observable.addValueChangeListener(listener); + if (Boolean.TRUE.equals(observable.getValue())) { + notifyIfChanged(indexOfObservable(observable)); + } + } + } + + private void addOption(Option option) { + Option[] newOptions = new Option[options.length + 1]; + System.arraycopy(options, 0, newOptions, 0, options.length); + newOptions[options.length] = option; + options = newOptions; + } + + protected Object doGetValue() { + return hasListeners() ? valueAtIndex(selectionIndex) : getLiveValue(); + } + + private Object getLiveValue() { + for (int i = 0; i < options.length; i++) { + if (Boolean.TRUE.equals(options[i].observable.getValue())) + return options[i].value; + } + return null; + } + + protected void doSetValue(Object value) { + int index = indexOfValue(value); + + try { + updating = true; + for (int i = 0; i < options.length; i++) { + options[i].observable.setValue(i == index ? Boolean.TRUE + : Boolean.FALSE); + } + } finally { + updating = false; + } + + notifyIfChanged(index); + } + + private Object valueAtIndex(int index) { + if (index == -1) + return null; + return options[index].value; + } + + private int indexOfValue(Object value) { + for (int i = 0; i < options.length; i++) + if (Util.equals(options[i].value, value)) + return i; + return -1; + } + + private int indexOfObservable(IObservableValue observable) { + for (int i = 0; i < options.length; i++) + if (options[i].observable == observable) + return i; + return -1; + } +} |