data-bindingeclipse-emfemfeclipse-databinding

Nested observable list from EObjects contents


I have a model with the following structure (specified here in Xcore):

class Network {
    contains Master[] masters
}

class Master {
    contains Slave[] slaves
}

class Slave {}

I want to use EMF databinding to create an observable list of all slave objects in all masters in the network.

How can this be done?

Alternatively: Can I create a observable list of observable lists of slaves? That is, a structure of the type IObservableList<IObservableList<Slave>>.


The following, for example, does not work:

Network network = ... 

IObservableList allSlaves = EMFProperties
    .list(Literals.NETWORK__MASTERS)
    .values(Literals.MASTER__SLAVES)
    .observe(network);

The resulting list seem to be of type IObservableList<EList<Slave>> instead of the desired type. The problem is that the resulting IObservableList has elements of the class EObjectContainmentEList, which is not an IObservableList.


Solution

  • It turned out that there is a way to create nested observable lists, not only for EMF list features but for all kind of observable lists.

    The trick is to use the MasterDetailObservables.detailValues method with a factory that returns observable lists.

    Network network = TryingFactory.eINSTANCE.createNetwork();
    network.getMasters().add(TryingFactory.eINSTANCE.createMaster());
    network.getMasters().add(TryingFactory.eINSTANCE.createMaster());
    network.getMasters().get(0).getSlaves().add(TryingFactory.eINSTANCE.createSlave());
    network.getMasters().get(1).getSlaves().add(TryingFactory.eINSTANCE.createSlave());
    network.getMasters().get(1).getSlaves().add(TryingFactory.eINSTANCE.createSlave());
    
    IObservableList<Master> masterList = EMFProperties.list(Literals.NETWORK__MASTERS).observe(network);
    
    IObservableList<IObservableList<Slave>> nestedLists = MasterDetailObservables.detailValues(masterList,
            master -> Observables.constantObservableValue(masterList.getRealm(), 
                    EMFProperties.list(Literals.MASTER__SLAVES).observe(master),
                    IObservableList.class),
            IObservableList.class);
    
    // Dispose nested lists when they are removed from the top-level list 
    nestedLists.addListChangeListener(event -> event.diff.accept(new ListDiffVisitor<IObservableList<?>>() {
        @Override
        public void handleRemove(int index, IObservableList<?> element) {
            element.dispose();
        }
    
        @Override public void handleAdd(int index, IObservableList<?> element) {}
        @Override public void handleMove(int oldIndex, int newIndex, IObservableList<?> element) {}
    }));
    
    nestedLists.forEach(System.out::println);
    // Prints:
    // [trying.impl.SlaveImpl@7692d9cc]
    // [trying.impl.SlaveImpl@75f32542, trying.impl.SlaveImpl@7f1302d6]