miho / VWorkflows

Flow Visualization Library for JavaFX and VRL-Studio
http://vworkflows.mihosoft.eu
Other
297 stars 67 forks source link

Content of nodes added to flow after setting up skin factories doesn't get updated #28

Open tengwar opened 8 years ago

tengwar commented 8 years ago

With code like:

    flow = loadFlow();
    addNode("1");

    // create skin factory for flow visualization
    FXValueSkinFactory fXSkinFactory = new FXValueSkinFactory(rootPane);
    // register visualizations for various types
    fXSkinFactory.addSkinClassForValueType(Example.class, ExampleFlowNodeSkin.class);
    // generate the ui for the flow
    flow.setSkinFactories(fXSkinFactory);
    addNode("2");

The second added node appears empty as FXFlowNodeSkinBase's updateView() never gets called for it. I suggest watching the flow for new nodes and acting on them too.

mcolletta commented 8 years ago

Hi @tengwar, here the problem is not "watching the flow for new nodes", the library already does that by means of a nodeListener. The real issue in this case is more subtle and has to do with the way a new VNode is built. I assume that the fictional addNode method in your example is something like this one

static VNode addNode(VFlow flow, object inp) {
    VNode node = flow.newNode();
    node.setTitle(title);
    node.getValueObject().setValue(inp);
    ...
    return node;
}

in the code after addSkinFactories (or setSkinFactories) when you add a new node (with flow.newNode()) a nodeListener change event (wasAdded) is fired (see VFlowImpl.java) due to changes in the list of nodes (that is readOnlyObservableNodes in FlowModelImpl) but in the chooseNodeSkin(VNode n, VFlow flow) (class FXValueSkinFactory) it is passed a null value since node.getValueObject().setValue(inp) is still not called at this time! So in the end the method is not able of choosing the correct skin class because the value type is unknown at this process time step. The method updateView() is however called in both cases but for Node2 is called within the base class (where that method does nothing!) Indeed, if you try debugging/logging with getClass().getName() you can see that the updateView of "Node 1" has the correct custom context (ExampleFlowNodeSkin in your example) while for the "Node 2" the class is still FXFlowNodeSkinBase.

A workaround is to create the nodes passing directly the value with a DefaultValueObject. Below a gist with a working demo: https://gist.github.com/mcolletta/1d28c56a01eb207ee6214ad5194cf879

maybe a more general solution could be applying the chooseNodeSkin during the setValue of the node's underlying object value but my knowledge of this project is too limited to ponder all the implications of such modification

Regards