Bug 123375 [DataBinding] Enhancements to the data binding framework
My team has developed a library with some similarities to the data binding framework. I've been investigating what is required to adopt the data binding framework without losing any features. We don't actually need the data binding or validation part. We need standardized interfaces for trees, sets, lists, and scalars that fire change notifications, and utilities and content providers to work with them. Although this isn't the main focus of the framework, there is a subset of the framework that comes very close to giving us what we need. I've prepared a patch that refactors the framework to add the features we need. Nick has approved the features in principle, and Boris has approved an initial version of the API. However, since David is most active in the code right now I've filed this bug to get his feedback. Requirements: - Need read-only interfaces for sets, lists, trees, and scalars that fire change notifications. - Asynchronous support. Updatables need to be able to indicate that their value is currently being recomputed asynchronously and will change soon. Needed for progress and busy affordances. - Support for "updatable functions". An updatable function is a transformation from one object to another where the transformation may change over time. - Library of set operations. Require: - union (a set consisting of elements from a set of sets) - list-to-set conversion - set transformation (takes a set and an updatable function as input, produces a new set consisting of the function applied to all elements in the original set) - Require standard content providers and label providers that can be instantiated directly and can use the above data types. - The tree interface needs to make it easy to reuse a set as one level in a tree. - Need to be able to instrument calls to IUpdatable getters. We use this to automatically compute dependencies and attach listeners. Changes made by the patch: - Implements the requirements (above). - Renames the existing writable IUpdatable interfaces to IWritableUpdatable* to distinguish them from the read-only versions. The writable ones extend the read-only ones. - Adds a greedyExec utility. This is similar to SWT's asyncExec, but it reduces flicker by running the runnable before the next repaint rather than at the end of the event queue. Also added runOnce, which ensures that a runnable will run before the next repaint and only run once. Replaced asyncExecs with greedyExecs and runOnces. - (optional) Adds ControlUpdator and ComputableValue utility classes. These make use of the instrumented getters to automatically attach and detach listeners. Boris suggested this pattern awile back and I thought it was brilliant so added it. If anyone has objections, they can be pulled out from the API and I can just use them for my own code. This is the extent of the patch. However, I have some additional suggestions which I did not implement, but would like to mention before they're forgotten: - Suggestion: remove getType(). I often need to wrap data structures that do not supply this information, where computing it would require extra plugin activation, or where the code for determining the types would double the code size of the updatable. For this reason, I couldn't include getType on the new read-only interfaces. Since implementers of the writable interfaces are likely to hit the same problems, I would strongly recommend that the remainder of the library discard this pattern as well. It looks like it is only necessary for locating the correct conversions. If conversion lookups used instanceof or isAssignableTo rather than identity comparisons, then the java types of the elements would be enough and this method could be removed. - Suggestion: make the IUpdatable implementations API. The data binding library has a lot of useful IUpdatable implementations that convert a wide variety of data types into standard data structures. However, creating them requires a lot of context (you need a BindingContext, a factory, and a Property first). It is clear that the factory has benefits for WYSIWIG editors and data-driven UIs. But for those of us who are using them programmatically, it would be a lot easier to say "new CComboUpdatableValue(myCombo, SWTProperties.TEXT)". These classes are too useful to be internal. (Make them final, though). - Suggestion: Remove ChangeEvent.getParent(). With the ITreeProvider in the patch, it is not necessary. - Suggestion: Remove one of the writable tree variants (ITree and IUpdatableTree. I've renamed them to IWritableTree and IWritableUpdatable tree respectively in my patch). Remove the getters from the remaining tree interface and make it extend the read-only ITreeProvider interface. This will permit utilities that understand the read-only version to work with the writable one.
tests/org.eclipse.jface.tests.databinding/src/org/eclipse/jface/databinding/UpdatableCollectionTest.java
/*
	 * Test method for 'org.eclipse.jface.databinding.UpdatableCollection.getElements()'
	 */
	public void testGetElementsAndSetElements() {
		TestUpdatableCollection collection = new TestUpdatableCollection();
		String string1 = "string1";
		String string2 = "string2";
		String string3 = "string3";
		String string4 = "string4";
		String string5 = "string5";
		
		collection.addElement(string1, 0);
		collection.addElement(string2, 1);
		
		List elementsToUpdate = new ArrayList();
		elementsToUpdate.add(string3);
		elementsToUpdate.add(string4);
		elementsToUpdate.add(string5);
		
		collection.setElements(elementsToUpdate);
		
		assertEquals("The collection was not updated to the right size.", 3, collection.getSize());
		assertEquals("The wrong element was found in position 0", string3, collection.getElement(0));
		assertEquals("The wrong element was found in position 1", string4, collection.getElement(1));
		assertEquals("The wrong element was found in position 2", string5, collection.getElement(2));
		
		assertNotSame("The all elements list instance should not be the one provided in the set.", elementsToUpdate, collection.getElements());