Released patch (plus one additional test) for Bug 177770 [DataBinding] Mutators not implemented on JavaBeansObservableList
diff --git a/bundles/org.eclipse.core.databinding.beans/src/org/eclipse/core/databinding/beans/BeansObservables.java b/bundles/org.eclipse.core.databinding.beans/src/org/eclipse/core/databinding/beans/BeansObservables.java
index 6749099..35ee4c5 100644
--- a/bundles/org.eclipse.core.databinding.beans/src/org/eclipse/core/databinding/beans/BeansObservables.java
+++ b/bundles/org.eclipse.core.databinding.beans/src/org/eclipse/core/databinding/beans/BeansObservables.java
@@ -35,9 +35,8 @@
import org.eclipse.core.internal.databinding.internal.beans.JavaBeanObservableValue;
/**
- * A factory for creating observable objects of Java
- * objects that conform to the <a
- * href="http://java.sun.com/products/javabeans/docs/spec.html">JavaBean
+ * A factory for creating observable objects of Java objects that conform to the
+ * <a href="http://java.sun.com/products/javabeans/docs/spec.html">JavaBean
* specification</a> for bound properties.
*
* @since 1.1
@@ -150,7 +149,8 @@
/**
* Returns an observable list in the given realm tracking the
- * collection-typed named property of the given bean object
+ * collection-typed named property of the given bean object. The returned
+ * list is mutable.
*
* @param realm
* the realm
@@ -160,7 +160,7 @@
* the name of the collection-typed property
* @return an observable list tracking the collection-typed named property
* of the given bean object
- *
+ * @see #observeList(Realm, Object, String, Class)
*/
public static IObservableList observeList(Realm realm, Object bean,
String propertyName) {
@@ -169,7 +169,12 @@
/**
* Returns an observable list in the given realm tracking the
- * collection-typed named property of the given bean object
+ * collection-typed named property of the given bean object. The returned
+ * list is mutable. When an item is added or removed the setter is invoked
+ * for the list on the parent bean to provide notification to other
+ * listeners via <code>PropertyChangeEvents</code>. This is done to
+ * provide the same behavior as is expected from arrays as specified in the
+ * bean spec in section 7.2.
*
* @param realm
* the realm
diff --git a/bundles/org.eclipse.core.databinding.beans/src/org/eclipse/core/internal/databinding/internal/beans/JavaBeanObservableList.java b/bundles/org.eclipse.core.databinding.beans/src/org/eclipse/core/internal/databinding/internal/beans/JavaBeanObservableList.java
index f752b17..b510f3a 100644
--- a/bundles/org.eclipse.core.databinding.beans/src/org/eclipse/core/internal/databinding/internal/beans/JavaBeanObservableList.java
+++ b/bundles/org.eclipse.core.databinding.beans/src/org/eclipse/core/internal/databinding/internal/beans/JavaBeanObservableList.java
@@ -23,12 +23,12 @@
import java.util.Iterator;
import java.util.List;
+import org.eclipse.core.databinding.BindingException;
import org.eclipse.core.databinding.beans.IBeanObservable;
import org.eclipse.core.databinding.observable.Diffs;
import org.eclipse.core.databinding.observable.Realm;
import org.eclipse.core.databinding.observable.list.ListDiffEntry;
import org.eclipse.core.databinding.observable.list.ObservableList;
-import org.eclipse.core.runtime.Assert;
/**
* @since 1.0
@@ -87,6 +87,7 @@
}
private Object primGetValues() {
+ Exception ex = null;
try {
Method readMethod = descriptor.getReadMethod();
if (!readMethod.isAccessible()) {
@@ -94,11 +95,13 @@
}
return readMethod.invoke(object, new Object[0]);
} catch (IllegalArgumentException e) {
+ ex = e;
} catch (IllegalAccessException e) {
+ ex = e;
} catch (InvocationTargetException e) {
+ ex = e;
}
- Assert.isTrue(false, "Could not read collection values"); //$NON-NLS-1$
- return null;
+ throw new BindingException("Could not read collection values", ex); //$NON-NLS-1$
}
private Object[] getValues() {
@@ -142,17 +145,22 @@
}
private void primSetValues(Object newValue) {
+ Exception ex = null;
try {
Method writeMethod = descriptor.getWriteMethod();
if (!writeMethod.isAccessible()) {
writeMethod.setAccessible(true);
}
writeMethod.invoke(object, new Object[] { newValue });
+ return;
} catch (IllegalArgumentException e) {
+ ex = e;
} catch (IllegalAccessException e) {
+ ex = e;
} catch (InvocationTargetException e) {
+ ex = e;
}
- Assert.isTrue(false, "Could not write collection values"); //$NON-NLS-1$
+ throw new BindingException("Could not write collection values", ex); //$NON-NLS-1$
}
public Object set(int index, Object element) {
@@ -223,7 +231,7 @@
int i = 0;
for (Iterator it = c.iterator(); it.hasNext();) {
Object o = it.next();
- entries[i] = Diffs.createListDiffEntry(index++, true, o);
+ entries[i++] = Diffs.createListDiffEntry(index++, true, o);
}
fireListChange(Diffs.createListDiff(entries));
return result;
@@ -244,7 +252,7 @@
int i = 0;
for (Iterator it = c.iterator(); it.hasNext();) {
Object o = it.next();
- entries[i] = Diffs.createListDiffEntry(index++, true, o);
+ entries[i++] = Diffs.createListDiffEntry(index++, true, o);
}
fireListChange(Diffs.createListDiff(entries));
return result;
diff --git a/tests/org.eclipse.jface.tests.databinding/src/org/eclipse/core/tests/databinding/beans/BeansObservablesTest.java b/tests/org.eclipse.jface.tests.databinding/src/org/eclipse/core/tests/databinding/beans/BeansObservablesTest.java
index ba2ac42..5a2ed8c 100644
--- a/tests/org.eclipse.jface.tests.databinding/src/org/eclipse/core/tests/databinding/beans/BeansObservablesTest.java
+++ b/tests/org.eclipse.jface.tests.databinding/src/org/eclipse/core/tests/databinding/beans/BeansObservablesTest.java
@@ -46,8 +46,8 @@
public void testObserveListArrayInferredElementType() throws Exception {
IObservableList list = BeansObservables.observeList(Realm.getDefault(),
- model, "listArray", null);
- assertEquals("element type", elementType, list.getElementType());
+ model, "list", null);
+ assertEquals("element type", Object.class, list.getElementType());
}
public void testObserveListNonInferredElementType() throws Exception {
diff --git a/tests/org.eclipse.jface.tests.databinding/src/org/eclipse/core/tests/internal/databinding/internal/beans/Bean.java b/tests/org.eclipse.jface.tests.databinding/src/org/eclipse/core/tests/internal/databinding/internal/beans/Bean.java
index f05543d..da8baab 100644
--- a/tests/org.eclipse.jface.tests.databinding/src/org/eclipse/core/tests/internal/databinding/internal/beans/Bean.java
+++ b/tests/org.eclipse.jface.tests.databinding/src/org/eclipse/core/tests/internal/databinding/internal/beans/Bean.java
@@ -24,7 +24,7 @@
public class Bean {
/* package */PropertyChangeSupport changeSupport = new PropertyChangeSupport(this);
private String value;
- private List list;
+ private Object[] list = new Object[0];
private Set set;
public Bean() {
@@ -35,7 +35,7 @@
}
public Bean(List list) {
- this.list = list;
+ this.list = (Bean[]) list.toArray(new Bean[list.size()]);
}
public Bean(Set set) {
@@ -58,16 +58,12 @@
changeSupport.firePropertyChange("value", this.value, this.value = value);
}
- public List getList() {
+ public Object[] getList() {
return list;
}
- public void setList(List list) {
- changeSupport.firePropertyChange("list", this.list, this.list = list);
- }
-
- public Bean[] getListArray() {
- return (Bean[]) list.toArray(new Bean[list.size()]);
+ public void setList(Object[] elements) {
+ changeSupport.firePropertyChange("list", this.list, this.list = elements);
}
public Set getSet() {
diff --git a/tests/org.eclipse.jface.tests.databinding/src/org/eclipse/core/tests/internal/databinding/internal/beans/BeanObservableListDecoratorTest.java b/tests/org.eclipse.jface.tests.databinding/src/org/eclipse/core/tests/internal/databinding/internal/beans/BeanObservableListDecoratorTest.java
index f5aa9a5..6b86e0f 100644
--- a/tests/org.eclipse.jface.tests.databinding/src/org/eclipse/core/tests/internal/databinding/internal/beans/BeanObservableListDecoratorTest.java
+++ b/tests/org.eclipse.jface.tests.databinding/src/org/eclipse/core/tests/internal/databinding/internal/beans/BeanObservableListDecoratorTest.java
@@ -38,7 +38,7 @@
Bean bean = new Bean();
propertyDescriptor = new PropertyDescriptor(
- "list", Bean.class);
+ "list", Bean.class,"getList","setList");
observableList = new JavaBeanObservableList(
SWTObservables.getRealm(Display.getDefault()), bean,
propertyDescriptor, Bean.class);
diff --git a/tests/org.eclipse.jface.tests.databinding/src/org/eclipse/core/tests/internal/databinding/internal/beans/JavaBeanObservableArrayBasedListTest.java b/tests/org.eclipse.jface.tests.databinding/src/org/eclipse/core/tests/internal/databinding/internal/beans/JavaBeanObservableArrayBasedListTest.java
new file mode 100644
index 0000000..2122a63
--- /dev/null
+++ b/tests/org.eclipse.jface.tests.databinding/src/org/eclipse/core/tests/internal/databinding/internal/beans/JavaBeanObservableArrayBasedListTest.java
@@ -0,0 +1,467 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Brad Reynolds 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:
+ * Brad Reynolds - initial API and implementation
+ ******************************************************************************/
+
+package org.eclipse.core.tests.internal.databinding.internal.beans;
+
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyDescriptor;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
+import org.eclipse.core.databinding.observable.list.ListChangeEvent;
+import org.eclipse.core.databinding.observable.list.ListDiffEntry;
+import org.eclipse.core.internal.databinding.internal.beans.JavaBeanObservableList;
+import org.eclipse.jface.databinding.swt.SWTObservables;
+import org.eclipse.jface.tests.databinding.AbstractDefaultRealmTestCase;
+import org.eclipse.jface.tests.databinding.EventTrackers.ListChangeEventTracker;
+import org.eclipse.swt.widgets.Display;
+
+/**
+ * @since 1.1
+ */
+public class JavaBeanObservableArrayBasedListTest extends AbstractDefaultRealmTestCase {
+ private JavaBeanObservableList list;
+
+ private PropertyDescriptor propertyDescriptor;
+
+ private Bean bean;
+
+ private String propertyName;
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see junit.framework.TestCase#setUp()
+ */
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ propertyName = "list";
+ propertyDescriptor = new PropertyDescriptor(propertyName, Bean.class);
+ bean = new Bean(new ArrayList());
+
+ list = new JavaBeanObservableList(SWTObservables.getRealm(Display
+ .getDefault()), bean, propertyDescriptor, Bean.class);
+ }
+
+ public void testGetObserved() throws Exception {
+ assertEquals(bean, list.getObserved());
+ }
+
+ public void testGetPropertyDescriptor() throws Exception {
+ assertEquals(propertyDescriptor, list.getPropertyDescriptor());
+ }
+
+ public void testRegistersListenerAfterFirstListenerIsAdded()
+ throws Exception {
+ assertFalse(bean.changeSupport.hasListeners(propertyName));
+ list.addListChangeListener(new ListChangeEventTracker());
+ assertTrue(bean.changeSupport.hasListeners(propertyName));
+ }
+
+ public void testRemovesListenerAfterLastListenerIsRemoved()
+ throws Exception {
+ ListChangeEventTracker listener = new ListChangeEventTracker();
+ list.addListChangeListener(listener);
+
+ assertTrue(bean.changeSupport.hasListeners(propertyName));
+ list.removeListChangeListener(listener);
+ assertFalse(bean.changeSupport.hasListeners(propertyName));
+ }
+
+ public void testFiresListChangeEvents() throws Exception {
+ ListChangeEventTracker listener = new ListChangeEventTracker();
+ list.addListChangeListener(listener);
+
+ assertEquals(0, listener.count);
+ bean.setList(new Bean[] { new Bean() });
+ assertEquals(1, listener.count);
+ }
+
+ public void testAddAddsElement() throws Exception {
+ int count = list.size();
+ String element = "1";
+
+ assertEquals(0, count);
+ list.add(element);
+ assertEquals(count + 1, list.size());
+ assertEquals(element, bean.getList()[count]);
+ }
+
+ public void testAddListChangeEvent() throws Exception {
+ ListChangeEventTracker listener = new ListChangeEventTracker();
+ list.addListChangeListener(listener);
+
+ assertEquals(0, listener.count);
+ String element = "1";
+
+ list.add(element);
+
+ assertEquals(1, listener.count);
+ ListChangeEvent event = listener.event;
+
+ assertEquals(list, event.getObservableList());
+ assertEntry(event.diff.getDifferences()[0], true, 0, element);
+ }
+
+ public void testAddFiresPropertyChangeEvent() throws Exception {
+ assertPropertyChangeEvent(bean, new Runnable() {
+ public void run() {
+ list.add("0");
+ }
+ });
+ }
+
+ public void testAddAtIndex() throws Exception {
+ String element = "1";
+ assertEquals(0, list.size());
+
+ list.add(0, element);
+ assertEquals(element, bean.getList()[0]);
+ }
+
+ public void testAddAtIndexListChangeEvent() throws Exception {
+ String element = "1";
+ assertEquals(0, list.size());
+
+ ListChangeEventTracker listener = new ListChangeEventTracker();
+ list.addListChangeListener(listener);
+
+ list.add(0, element);
+
+ ListChangeEvent event = listener.event;
+ assertEntry(event.diff.getDifferences()[0], true, 0, element);
+ }
+
+ public void testAddAtIndexPropertyChangeEvent() throws Exception {
+ assertPropertyChangeEvent(bean, new Runnable() {
+ public void run() {
+ list.add(0, "0");
+ }
+ });
+ }
+
+ public void testRemove() throws Exception {
+ String element = "1";
+ list.add(element);
+
+ assertEquals(1, bean.getList().length);
+ list.remove(element);
+ assertEquals(0, bean.getList().length);
+ }
+
+ public void testRemoveListChangeEvent() throws Exception {
+ String element = "1";
+ list.add(element);
+
+ assertEquals(1, list.size());
+ ListChangeEventTracker listener = new ListChangeEventTracker();
+ list.addListChangeListener(listener);
+
+ list.remove(element);
+
+ assertEquals(1, listener.count);
+ ListChangeEvent event = listener.event;
+ assertEquals(list, event.getObservableList());
+ assertEntry(event.diff.getDifferences()[0], false, 0, element);
+ }
+
+ public void testRemovePropertyChangeEvent() throws Exception {
+ list.add("0");
+
+ assertPropertyChangeEvent(bean, new Runnable() {
+ public void run() {
+ list.remove("0");
+ }
+ });
+ }
+
+ public void testRemoveAtIndex() throws Exception {
+ String element = "1";
+ list.add(element);
+
+ assertEquals(element, bean.getList()[0]);
+
+ list.remove(0);
+ assertEquals(0, bean.getList().length);
+ }
+
+ public void testRemoveAtIndexListChangeEvent() throws Exception {
+ String element = "1";
+ list.add(element);
+
+ assertEquals(1, list.size());
+ ListChangeEventTracker listener = new ListChangeEventTracker();
+ list.addListChangeListener(listener);
+
+ list.remove(0);
+
+ assertEquals(1, listener.count);
+ ListChangeEvent event = listener.event;
+ assertEquals(list, event.getObservableList());
+ assertEntry(event.diff.getDifferences()[0], false, 0, element);
+ }
+
+ public void testRemoveAtIndexPropertyChangeEvent() throws Exception {
+ list.add("0");
+ assertPropertyChangeEvent(bean, new Runnable() {
+ public void run() {
+ list.remove(0);
+ }
+ });
+ }
+
+ public void testAddAll() throws Exception {
+ Collection elements = Arrays.asList(new String[] { "1", "2" });
+ assertEquals(0, list.size());
+
+ list.addAll(elements);
+
+ assertEquals(2, bean.getList().length);
+ }
+
+ public void testAddAllListChangEvent() throws Exception {
+ List elements = Arrays.asList(new String[] { "1", "2" });
+ assertEquals(0, list.size());
+
+ ListChangeEventTracker listener = new ListChangeEventTracker();
+ list.addListChangeListener(listener);
+ assertEquals(0, listener.count);
+
+ list.addAll(elements);
+
+ assertEquals(1, listener.count);
+ ListChangeEvent event = listener.event;
+ assertEquals(list, event.getObservableList());
+
+ assertEntry(event.diff.getDifferences()[0], true, 0, elements.get(0));
+ assertEntry(event.diff.getDifferences()[1], true, 1, elements.get(1));
+ }
+
+ public void testAddAllPropertyChangeEvent() throws Exception {
+ assertPropertyChangeEvent(bean, new Runnable() {
+ public void run() {
+ list.addAll(Arrays.asList(new String[] {"0", "1"}));
+ }
+ });
+ }
+
+ public void testAddAllAtIndex() throws Exception {
+ List elements = Arrays.asList(new String[] { "1", "2" });
+ list.addAll(elements);
+
+ assertEquals(2, list.size());
+
+ list.addAll(2, elements);
+
+ assertEquals(4, bean.getList().length);
+ assertEquals(elements.get(0), bean.getList()[0]);
+ assertEquals(elements.get(1), bean.getList()[1]);
+ }
+
+ public void testAddAllAtIndexListChangeEvent() throws Exception {
+ List elements = Arrays.asList(new String[] { "1", "2" });
+ list.addAll(elements);
+
+ ListChangeEventTracker listener = new ListChangeEventTracker();
+ list.addListChangeListener(listener);
+
+ assertEquals(0, listener.count);
+
+ list.addAll(2, elements);
+
+ assertEquals(1, listener.count);
+ ListChangeEvent event = listener.event;
+ assertEquals(list, event.getObservableList());
+ assertEntry(event.diff.getDifferences()[0], true, 2, elements.get(0));
+ assertEntry(event.diff.getDifferences()[1], true, 3, elements.get(1));
+ }
+
+ public void testAddAllAtIndexPropertyChangeEvent() throws Exception {
+ assertPropertyChangeEvent(bean, new Runnable() {
+ public void run() {
+ list.addAll(0, Arrays.asList(new String[] {"1", "2"}));
+ }
+ });
+ }
+
+ public void testRemoveAll() throws Exception {
+ List elements = Arrays.asList(new String[] { "1", "2" });
+ list.addAll(elements);
+ list.addAll(elements);
+
+ assertEquals(4, bean.getList().length);
+ list.removeAll(elements);
+
+ assertEquals(2, bean.getList().length);
+ assertEquals(elements.get(0), bean.getList()[0]);
+ assertEquals(elements.get(1), bean.getList()[1]);
+ }
+
+ public void testRemoveAllListChangeEvent() throws Exception {
+ List elements = Arrays.asList(new String[] { "1", "2" });
+ list.addAll(elements);
+ list.addAll(elements);
+
+ ListChangeEventTracker listener = new ListChangeEventTracker();
+ list.addListChangeListener(listener);
+
+ assertEquals(0, listener.count);
+ list.removeAll(elements);
+
+ ListChangeEvent event = listener.event;
+ assertEquals(list, event.getObservableList());
+ assertEntry(event.diff.getDifferences()[0], false, 0, elements.get(0));
+ assertEntry(event.diff.getDifferences()[1], false, 0, elements.get(1));
+ }
+
+ public void testRemoveAllPropertyChangeEvent() throws Exception {
+ list.add("0");
+ assertPropertyChangeEvent(bean, new Runnable() {
+ public void run() {
+ list.removeAll(Arrays.asList(new String[] {"0"}));
+ }
+ });
+ }
+
+ public void testRetailAll() throws Exception {
+ List elements = Arrays.asList(new String[] { "0", "1", "2", "3" });
+ list.addAll(elements);
+
+ assertEquals(4, bean.getList().length);
+
+ list.retainAll(elements.subList(0, 2));
+ assertEquals(2, bean.getList().length);
+
+ assertEquals(elements.get(0), bean.getList()[0]);
+ assertEquals(elements.get(1), bean.getList()[1]);
+ }
+
+ public void testRetainAllListChangeEvent() throws Exception {
+ List elements = Arrays.asList(new String[] { "0", "1", "2", "3" });
+ list.addAll(elements);
+
+ ListChangeEventTracker listener = new ListChangeEventTracker();
+ list.addListChangeListener(listener);
+
+ assertEquals(0, listener.count);
+ list.retainAll(elements.subList(0, 2));
+
+ assertEquals(1, listener.count);
+ ListChangeEvent event = listener.event;
+ assertEquals(list, event.getObservableList());
+ assertEntry(event.diff.getDifferences()[0], false, 2, elements.get(2));
+ assertEntry(event.diff.getDifferences()[1], false, 2, elements.get(3));
+ }
+
+ public void testRetainAllPropertyChangeEvent() throws Exception {
+ list.addAll(Arrays.asList(new String[] {"0", "1"}));
+
+ assertPropertyChangeEvent(bean, new Runnable() {
+ public void run() {
+ list.retainAll(Arrays.asList(new String[] {"0"}));
+ }
+ });
+ }
+
+ public void testSet() throws Exception {
+ String oldElement = "old";
+ String newElement = "new";
+ list.add(oldElement);
+
+ assertEquals(oldElement, bean.getList()[0]);
+
+ list.set(0, newElement);
+ assertEquals(newElement, bean.getList()[0]);
+ }
+
+ public void testSetListChangeEvent() throws Exception {
+ String oldElement = "old";
+ String newElement = "new";
+ list.add(oldElement);
+
+ ListChangeEventTracker listener = new ListChangeEventTracker();
+ list.addListChangeListener(listener);
+ assertEquals(0, listener.count);
+
+ list.set(0, newElement);
+
+ assertEquals(1, listener.count);
+ ListChangeEvent event = listener.event;
+ assertEquals(list, event.getObservableList());
+ assertEntry(event.diff.getDifferences()[0], true, 0, newElement);
+ assertEntry(event.diff.getDifferences()[1], false, 1, oldElement);
+ }
+
+ public void testSetPropertyChangeEvent() throws Exception {
+ list.add("0");
+ assertPropertyChangeEvent(bean, new Runnable() {
+ public void run() {
+ list.set(0, "1");
+ }
+ });
+ }
+
+ public void testListChangeEventFiresWhenNewListIsSet() throws Exception {
+ Bean[] elements = new Bean[] { new Bean(), new Bean() };
+
+ ListChangeEventTracker listener = new ListChangeEventTracker();
+ list.addListChangeListener(listener);
+
+ assertEquals(0, listener.count);
+ bean.setList(elements);
+ assertEquals(1, listener.count);
+ }
+
+ private static void assertEntry(ListDiffEntry entry, boolean addition,
+ int position, Object element) {
+ assertEquals("addition", addition, entry.isAddition());
+ assertEquals("position", position, entry.getPosition());
+ assertEquals("element", element, entry.getElement());
+ }
+
+ private static void assertPropertyChangeEvent(Bean bean, Runnable runnable) {
+ PropertyChangeTracker listener = new PropertyChangeTracker();
+ bean.addPropertyChangeListener(listener);
+
+ Object[] old = bean.getList();
+ assertEquals(0, listener.count);
+
+ runnable.run();
+
+ PropertyChangeEvent event = listener.evt;
+ assertEquals("event did not fire", 1, listener.count);
+ assertEquals("list", event.getPropertyName());
+ assertEquals("old value", old, event.getOldValue());
+ assertEquals("new value", bean.getList(), event.getNewValue());
+ assertFalse("lists are equal", bean.getList().equals(old));
+ }
+
+ private static class PropertyChangeTracker implements
+ PropertyChangeListener {
+ int count;
+
+ PropertyChangeEvent evt;
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.beans.PropertyChangeListener#propertyChange(java.beans.PropertyChangeEvent)
+ */
+ public void propertyChange(PropertyChangeEvent evt) {
+ count++;
+ this.evt = evt;
+ }
+ }
+}
diff --git a/tests/org.eclipse.jface.tests.databinding/src/org/eclipse/core/tests/internal/databinding/internal/beans/JavaBeanObservableListTest.java b/tests/org.eclipse.jface.tests.databinding/src/org/eclipse/core/tests/internal/databinding/internal/beans/JavaBeanObservableListTest.java
index 9baed2c..8b1a9d3 100644
--- a/tests/org.eclipse.jface.tests.databinding/src/org/eclipse/core/tests/internal/databinding/internal/beans/JavaBeanObservableListTest.java
+++ b/tests/org.eclipse.jface.tests.databinding/src/org/eclipse/core/tests/internal/databinding/internal/beans/JavaBeanObservableListTest.java
@@ -11,25 +11,34 @@
package org.eclipse.core.tests.internal.databinding.internal.beans;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
import java.beans.PropertyDescriptor;
+import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
-import org.eclipse.core.databinding.observable.list.IListChangeListener;
import org.eclipse.core.databinding.observable.list.ListChangeEvent;
+import org.eclipse.core.databinding.observable.list.ListDiffEntry;
import org.eclipse.core.internal.databinding.internal.beans.JavaBeanObservableList;
import org.eclipse.jface.databinding.swt.SWTObservables;
import org.eclipse.jface.tests.databinding.AbstractDefaultRealmTestCase;
+import org.eclipse.jface.tests.databinding.EventTrackers.ListChangeEventTracker;
import org.eclipse.swt.widgets.Display;
/**
- * @since 3.3
+ * @since 1.1
*/
public class JavaBeanObservableListTest extends AbstractDefaultRealmTestCase {
- private JavaBeanObservableList observableList;
+ private JavaBeanObservableList list;
+
private PropertyDescriptor propertyDescriptor;
- private Bean bean;
+
+ private NonStandardBean bean;
+
private String propertyName;
-
+
/*
* (non-Javadoc)
*
@@ -37,52 +46,422 @@
*/
protected void setUp() throws Exception {
super.setUp();
-
+
propertyName = "list";
- propertyDescriptor = new PropertyDescriptor(propertyName, Bean.class);
- bean = new Bean();
-
- observableList = new JavaBeanObservableList(SWTObservables
- .getRealm(Display.getDefault()), bean, propertyDescriptor,
- Bean.class);
+ propertyDescriptor = new PropertyDescriptor(propertyName, NonStandardBean.class);
+ bean = new NonStandardBean(new ArrayList());
+
+ list = new JavaBeanObservableList(SWTObservables.getRealm(Display
+ .getDefault()), bean, propertyDescriptor, NonStandardBean.class);
}
public void testGetObserved() throws Exception {
- assertEquals(bean, observableList.getObserved());
+ assertEquals(bean, list.getObserved());
}
public void testGetPropertyDescriptor() throws Exception {
- assertEquals(propertyDescriptor, observableList.getPropertyDescriptor());
+ assertEquals(propertyDescriptor, list.getPropertyDescriptor());
+ }
+
+ public void testRegistersListenerAfterFirstListenerIsAdded()
+ throws Exception {
+ assertFalse(bean.changeSupport.hasListeners(propertyName));
+ list.addListChangeListener(new ListChangeEventTracker());
+ assertTrue(bean.changeSupport.hasListeners(propertyName));
+ }
+
+ public void testRemovesListenerAfterLastListenerIsRemoved()
+ throws Exception {
+ ListChangeEventTracker listener = new ListChangeEventTracker();
+ list.addListChangeListener(listener);
+
+ assertTrue(bean.changeSupport.hasListeners(propertyName));
+ list.removeListChangeListener(listener);
+ assertFalse(bean.changeSupport.hasListeners(propertyName));
+ }
+
+ public void testFiresListChangeEvents() throws Exception {
+ ListChangeEventTracker listener = new ListChangeEventTracker();
+ list.addListChangeListener(listener);
+
+ assertEquals(0, listener.count);
+ bean.setList(Arrays.asList(new String[] { "value" }));
+ assertEquals(1, listener.count);
+ }
+
+ public void testAddAddsElement() throws Exception {
+ int count = list.size();
+ String element = "1";
+
+ assertEquals(0, count);
+ list.add(element);
+ assertEquals(count + 1, list.size());
+ assertEquals(element, bean.getList().get(count));
+ }
+
+ public void testAddListChangeEvent() throws Exception {
+ ListChangeEventTracker listener = new ListChangeEventTracker();
+ list.addListChangeListener(listener);
+
+ assertEquals(0, listener.count);
+ String element = "1";
+
+ list.add(element);
+
+ assertEquals(1, listener.count);
+ ListChangeEvent event = listener.event;
+
+ assertEquals(list, event.getObservableList());
+ assertEntry(event.diff.getDifferences()[0], true, 0, element);
+ }
+
+ public void testAddFiresPropertyChangeEvent() throws Exception {
+ assertPropertyChangeEvent(bean, new Runnable() {
+ public void run() {
+ list.add("0");
+ }
+ });
+ }
+
+ public void testAddAtIndex() throws Exception {
+ String element = "1";
+ assertEquals(0, list.size());
+
+ list.add(0, element);
+ assertEquals(element, bean.getList().get(0));
+ }
+
+ public void testAddAtIndexListChangeEvent() throws Exception {
+ String element = "1";
+ assertEquals(0, list.size());
+
+ ListChangeEventTracker listener = new ListChangeEventTracker();
+ list.addListChangeListener(listener);
+
+ list.add(0, element);
+
+ ListChangeEvent event = listener.event;
+ assertEntry(event.diff.getDifferences()[0], true, 0, element);
}
- public void testRegistersListenerAfterFirstListenerIsAdded() throws Exception {
- assertFalse(bean.changeSupport.hasListeners(propertyName));
- observableList.addListChangeListener(new ListChangeListener());
- assertTrue(bean.changeSupport.hasListeners(propertyName));
+ public void testAddAtIndexPropertyChangeEvent() throws Exception {
+ assertPropertyChangeEvent(bean, new Runnable() {
+ public void run() {
+ list.add(0, "0");
+ }
+ });
}
-
- public void testRemovesListenerAfterLastListenerIsRemoved() throws Exception {
- ListChangeListener listener = new ListChangeListener();
- observableList.addListChangeListener(listener);
+
+ public void testRemove() throws Exception {
+ String element = "1";
+ list.add(element);
+
+ assertEquals(1, bean.getList().size());
+ list.remove(element);
+ assertEquals(0, bean.getList().size());
+ }
+
+ public void testRemoveListChangeEvent() throws Exception {
+ String element = "1";
+ list.add(element);
+
+ assertEquals(1, list.size());
+ ListChangeEventTracker listener = new ListChangeEventTracker();
+ list.addListChangeListener(listener);
+
+ list.remove(element);
+
+ assertEquals(1, listener.count);
+ ListChangeEvent event = listener.event;
+ assertEquals(list, event.getObservableList());
+ assertEntry(event.diff.getDifferences()[0], false, 0, element);
+ }
+
+ public void testRemovePropertyChangeEvent() throws Exception {
+ list.add("0");
- assertTrue(bean.changeSupport.hasListeners(propertyName));
- observableList.removeListChangeListener(listener);
- assertFalse(bean.changeSupport.hasListeners(propertyName));
+ assertPropertyChangeEvent(bean, new Runnable() {
+ public void run() {
+ list.remove("0");
+ }
+ });
}
-
- public void testFiresListChangeEvents() throws Exception {
- ListChangeListener listener = new ListChangeListener();
- observableList.addListChangeListener(listener);
-
- assertEquals(0, listener.count);
- bean.setList(Arrays.asList(new String[] {"value"}));
- assertEquals(1, listener.count);
+
+ public void testRemoveAtIndex() throws Exception {
+ String element = "1";
+ list.add(element);
+
+ assertEquals(element, bean.getList().get(0));
+
+ list.remove(0);
+ assertEquals(0, bean.getList().size());
}
-
- static class ListChangeListener implements IListChangeListener {
- int count;
- public void handleListChange(ListChangeEvent event) {
+
+ public void testRemoveAtIndexListChangeEvent() throws Exception {
+ String element = "1";
+ list.add(element);
+
+ assertEquals(1, list.size());
+ ListChangeEventTracker listener = new ListChangeEventTracker();
+ list.addListChangeListener(listener);
+
+ list.remove(0);
+
+ assertEquals(1, listener.count);
+ ListChangeEvent event = listener.event;
+ assertEquals(list, event.getObservableList());
+ assertEntry(event.diff.getDifferences()[0], false, 0, element);
+ }
+
+ public void testRemoveAtIndexPropertyChangeEvent() throws Exception {
+ list.add("0");
+ assertPropertyChangeEvent(bean, new Runnable() {
+ public void run() {
+ list.remove(0);
+ }
+ });
+ }
+
+ public void testAddAll() throws Exception {
+ Collection elements = Arrays.asList(new String[] { "1", "2" });
+ assertEquals(0, list.size());
+
+ list.addAll(elements);
+
+ assertEquals(2, bean.getList().size());
+ }
+
+ public void testAddAllListChangEvent() throws Exception {
+ List elements = Arrays.asList(new String[] { "1", "2" });
+ assertEquals(0, list.size());
+
+ ListChangeEventTracker listener = new ListChangeEventTracker();
+ list.addListChangeListener(listener);
+ assertEquals(0, listener.count);
+
+ list.addAll(elements);
+
+ assertEquals(1, listener.count);
+ ListChangeEvent event = listener.event;
+ assertEquals(list, event.getObservableList());
+
+ assertEntry(event.diff.getDifferences()[0], true, 0, elements.get(0));
+ assertEntry(event.diff.getDifferences()[1], true, 1, elements.get(1));
+ }
+
+ public void testAddAllPropertyChangeEvent() throws Exception {
+ assertPropertyChangeEvent(bean, new Runnable() {
+ public void run() {
+ list.addAll(Arrays.asList(new String[] {"0", "1"}));
+ }
+ });
+ }
+
+ public void testAddAllAtIndex() throws Exception {
+ List elements = Arrays.asList(new String[] { "1", "2" });
+ list.addAll(elements);
+
+ assertEquals(2, list.size());
+
+ list.addAll(2, elements);
+
+ assertEquals(4, bean.getList().size());
+ assertEquals(elements.get(0), bean.getList().get(0));
+ assertEquals(elements.get(1), bean.getList().get(1));
+ }
+
+ public void testAddAllAtIndexListChangeEvent() throws Exception {
+ List elements = Arrays.asList(new String[] { "1", "2" });
+ list.addAll(elements);
+
+ ListChangeEventTracker listener = new ListChangeEventTracker();
+ list.addListChangeListener(listener);
+
+ assertEquals(0, listener.count);
+
+ list.addAll(2, elements);
+
+ assertEquals(1, listener.count);
+ ListChangeEvent event = listener.event;
+ assertEquals(list, event.getObservableList());
+ assertEntry(event.diff.getDifferences()[0], true, 2, elements.get(0));
+ assertEntry(event.diff.getDifferences()[1], true, 3, elements.get(1));
+ }
+
+ public void testAddAllAtIndexPropertyChangeEvent() throws Exception {
+ assertPropertyChangeEvent(bean, new Runnable() {
+ public void run() {
+ list.addAll(0, Arrays.asList(new String[] {"1", "2"}));
+ }
+ });
+ }
+
+ public void testRemoveAll() throws Exception {
+ List elements = Arrays.asList(new String[] { "1", "2" });
+ list.addAll(elements);
+ list.addAll(elements);
+
+ assertEquals(4, bean.getList().size());
+ list.removeAll(elements);
+
+ assertEquals(2, bean.getList().size());
+ assertEquals(elements.get(0), bean.getList().get(0));
+ assertEquals(elements.get(1), bean.getList().get(1));
+ }
+
+ public void testRemoveAllListChangeEvent() throws Exception {
+ List elements = Arrays.asList(new String[] { "1", "2" });
+ list.addAll(elements);
+ list.addAll(elements);
+
+ ListChangeEventTracker listener = new ListChangeEventTracker();
+ list.addListChangeListener(listener);
+
+ assertEquals(0, listener.count);
+ list.removeAll(elements);
+
+ ListChangeEvent event = listener.event;
+ assertEquals(list, event.getObservableList());
+ assertEntry(event.diff.getDifferences()[0], false, 0, elements.get(0));
+ assertEntry(event.diff.getDifferences()[1], false, 0, elements.get(1));
+ }
+
+ public void testRemoveAllPropertyChangeEvent() throws Exception {
+ list.add("0");
+ assertPropertyChangeEvent(bean, new Runnable() {
+ public void run() {
+ list.removeAll(Arrays.asList(new String[] {"0"}));
+ }
+ });
+ }
+
+ public void testRetailAll() throws Exception {
+ List elements = Arrays.asList(new String[] { "0", "1", "2", "3" });
+ list.addAll(elements);
+
+ assertEquals(4, bean.getList().size());
+
+ list.retainAll(elements.subList(0, 2));
+ assertEquals(2, bean.getList().size());
+
+ assertEquals(elements.get(0), bean.getList().get(0));
+ assertEquals(elements.get(1), bean.getList().get(1));
+ }
+
+ public void testRetainAllListChangeEvent() throws Exception {
+ List elements = Arrays.asList(new String[] { "0", "1", "2", "3" });
+ list.addAll(elements);
+
+ ListChangeEventTracker listener = new ListChangeEventTracker();
+ list.addListChangeListener(listener);
+
+ assertEquals(0, listener.count);
+ list.retainAll(elements.subList(0, 2));
+
+ assertEquals(1, listener.count);
+ ListChangeEvent event = listener.event;
+ assertEquals(list, event.getObservableList());
+ assertEntry(event.diff.getDifferences()[0], false, 2, elements.get(2));
+ assertEntry(event.diff.getDifferences()[1], false, 2, elements.get(3));
+ }
+
+ public void testRetainAllPropertyChangeEvent() throws Exception {
+ list.addAll(Arrays.asList(new String[] {"0", "1"}));
+
+ assertPropertyChangeEvent(bean, new Runnable() {
+ public void run() {
+ list.retainAll(Arrays.asList(new String[] {"0"}));
+ }
+ });
+ }
+
+ public void testSet() throws Exception {
+ String oldElement = "old";
+ String newElement = "new";
+ list.add(oldElement);
+
+ assertEquals(oldElement, bean.getList().get(0));
+
+ list.set(0, newElement);
+ assertEquals(newElement, bean.getList().get(0));
+ }
+
+ public void testSetListChangeEvent() throws Exception {
+ String oldElement = "old";
+ String newElement = "new";
+ list.add(oldElement);
+
+ ListChangeEventTracker listener = new ListChangeEventTracker();
+ list.addListChangeListener(listener);
+ assertEquals(0, listener.count);
+
+ list.set(0, newElement);
+
+ assertEquals(1, listener.count);
+ ListChangeEvent event = listener.event;
+ assertEquals(list, event.getObservableList());
+ assertEntry(event.diff.getDifferences()[0], true, 0, newElement);
+ assertEntry(event.diff.getDifferences()[1], false, 1, oldElement);
+ }
+
+ public void testSetPropertyChangeEvent() throws Exception {
+ list.add("0");
+ assertPropertyChangeEvent(bean, new Runnable() {
+ public void run() {
+ list.set(0, "1");
+ }
+ });
+ }
+
+ public void testListChangeEventFiresWhenNewListIsSet() throws Exception {
+ List elements = Arrays.asList(new String[] { "1", "2" });
+
+ ListChangeEventTracker listener = new ListChangeEventTracker();
+ list.addListChangeListener(listener);
+
+ assertEquals(0, listener.count);
+ bean.setList(elements);
+ assertEquals(1, listener.count);
+ }
+
+ private static void assertEntry(ListDiffEntry entry, boolean addition,
+ int position, Object element) {
+ assertEquals("addition", addition, entry.isAddition());
+ assertEquals("position", position, entry.getPosition());
+ assertEquals("element", element, entry.getElement());
+ }
+
+ private static void assertPropertyChangeEvent(NonStandardBean bean, Runnable runnable) {
+ PropertyChangeTracker listener = new PropertyChangeTracker();
+ bean.addPropertyChangeListener(listener);
+
+ List old = bean.getList();
+ assertEquals(0, listener.count);
+
+ runnable.run();
+
+ PropertyChangeEvent event = listener.evt;
+ assertEquals("event did not fire", 1, listener.count);
+ assertEquals("list", event.getPropertyName());
+ assertEquals("old value", old, event.getOldValue());
+ assertEquals("new value", bean.getList(), event.getNewValue());
+ assertFalse("lists are equal", bean.getList().equals(old));
+ }
+
+ private static class PropertyChangeTracker implements
+ PropertyChangeListener {
+ int count;
+
+ PropertyChangeEvent evt;
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.beans.PropertyChangeListener#propertyChange(java.beans.PropertyChangeEvent)
+ */
+ public void propertyChange(PropertyChangeEvent evt) {
count++;
+ this.evt = evt;
}
- }
+ }
}
diff --git a/tests/org.eclipse.jface.tests.databinding/src/org/eclipse/core/tests/internal/databinding/internal/beans/NonStandardBean.java b/tests/org.eclipse.jface.tests.databinding/src/org/eclipse/core/tests/internal/databinding/internal/beans/NonStandardBean.java
new file mode 100644
index 0000000..2ee5b1a
--- /dev/null
+++ b/tests/org.eclipse.jface.tests.databinding/src/org/eclipse/core/tests/internal/databinding/internal/beans/NonStandardBean.java
@@ -0,0 +1,77 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Brad Reynolds 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:
+ * Brad Reynolds - initial API and implementation
+ ******************************************************************************/
+
+package org.eclipse.core.tests.internal.databinding.internal.beans;
+
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Simple non-standard (java.util.List-based property) Java Bean for testing.
+ *
+ * @since 3.3
+ */
+public class NonStandardBean {
+ /* package */PropertyChangeSupport changeSupport = new PropertyChangeSupport(this);
+ private String value;
+ private List list = new ArrayList();
+ private Set set;
+
+ public NonStandardBean() {
+ }
+
+ public NonStandardBean(String value) {
+ this.value = value;
+ }
+
+ public NonStandardBean(List list) {
+ this.list = list;
+ }
+
+ public NonStandardBean(Set set) {
+ this.set = set;
+ }
+
+ public void addPropertyChangeListener(PropertyChangeListener listener) {
+ changeSupport.addPropertyChangeListener(listener);
+ }
+
+ public void removePropertyChangeListener(PropertyChangeListener listener) {
+ changeSupport.removePropertyChangeListener(listener);
+ }
+
+ public String getValue() {
+ return value;
+ }
+
+ public void setValue(String value) {
+ changeSupport.firePropertyChange("value", this.value, this.value = value);
+ }
+
+ public List getList() {
+ return list;
+ }
+
+ public void setList(List list) {
+ changeSupport.firePropertyChange("list", this.list, this.list = list);
+ }
+
+ public Set getSet() {
+ return set;
+ }
+
+ public void setSet(Set set) {
+ changeSupport.firePropertyChange("set", this.set, this.set = set);
+ }
+}
diff --git a/tests/org.eclipse.jface.tests.databinding/src/org/eclipse/jface/tests/databinding/BindingTestSuite.java b/tests/org.eclipse.jface.tests.databinding/src/org/eclipse/jface/tests/databinding/BindingTestSuite.java
index c8c6ebe..a1987d6 100644
--- a/tests/org.eclipse.jface.tests.databinding/src/org/eclipse/jface/tests/databinding/BindingTestSuite.java
+++ b/tests/org.eclipse.jface.tests.databinding/src/org/eclipse/jface/tests/databinding/BindingTestSuite.java
@@ -77,6 +77,7 @@
import org.eclipse.core.tests.internal.databinding.internal.beans.BeanObservableListDecoratorTest;
import org.eclipse.core.tests.internal.databinding.internal.beans.BeanObservableSetDecoratorTest;
import org.eclipse.core.tests.internal.databinding.internal.beans.BeanObservableValueDecoratorTest;
+import org.eclipse.core.tests.internal.databinding.internal.beans.JavaBeanObservableArrayBasedListTest;
import org.eclipse.core.tests.internal.databinding.internal.beans.JavaBeanObservableListTest;
import org.eclipse.core.tests.internal.databinding.internal.beans.JavaBeanObservableMapTest;
import org.eclipse.core.tests.internal.databinding.internal.beans.JavaBeanObservableSetTest;
@@ -212,6 +213,7 @@
addTestSuite(BeanObservableSetDecoratorTest.class);
addTestSuite(BeanObservableValueDecoratorTest.class);
addTestSuite(BeanObservableListDecoratorTest.class);
+ addTestSuite(JavaBeanObservableArrayBasedListTest.class);
addTestSuite(JavaBeanObservableListTest.class);
addTestSuite(JavaBeanObservableMapTest.class);
addTestSuite(JavaBeanObservableSetTest.class);
diff --git a/tests/org.eclipse.jface.tests.databinding/src/org/eclipse/jface/tests/databinding/EventTrackers.java b/tests/org.eclipse.jface.tests.databinding/src/org/eclipse/jface/tests/databinding/EventTrackers.java
index 4208316..bf1d7a6 100644
--- a/tests/org.eclipse.jface.tests.databinding/src/org/eclipse/jface/tests/databinding/EventTrackers.java
+++ b/tests/org.eclipse.jface.tests.databinding/src/org/eclipse/jface/tests/databinding/EventTrackers.java
@@ -13,6 +13,8 @@
import org.eclipse.core.databinding.observable.ChangeEvent;
import org.eclipse.core.databinding.observable.IChangeListener;
+import org.eclipse.core.databinding.observable.list.IListChangeListener;
+import org.eclipse.core.databinding.observable.list.ListChangeEvent;
import org.eclipse.core.databinding.observable.map.IMapChangeListener;
import org.eclipse.core.databinding.observable.map.MapChangeEvent;
import org.eclipse.core.databinding.observable.value.IValueChangeListener;
@@ -54,4 +56,14 @@
this.event = event;
}
}
+
+ public static class ListChangeEventTracker implements IListChangeListener {
+ public int count;
+ public ListChangeEvent event;
+
+ public void handleListChange(ListChangeEvent event) {
+ count++;
+ this.event = event;
+ }
+ }
}