graphstream / gs-core

Graphstream core
http://graphstream-project.org/
Other
403 stars 109 forks source link

IdAlreadyInUseException when toggeling auto layout #209

Open toddharrison opened 7 years ago

toddharrison commented 7 years ago

I have created a new graph and registered a pump so that I am notified when a user clicks on a node using something like this:

        viewer.enableAutoLayout();

        final ViewerPipe pipe = viewer.newViewerPipe();
        pipe.addViewerListener(this);
        pipe.addSink(graph);
        graphEventPumpThread = new Thread() {
            @Override
            public void run() {
                try {
                    while (true) {
                        pipe.blockingPump();
                    }
                } catch (final InterruptedException e) {
                    // Interrupted for shutdown
                }
            }
        };
        graphEventPumpThread.start();

I also have a toggle that turns on and off auto layout, like so:

    public void toggleAutoLayout(final ActionEvent event) {
        if (autoLayoutCheckbox.isSelected()) {
            viewer.enableAutoLayout();
        } else {
            viewer.disableAutoLayout();
        }
    }

Everything works fine until I toggle the auto layout off and then on again. When I toggle it on again I get the following exception:

Exception in thread "Thread-7" org.graphstream.graph.IdAlreadyInUseException: singleton exception: id "01808851-49d4-4767-b60c-c07deac9e45e" already in use. Cannot create a node.
    at org.graphstream.graph.implementations.AbstractGraph.addNode(AbstractGraph.java:321)
    at org.graphstream.util.GraphListeners.nodeAdded(GraphListeners.java:412)
    at org.graphstream.graph.implementations.AbstractGraph.nodeAdded(AbstractGraph.java:733)
    at org.graphstream.stream.SourceBase.sendNodeAdded(SourceBase.java:323)
    at org.graphstream.ui.view.ViewerPipe.nodeAdded(ViewerPipe.java:301)
    at org.graphstream.stream.SourceBase.sendNodeAdded(SourceBase.java:323)
    at org.graphstream.stream.thread.ThreadProxyPipe.processMessage(ThreadProxyPipe.java:492)
    at org.graphstream.stream.thread.ThreadProxyPipe.blockingPump(ThreadProxyPipe.java:311)
    at org.graphstream.stream.thread.ThreadProxyPipe.blockingPump(ThreadProxyPipe.java:280)
    at org.graphstream.ui.view.ViewerPipe.blockingPump(ViewerPipe.java:106)

It seems to be trying to add a node again, just by changing the auto layout to be true. I also receive this exception if I startup my application and do not specify viewer.enableAutoLayout(); before creating the ViewerPipe, as above.

jordilaforge commented 7 years ago

can you throw that into a github project so that we can try it out?

pigne commented 7 years ago

Ok, This is only a guess.

The problem is that viewer.enableAutoLayout() is "replaying" all the graph events so that the newly created layout algorithm can be aware of all the nodes and edges of the graph. In the mean time you plugged the graphicGraph back to the "real" graph with a pipe. So each time you re-enable the layout, you also send all the graphic graph's events back to the original graph that itself already has those nodes and edges. Hence the IdAlreadyInUseException.

Perhaps viewer.enableAutoLayout() should be reworked, but iI thing it was meant to be used only once in le life time of the visualisation.

In the mean time you can prevent the original graph from receiving elements-related event and only listen to attribute-related events. Use :

pipe.addAttributeSink(graph);

instead of

pipe.addSink(graph);