/*
* Copyright (C) 2010 Brockmann Consult GmbH (info@brockmann-consult.de)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 3 of the License, or (at your option)
* any later version.
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, see http://www.gnu.org/licenses/
*/
package com.bc.ceres.swing.binding;
import com.bc.ceres.binding.Property;
import com.bc.ceres.binding.PropertyContainer;
import com.bc.ceres.binding.PropertyDescriptor;
import com.bc.ceres.binding.ValidationException;
import com.bc.ceres.binding.ValueSet;
import com.bc.ceres.swing.binding.internal.TextComponentAdapter;
import org.junit.Before;
import org.junit.Test;
import javax.swing.ButtonGroup;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JFormattedTextField;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JRadioButton;
import javax.swing.JSpinner;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Arrays;
import static org.junit.Assert.*;
public class BindingContextTest {
private BindingContext bindingContextVB;
private PropertyContainer propertyContainerVB;
private PropertyContainer propertyContainerOB;
private BindingContext bindingContextOB;
private TestPojo pojo;
private Exception error;
private JComponent component;
@Before
public void setUp() throws Exception {
propertyContainerVB = PropertyContainer.createValueBacked(TestPojo.class);
propertyContainerVB.getDescriptor("valueSetBoundIntValue").setValueSet(new ValueSet(TestPojo.intValueSet));
bindingContextVB = new BindingContext(propertyContainerVB, null);
bindingContextVB.addProblemListener(new MyBindingProblemListener());
pojo = new TestPojo();
propertyContainerOB = PropertyContainer.createObjectBacked(pojo);
propertyContainerOB.getDescriptor("valueSetBoundIntValue").setValueSet(new ValueSet(TestPojo.intValueSet));
bindingContextOB = new BindingContext(propertyContainerOB, null);
bindingContextVB.addProblemListener(new MyBindingProblemListener());
error = null;
component = null;
}
private void clearError() {
error = null;
component = null;
}
@Test
public void testBindSpinner() throws ValidationException {
JSpinner spinner = new JSpinner();
Binding binding = bindingContextVB.bind("intValue", spinner);
assertNotNull(binding);
assertSame(spinner, getPrimaryComponent(binding));
assertNotNull(binding.getComponents());
assertEquals(1, binding.getComponents().length);
assertEquals("intValue", spinner.getName());
spinner.setValue(3);
assertEquals(3, (int)propertyContainerVB.getValue("intValue"));
propertyContainerVB.setValue("intValue", 76);
assertEquals(76, spinner.getValue());
}
@Test
public void testBindComboBox() throws ValidationException {
JComboBox<Integer> comboBox = new JComboBox<>(new Integer[]{1, 3, 7});
comboBox.setEditable(false);
Binding binding = bindingContextVB.bind("intValue", comboBox);
assertNotNull(binding);
assertSame(comboBox, getPrimaryComponent(binding));
assertNotNull(binding.getComponents());
assertEquals(1, binding.getComponents().length);
assertEquals("intValue", comboBox.getName());
comboBox.setSelectedItem(3);
assertEquals(3, comboBox.getSelectedItem());
assertEquals(3, binding.getPropertyValue());
propertyContainerVB.setValue("intValue", 1);
assertEquals(1, comboBox.getSelectedItem());
assertEquals(1, binding.getPropertyValue());
// "4" is not allowed, because it is not in the comboBox's model
comboBox.setSelectedItem(4);
assertEquals(1, comboBox.getSelectedItem());
assertEquals(1, binding.getPropertyValue());
comboBox.setEditable(true);
// Now "4" is allowed, because the comboBox is editable
comboBox.setSelectedItem(4);
assertEquals(4, comboBox.getSelectedItem());
assertEquals(4, binding.getPropertyValue());
propertyContainerVB.setValue("intValue", 5);
assertEquals(5, comboBox.getSelectedItem());
assertEquals(5, binding.getPropertyValue());
comboBox.setEditable(false);
final ValueSet valueSet = new ValueSet(new Object[]{10, 20});
final PropertyDescriptor descriptor = binding.getContext().getPropertySet().getDescriptor("intValue");
descriptor.setValueSet(valueSet);
assertEquals(2, comboBox.getModel().getSize());
assertEquals(10, comboBox.getModel().getElementAt(0).intValue());
assertEquals(20, comboBox.getModel().getElementAt(1).intValue());
assertEquals(10, comboBox.getSelectedItem());
assertEquals(10, binding.getPropertyValue());
assertNull(binding.getProblem());
}
@Test
public void testBindTextField() throws Exception {
JTextField textField = new JTextField();
Binding binding = bindingContextVB.bind("stringValue", textField);
Thread.sleep(1000); // previous value of 100 was not enough for building on my desktop rq-20140426
assertNotNull(binding);
assertSame(textField, getPrimaryComponent(binding));
assertNotNull(binding.getComponents());
assertEquals(1, binding.getComponents().length);
assertEquals("stringValue", textField.getName());
textField.setText("Bibo");
textField.postActionEvent();
assertEquals("Bibo", propertyContainerVB.getValue("stringValue"));
propertyContainerVB.setValue("stringValue", "Samson");
Thread.sleep(1000); // previous value of 100 was not enough for building on my desktop rq-20140426
assertEquals("Samson", textField.getText());
}
@Test
public void testBindTextField2() throws Exception {
JTextField textField = new JTextField();
Binding binding = bindingContextOB.bind("stringValue", textField);
assertNotNull(binding);
assertSame(textField, getPrimaryComponent(binding));
assertNotNull(binding.getComponents());
assertEquals(1, binding.getComponents().length);
assertEquals("stringValue", textField.getName());
textField.setText("Bibo");
textField.postActionEvent();
Thread.sleep(10);
assertEquals("Bibo", propertyContainerOB.getValue("stringValue"));
propertyContainerOB.setValue("stringValue", "Samson");
Thread.sleep(100);
assertEquals("Samson", pojo.stringValue);
assertEquals("Samson", textField.getText());
pojo.stringValue = "Oscar";
assertSame("Oscar", propertyContainerOB.getValue("stringValue"));
assertNotSame("Oscar", textField.getText()); // value change not detected by binding
}
@Test
public void testBindFormattedTextFieldToString() throws ValidationException {
JFormattedTextField textField = new JFormattedTextField();
Binding binding = bindingContextVB.bind("stringValue", textField);
assertNotNull(binding);
assertSame(textField, getPrimaryComponent(binding));
assertNotNull(binding.getComponents());
assertEquals(1, binding.getComponents().length);
assertEquals("stringValue", textField.getName());
textField.setValue("Bibo");
assertEquals("Bibo", propertyContainerVB.getValue("stringValue"));
propertyContainerVB.setValue("stringValue", "Samson");
assertEquals("Samson", textField.getValue());
}
@Test
public void testBindFormattedTextFieldToDouble() throws ValidationException {
JFormattedTextField textField = new JFormattedTextField();
Binding binding = bindingContextVB.bind("doubleValue", textField);
assertNotNull(binding);
assertSame(textField, getPrimaryComponent(binding));
assertNotNull(binding.getComponents());
assertEquals(1, binding.getComponents().length);
assertEquals("doubleValue", textField.getName());
textField.setValue(3.14);
assertEquals(3.14, (double)propertyContainerVB.getValue("doubleValue"), 1.0e-6);
propertyContainerVB.setValue("doubleValue", 2.71);
assertEquals(2.71, textField.getValue());
}
@Test
public void testBindTextArea() throws Exception {
JTextArea textArea = new JTextArea();
TextComponentAdapter textComponentAdapter = new TextComponentAdapter(textArea);
Binding binding = bindingContextVB.bind("stringValue", textComponentAdapter);
assertNotNull(binding);
assertSame(textArea, getPrimaryComponent(binding));
assertNotNull(binding.getComponents());
assertEquals(1, binding.getComponents().length);
assertEquals("stringValue", textArea.getName());
textArea.setText("Bibo");
textComponentAdapter.actionPerformed(null);
assertEquals("Bibo", propertyContainerVB.getValue("stringValue"));
propertyContainerVB.setValue("stringValue", "Samson");
Thread.sleep(100);
assertEquals("Samson", textArea.getText());
}
@Test
public void testBindCheckBox() throws ValidationException {
JCheckBox checkBox = new JCheckBox();
Binding binding = bindingContextVB.bind("booleanValue", checkBox);
assertNotNull(binding);
assertSame(checkBox, getPrimaryComponent(binding));
assertNotNull(binding.getComponents());
assertEquals(1, binding.getComponents().length);
assertEquals("booleanValue", checkBox.getName());
checkBox.doClick();
assertEquals(true, propertyContainerVB.getValue("booleanValue"));
propertyContainerVB.setValue("booleanValue", false);
assertEquals(false, checkBox.isSelected());
}
@Test
public void testBindRadioButton() throws ValidationException {
JRadioButton radioButton = new JRadioButton();
Binding binding = bindingContextVB.bind("booleanValue", radioButton);
assertNotNull(binding);
assertSame(radioButton, getPrimaryComponent(binding));
assertNotNull(binding.getComponents());
assertEquals(1, binding.getComponents().length);
assertEquals("booleanValue", radioButton.getName());
radioButton.doClick();
assertEquals(true, propertyContainerVB.getValue("booleanValue"));
propertyContainerVB.setValue("booleanValue", false);
assertEquals(false, radioButton.isSelected());
}
@Test
public void testBindButtonGroup() throws ValidationException {
JRadioButton radioButton1 = new JRadioButton();
JRadioButton radioButton2 = new JRadioButton();
JRadioButton radioButton3 = new JRadioButton();
ButtonGroup buttonGroup = new ButtonGroup();
buttonGroup.add(radioButton1);
buttonGroup.add(radioButton2);
buttonGroup.add(radioButton3);
Property m = propertyContainerVB.getProperty("valueSetBoundIntValue");
m.setValue(TestPojo.intValueSet[0]);
Binding binding = bindingContextVB.bind("valueSetBoundIntValue", buttonGroup);
assertNotNull(binding);
assertSame(radioButton1, getPrimaryComponent(binding));
assertNotNull(binding.getComponents());
assertEquals(3, binding.getComponents().length);
assertSame(radioButton1, binding.getComponents()[0]);
assertSame(radioButton2, binding.getComponents()[1]);
assertSame(radioButton3, binding.getComponents()[2]);
assertEquals(true, radioButton1.isSelected());
assertEquals(false, radioButton2.isSelected());
assertEquals(false, radioButton3.isSelected());
assertEquals(TestPojo.intValueSet[0], m.getValue());
radioButton3.doClick();
assertEquals(false, radioButton1.isSelected());
assertEquals(false, radioButton2.isSelected());
assertEquals(true, radioButton3.isSelected());
assertEquals(TestPojo.intValueSet[2], m.getValue());
radioButton2.doClick();
assertEquals(false, radioButton1.isSelected());
assertEquals(true, radioButton2.isSelected());
assertEquals(false, radioButton3.isSelected());
assertEquals(TestPojo.intValueSet[1], m.getValue());
m.setValue(TestPojo.intValueSet[0]);
assertEquals(true, radioButton1.isSelected());
assertEquals(false, radioButton2.isSelected());
assertEquals(false, radioButton3.isSelected());
assertEquals(TestPojo.intValueSet[0], m.getValue());
m.setValue(TestPojo.intValueSet[2]);
assertEquals(false, radioButton1.isSelected());
assertEquals(false, radioButton2.isSelected());
assertEquals(true, radioButton3.isSelected());
assertEquals(TestPojo.intValueSet[2], m.getValue());
m.setValue(TestPojo.intValueSet[1]);
assertEquals(false, radioButton1.isSelected());
assertEquals(true, radioButton2.isSelected());
assertEquals(false, radioButton3.isSelected());
assertEquals(TestPojo.intValueSet[1], m.getValue());
}
@Test
public void testBindListSelection() throws ValidationException {
JList<Integer> list = new JList<>(new Integer[]{3, 4, 5, 6, 7});
Binding binding = bindingContextVB.bind("listValue", list, true);
assertNotNull(binding);
assertSame(list, getPrimaryComponent(binding));
assertNotNull(binding.getComponents());
assertEquals(1, binding.getComponents().length);
assertEquals("listValue", list.getName());
list.setSelectedIndex(2);
assertTrue(Arrays.equals(new int[]{5}, (int[]) propertyContainerVB.getValue("listValue")));
propertyContainerVB.setValue("listValue", new int[]{6});
assertEquals(6, list.getSelectedValue().intValue());
}
@Test
public void testAdjustComponents() throws Exception {
JTextField textField1 = new JTextField();
JTextField textField2 = new JTextField();
JCheckBox checkBox = new JCheckBox();
pojo.booleanValue = true;
pojo.doubleValue = 3.2;
pojo.stringValue = "ABC";
bindingContextOB.bind("booleanValue", checkBox);
bindingContextOB.bind("doubleValue", textField1);
bindingContextOB.bind("stringValue", textField2);
Thread.sleep(100);
assertEquals(true, checkBox.isSelected());
assertEquals("3.2", textField1.getText());
assertEquals("ABC", textField2.getText());
pojo.booleanValue = false;
pojo.doubleValue = 1.5;
pojo.stringValue = "XYZ";
assertEquals(true, checkBox.isSelected());
assertEquals("3.2", textField1.getText());
assertEquals("ABC", textField2.getText());
bindingContextOB.adjustComponents();
Thread.sleep(100);
assertEquals(false, checkBox.isSelected());
assertEquals("1.5", textField1.getText());
assertEquals("XYZ", textField2.getText());
}
@Test
public void testSecondaryComponent() throws Exception {
JTextField textField = new JTextField();
Binding binding = bindingContextVB.bind("stringValue", textField);
JLabel label = new JLabel("myLabel");
binding.addComponent(label);
JComponent[] components = binding.getComponents();
assertNotNull(components);
assertEquals(2, components.length);
assertSame(getPrimaryComponent(binding), components[0]);
assertSame(label, components[1]);
}
@Test
public void testProblemManagement() {
JTextField intTextField = new JTextField();
JTextField stringTextField = new JTextField();
final MyChangeListener listener = new MyChangeListener();
clearError();
bindingContextVB.addProblemListener(listener);
bindingContextVB.addPropertyChangeListener(listener);
bindingContextVB.bind("intValue", intTextField);
bindingContextVB.bind("stringValue", stringTextField);
assertEquals("", listener.trace);
assertEquals(false, bindingContextVB.hasProblems());
assertNotNull(bindingContextVB.getProblems());
assertEquals(0, bindingContextVB.getProblems().length);
assertNull(error);
assertNull(component);
clearError();
bindingContextVB.getBinding("intValue").setPropertyValue("a");
assertEquals("P;", listener.trace);
assertEquals(true, bindingContextVB.hasProblems());
assertNotNull(bindingContextVB.getProblems());
assertEquals(1, bindingContextVB.getProblems().length);
assertNotNull(error);
assertSame(intTextField, component);
clearError();
bindingContextVB.getBinding("stringValue").setPropertyValue(5);
assertEquals("P;P;", listener.trace);
assertEquals(true, bindingContextVB.hasProblems());
assertNotNull(bindingContextVB.getProblems());
assertEquals(2, bindingContextVB.getProblems().length);
assertNotNull(error);
assertSame(stringTextField, component);
clearError();
bindingContextVB.getBinding("intValue").setPropertyValue(5);
assertEquals("P;P;V;C;", listener.trace);
assertEquals(true, bindingContextVB.hasProblems());
assertNotNull(bindingContextVB.getProblems());
assertEquals(1, bindingContextVB.getProblems().length);
assertNull(error);
assertNull(component);
clearError();
bindingContextVB.getBinding("stringValue").setPropertyValue("a");
assertEquals("P;P;V;C;V;C;", listener.trace);
assertEquals(false, bindingContextVB.hasProblems());
assertNotNull(bindingContextVB.getProblems());
assertEquals(0, bindingContextVB.getProblems().length);
assertNull(error);
assertNull(component);
}
private static JComponent getPrimaryComponent(Binding binding) {
return binding.getComponents()[0];
}
private static class TestPojo {
boolean booleanValue;
@SuppressWarnings("UnusedDeclaration")
int intValue;
double doubleValue;
String stringValue;
@SuppressWarnings("UnusedDeclaration")
int[] listValue;
@SuppressWarnings("UnusedDeclaration")
int valueSetBoundIntValue;
static Integer[] intValueSet = new Integer[]{101, 102, 103};
}
private static class MyChangeListener implements BindingProblemListener, PropertyChangeListener {
String trace = "";
@Override
public void problemReported(BindingProblem newProblem, BindingProblem oldProblem) {
trace += "P;";
}
@Override
public void problemCleared(BindingProblem oldProblem) {
trace += "C;";
}
@Override
public void propertyChange(PropertyChangeEvent evt) {
trace += "V;";
}
}
private class MyBindingProblemListener implements BindingProblemListener {
@Override
public void problemReported(BindingProblem newProblem, BindingProblem oldProblem) {
error = newProblem.getCause();
component = newProblem.getBinding().getComponents()[0];
}
@Override
public void problemCleared(BindingProblem oldProblem) {
error = null;
component = null;
}
}
}