| Summary: | [DataBinding] Support nested list-typed properties in BeansObservables/PojoObservables | ||
|---|---|---|---|
| Product: | [Eclipse Project] Platform | Reporter: | Henno Vermeulen <strider80> |
| Component: | UI | Assignee: | Platform UI Triaged <platform-ui-triaged> |
| Status: | RESOLVED WORKSFORME | QA Contact: | Matthew Hall <qualidafial> |
| Severity: | enhancement | ||
| Priority: | P3 | ||
| Version: | 4.0 | ||
| Target Milestone: | --- | ||
| Hardware: | PC | ||
| OS: | Windows 7 | ||
| Whiteboard: | |||
I was a bit eager with simplifying and inlining my short helper methods for getting the property parts before and after the .
When modelProperty is a simple property that does not contain a ., I think that the code
modelProperty.substring(modelProperty.lastIndexOf('.') + 1)
actually works by accident because modelProperty.lastIndexOf('.') will then return -1, but this is a bit shady code.
If I understand your request correctly, you would like a simple way to observe a list property of a value property of an observable. e.g.
IObservableList siblingNodes = BeansObservables
.observeDetailList(nodeObservable, "parent.children", Node.class);
If that is what you're asking, you should take a look at the property APIs--they support nested property chaining extensively. The above code (which does not work BTW, but reflects my understanding of your request) would be written as:
IObservableList siblingNodes = BeanProperties
.value(Node.class, "parent")
.list("children")
.observeDetail(nodeObservable)
The reason we do not support nested properties with anything other than value properties is that it is impossible for us to know on the framework side which part of a nested property is the list property:
BeansObservables.observeList(foo, "bar.baz.buz")
Presumably one of these properties is a list property, and the others are value properties. But which one?
Our workaround was to separate keep the properties separate and only allow nested property names for value properties, but to allow you to chain all different types of properties (value, list, set, map) but still allow you to chain them in a single expression:
IObservableList siblingNames = BeanProperties
.value("parent")
.list("children")
.values("name") // note the plural "values" here
.observe(person);
WORKSFORME. If I am reading your description correctly, your use case is already satisfied by using IValueProperty.list(IListProperty) property chaining. If I've misunderstood your request, please reopen and elaborate. Our use case is with master-detail binding. We have an IObservableValue for the master table selection which is of type CustomerContactRelation. It has exactly one ContactPerson object which in its turn has a List<ObtainedDegrees>. We wish to observe this List so that it can be used as the input for a detail table. So we wish to have an IObservableList for the property "contactPerson.obtainedDegrees" of the given IObservableValue where the first property is a single Object and the last property is a List. So what you want to do is bind from the contact relation viewer selection to the input of the obtained degrees viewer.
On the obtained degrees viewer, use this property for content provider:
IListProperty childrenProperty = BeanProperties.value("contactPerson")
.list("obtainedDegrees");
ViewerSupport.setUp(viewer, null, childrenProperty, labelProperty...);
Does this help?
Well, I guess that line of code would help in my example. However I wish to have a generic "util" method for binding to a list property in my model where the property may be nested but doesn't have to. Maybe the code in my first comment can be rewritten using a combination of BeanProperties.value and IBeanValueProperty.list, but then it would be of the same length because you still have to parse the first and last part of the possibly nested property. True, but there's a reason we kept those separate. By making you explicitly state which properties are values and which are lists, it is trivial for someone new to the code to understand what is going on.
Moreover, it's not a given that the last property in the chain in the list. You could have a value-list-value chain:
IListProperty siblingNames = BeanProperties
.value("parent")
.list("children")
.values("name");
We chose this design so that Data Binding doesn't have to guess what's going on in your model.
Alright, I guess your last example is a more advanced usecase that I didn't think of when posting this :). Let's keep it at this, indeed it already works for me with the BeansObservablesExtension.observeDetailList code I wrote. Keep the questions coming though--by challenging the API you help us see how folks instinctively use the API, and that helps us design things to be more intuitive. :) |
Build Identifier: 20090920-1017 Currently the BeansObservables/PojoObservables that return an IObservableValue support nested properties but the methods that return an IObservableList (/Set/Map) do not. This is not hard to solve, for example I use: import org.eclipse.core.databinding.beans.BeansObservables; import org.eclipse.core.databinding.observable.list.IObservableList; import org.eclipse.core.databinding.observable.value.IObservableValue; public final class BeansObservablesExtension { private BeansObservablesExtension() { } /** * Same as * {@link BeansObservables#observeDetailList(IObservableValue, String, Class)} * except that nested properties are supported. */ public static IObservableList observeDetailList( IObservableValue modelObservable, String modelProperty, Class<?> propertyType) { IObservableValue leafModelObservable; if (modelProperty.contains(".")) { leafModelObservable = BeansObservables.observeDetailValue( modelObservable, modelProperty.substring(0, modelProperty .lastIndexOf('.')), null); } else { leafModelObservable = modelObservable; } return BeansObservables .observeDetailList(leafModelObservable, modelProperty .substring(modelProperty.lastIndexOf('.') + 1), propertyType); } } Reproducible: Always