/*******************************************************************************
* Copyright (c) 2007, Angelo Zerr 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:
* Angelo Zerr <angelo.zerr@gmail.com> - Initial API and implementation
*******************************************************************************/
package org.eclipse.ufacekit.ui.swing.databinding.internal.swing;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JComboBox;
import javax.swing.text.JTextComponent;
import org.eclipse.core.databinding.observable.Diffs;
import org.eclipse.core.databinding.observable.Realm;
import org.eclipse.core.runtime.Assert;
/**
* ISwingObservableValue implementation to observe value of JComboBox.
*
* @since 1.0
*/
public class ComboObservableValue extends AbstractSwingObservableValue {
private final JComboBox combo;
private JTextComponent textEditor;
private final String attribute;
private boolean updating = false;
private Object currentValue;
private KeyListener keyListener;
private ActionListener modifyListener;
/**
* @param combo
* @param attribute
*/
public ComboObservableValue(JComboBox combo, String attribute) {
super(combo);
this.combo = combo;
this.attribute = attribute;
init();
}
/**
* @param realm
* @param combo
* @param attribute
*/
public ComboObservableValue(Realm realm, JComboBox combo, String attribute) {
super(realm, combo);
this.combo = combo;
this.attribute = attribute;
init();
}
private void init() {
if (attribute.equals(SwingProperties.SELECTION) || attribute.equals(SwingProperties.TEXT)) {
this.currentValue = combo.getSelectedItem();
// Add Selected changed listener
modifyListener = new ActionListener() {
public void actionPerformed(ActionEvent actionevent) {
if (!updating) {
Object oldValue = currentValue;
currentValue = ComboObservableValue.this.combo.getSelectedItem();
notifyIfChanged(oldValue, currentValue);
}
}
};
combo.addActionListener(modifyListener);
Component editor = combo.getEditor().getEditorComponent();
if (editor instanceof JTextComponent)
textEditor = (JTextComponent) editor;
else
textEditor = null;
// Add key listener (for editable combo)
if (textEditor != null) {
keyListener = new KeyAdapter() {
public void keyReleased(KeyEvent e) {
if (!updating && combo.isEditable()) {
Object oldValue = currentValue;
currentValue = getComboValue();
notifyIfChanged(oldValue, currentValue);
}
}
};
textEditor.addKeyListener(keyListener);
}
} else
throw new IllegalArgumentException();
}
public void doSetValue(final Object value) {
Object oldValue = combo.getSelectedItem();
try {
updating = true;
combo.setSelectedItem(value);
combo.updateUI();
} finally {
updating = false;
}
notifyIfChanged(oldValue, value);
}
public Object doGetValue() {
if (attribute.equals(SwingProperties.TEXT))
return getComboValue();
Assert.isTrue(attribute.equals(SwingProperties.SELECTION), "unexpected attribute: " + attribute); //$NON-NLS-1$
// The problem with a ccombo, is that it changes the text and
// fires before it update its selection index
return getComboValue();
}
public Object getValueType() {
Assert.isTrue(attribute.equals(SwingProperties.TEXT) || attribute.equals(SwingProperties.SELECTION), "unexpected attribute: " + attribute); //$NON-NLS-1$
if( attribute.equals(SwingProperties.TEXT) ) {
return String.class;
}
return null;
}
/**
* @return attribute being observed
*/
public String getAttribute() {
return attribute;
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.core.databinding.observable.value.AbstractObservableValue
* #dispose()
*/
public synchronized void dispose() {
super.dispose();
if (modifyListener != null) {
combo.removeActionListener(modifyListener);
}
if (keyListener != null) {
combo.removeKeyListener(keyListener);
}
}
private void notifyIfChanged(Object oldValue, Object newValue) {
if ((oldValue == null && newValue != null) || (oldValue != null && !oldValue.equals(newValue))) {
fireValueChange(Diffs.createValueDiff(oldValue, newValue));
}
}
private Object getComboValue() {
Object value = combo.getSelectedItem();
if (combo.isEditable() && textEditor != null) {
if (value instanceof Integer) {
try {
return new Integer(textEditor.getText());
} catch (Throwable e) {
// FIXME : the user type String value into editable
// JComboBox and the setter is mapped with Integer.
// How can do notify that?
}
}
if (value instanceof Long) {
try {
return new Long(textEditor.getText());
} catch (Throwable e) {
// FIXME : the user type String value into editable
// JComboBox and the setter is mapped with Integer.
// How can do notify that?
}
}
return textEditor.getText();
}
return combo.getSelectedItem();
}
}