All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.graphstream.ui.fx_viewer.FxViewer Maven / Gradle / Ivy

The newest version!
/*
 * This file is part of GraphStream .
 * 
 * GraphStream is a library whose purpose is to handle static or dynamic
 * graph, create them from scratch, file or any source and display them.
 * 
 * This program is free software distributed under the terms of two licenses, the
 * CeCILL-C license that fits European law, and the GNU Lesser General Public
 * License. You can  use, modify and/ or redistribute the software under the terms
 * of the CeCILL-C license as circulated by CEA, CNRS and INRIA at the following
 * URL  or under the terms of the GNU LGPL as published by
 * the Free Software Foundation, either version 3 of the License, or (at your
 * option) any later version.
 * 
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
 * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see .
 * 
 * The fact that you are presently reading this means that you have had
 * knowledge of the CeCILL-C and LGPL licenses and that you accept their terms.
 */

 /**
  * @author Antoine Dutot 
  * @author Guilhelm Savin 
  * @author Hicham Brahimi 
  */
  
package org.graphstream.ui.fx_viewer;

import org.graphstream.graph.Graph;
import org.graphstream.stream.ProxyPipe;
import org.graphstream.stream.Source;
import org.graphstream.stream.thread.ThreadProxyPipe;
import org.graphstream.ui.graphicGraph.GraphicGraph;
import org.graphstream.ui.javafx.FxGraphRenderer;
import org.graphstream.ui.view.GraphRenderer;
import org.graphstream.ui.view.View;
import org.graphstream.ui.view.Viewer;

import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.util.Duration;

/**
 * Set of views on a graphic graph.
 * 
 * 

* The viewer class is in charge of maintaining : *

    *
  • A "graphic graph" (a special graph that internally stores the graph under * the form of style sets of "graphic" elements, suitable to draw the graph, but * not to adapted to used it as a general graph),
  • *
  • The eventual proxy pipe from which the events come from (but graph events * can come from any kind of source),
  • *
  • A default view, and eventually more views on the graphic graph.
  • *
  • A flag that allows to repaint the view only if the graphic graph changed. *
  • *
*

* *

* The graphic graph can be created by the viewer or given at construction (to * share it with another viewer). *

* *

* Once created, the viewer runs in a loop inside the UI thread. You * cannot call methods on it directly if you are not in this thread. The * only operation that you can use in other threads is the constructor, the * {@link #addView(View)}, {@link #removeView(String)} and the {@link #close()} * methods. Other methods are not protected from concurrent accesses. *

* *

* Some constructors allow a {@link ProxyPipe} as argument. If given, the * graphic graph is made listener of this pipe and the pipe is "pumped" during * the view loop. This allows to run algorithms on a graph in the main thread * (or any other thread) while letting the viewer run in the ui thread. *

* *

* Be very careful: due to the nature of graph events in GraphStream, the viewer * is not aware of events that occured on the graph before its creation. * There is a special mechanism that replay the graph if you use a proxy pipe or * if you pass the graph directly. However, when you create the viewer by * yourself and only pass a {@link Source}, the viewer will not display * the events that occured on the source before it is connected to it. *

*/ public class FxViewer extends Viewer { // Attributes /** * Timer in the JavaFX thread. */ protected Timeline timeline ; /** * Delay in milliseconds between frames. */ protected int delay = 40; /** * Name of the default view. */ public static String DEFAULT_VIEW_ID = "defaultView"; public String getDefaultID() { return DEFAULT_VIEW_ID ; } // Construction /** * The graph or source of graph events is in another thread or on another * machine, but the pipe already exists. The graphic graph displayed by this * viewer is created. * * @param source * The source of graph events. */ public FxViewer(ProxyPipe source) { graphInAnotherThread = true; init(new GraphicGraph(newGGId()), source, (Source) null); } /** * We draw a pre-existing graphic graph. The graphic graph is maintained by * its creator. * * @param graph * THe graph to draw. */ public FxViewer(GraphicGraph graph) { graphInAnotherThread = false; init(graph, (ProxyPipe) null, (Source) null); } /** * New viewer on an existing graph. The viewer always run in the UI * thread, therefore, you must specify how it will take graph events from * the graph you give. If the graph you give will be accessed only from the * UI thread use ThreadingModel.GRAPH_IN_GUI_THREAD. If the graph you use * is accessed in another thread use ThreadingModel.GRAPH_IN_ANOTHER_THREAD. * This last scheme is more powerful since it allows to run algorithms on * the graph in parallel with the viewer. * * @param graph * The graph to render. * @param threadingModel * The threading model. */ public FxViewer(Graph graph, ThreadingModel threadingModel) { switch (threadingModel) { case GRAPH_IN_GUI_THREAD: graphInAnotherThread = false; init(new GraphicGraph(newGGId()), (ProxyPipe) null, graph); enableXYZfeedback(true); break; case GRAPH_IN_ANOTHER_THREAD: graphInAnotherThread = true; ThreadProxyPipe tpp = new ThreadProxyPipe(); tpp.init(graph, true); init(new GraphicGraph(newGGId()), tpp, (Source) null); enableXYZfeedback(false); break; case GRAPH_ON_NETWORK: throw new RuntimeException("TO DO, sorry !:-)"); } } /** * Initialise the viewer. * * @param graph * The graphic graph. * @param ppipe * The source of events from another thread or machine (null if * source != null). * @param source * The source of events from this thread (null if ppipe != null). */ public void init(GraphicGraph graph, ProxyPipe ppipe, Source source) { super.graph = graph; super.pumpPipe = ppipe; super.sourceInSameThread = source; this.timeline = new Timeline(new KeyFrame(Duration.millis(delay), actionEvent -> actionPerformed())); assert ((ppipe != null && source == null) || (ppipe == null && source != null)); if (pumpPipe != null) pumpPipe.addSink(graph); if (sourceInSameThread != null) { if (source instanceof Graph) replayGraph((Graph) source); sourceInSameThread.addSink(graph); } //timer.setCoalesce(true); //timer.setRepeats(true); //timer.start(); timeline.setCycleCount(Timeline.INDEFINITE); String debugModule = System.getProperty("org.graphstream.debug"); new Thread(() -> { if (debugModule != null && !debugModule.isEmpty()) { // if debug is enable, add a delay to allow time for the interface to be created (some compilation require that) System.out.println("-- Debug Mode"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } timeline.play(); }).start(); } /** * Close definitively this viewer and all its views. */ public void close() { synchronized (views) { disableAutoLayout(); for (View view : views.values()) view.close(graph); timeline.stop(); //timer.removeActionListener(this); if (pumpPipe != null) pumpPipe.removeSink(graph); if (sourceInSameThread != null) sourceInSameThread.removeSink(graph); graph = null; pumpPipe = null; sourceInSameThread = null; timeline = null; } } @Override public GraphRenderer newDefaultGraphRenderer() { // TODO Auto-generated method stub return new FxGraphRenderer(); } /** * Build the default graph view and insert it. The view identifier is * {@link #DEFAULT_VIEW_ID}. You can request the view to be open in its own * frame. * * @param renderer * @param openInAFrame * It true, the view is placed in a frame, else the view is only * created and you must embed it yourself in your application. */ public View addDefaultView(boolean openInAFrame, GraphRenderer renderer) { synchronized (views) { View view = renderer.createDefaultView(this, getDefaultID()); addView(view); if (openInAFrame) view.openInAFrame(true); return view; } } /** * Called on a regular basis by the timer. Checks if some events occurred * from the graph pipe or from the layout pipe, and if the graph changed, * triggers a repaint. Never call this method, it is called by a UI Timer * automatically. */ public void actionPerformed() { synchronized (views) { // long t1=System.currentTimeMillis(); // long gsize1=graph.getNodeCount(); if (pumpPipe != null) pumpPipe.pump(); // long gsize2=graph.getNodeCount(); // long t2=System.currentTimeMillis(); if (layoutPipeIn != null) layoutPipeIn.pump(); // long t3=System.currentTimeMillis(); // Prevent the timer from using a empty graph to display if(graph != null){ boolean changed = graph.graphChangedFlag(); if (changed) { computeGraphMetrics(); // long t4=System.currentTimeMillis(); for (View view : views.values()) view.display(graph, changed); } // long t5=System.currentTimeMillis(); graph.resetGraphChangedFlag(); } // System.err.printf("display pump=%f layoutPump=%f metrics=%f // display=%f (size delta=%d size1=%d size2=%d)%n", // (t2-t1)/1000.0, (t3-t2)/1000.0, (t4-t3)/1000.0, (t5-t4)/1000.0, // (gsize2-gsize1), gsize1, gsize2); } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy