From f7e401d981ce4eb68a63f2d29ca69132392bd2c7 Mon Sep 17 00:00:00 2001
From: David Bohn <davbohn@googlemail.com>
Date: Fri, 8 Jul 2016 21:23:44 +0200
Subject: [PATCH] Implemented functionality to handle node click

---
 .../configurations/AbstractConfiguration.java | 31 +++++++++
 .../configurations/GephiConfiguration.java    | 64 +++----------------
 .../configurations/internal/GephiLoader.java  | 50 +++++++++++++++
 .../internal/NodeClickHandler.java            | 12 ++++
 .../java/fucoin/gui/gephi/GraphWindow.java    | 34 +++++++++-
 .../gui/gephi/MouseListenerTemplate.java      | 13 ++--
 .../fucoin/gui/gephi/NodeMouseListener.java   | 10 +++
 7 files changed, 149 insertions(+), 65 deletions(-)
 create mode 100644 src/main/java/fucoin/configurations/internal/GephiLoader.java
 create mode 100644 src/main/java/fucoin/configurations/internal/NodeClickHandler.java
 create mode 100644 src/main/java/fucoin/gui/gephi/NodeMouseListener.java

diff --git a/src/main/java/fucoin/configurations/AbstractConfiguration.java b/src/main/java/fucoin/configurations/AbstractConfiguration.java
index 07fcb48..2672665 100644
--- a/src/main/java/fucoin/configurations/AbstractConfiguration.java
+++ b/src/main/java/fucoin/configurations/AbstractConfiguration.java
@@ -5,6 +5,7 @@ import akka.actor.Props;
 import akka.pattern.Patterns;
 import akka.util.Timeout;
 import fucoin.AbstractNode;
+import fucoin.actions.control.ActionAddOverlayNeighbours;
 import fucoin.actions.control.ActionAnnounceWalletCreation;
 import fucoin.actions.control.ActionWalletSendMoney;
 import fucoin.actions.join.ActionTellSupervisor;
@@ -14,6 +15,8 @@ import fucoin.actions.transaction.ActionNotifyObserver;
 import fucoin.configurations.internal.ConfigurationCreator;
 import fucoin.supervisor.SuperVisorImpl;
 import fucoin.wallet.WalletImpl;
+import org.gephi.graph.api.Edge;
+import org.gephi.graph.api.Graph;
 import org.gephi.graph.api.Node;
 import scala.concurrent.Await;
 import scala.concurrent.Future;
@@ -21,6 +24,7 @@ import scala.concurrent.duration.Duration;
 
 import java.util.*;
 import java.util.concurrent.ThreadLocalRandom;
+import java.util.stream.Collectors;
 
 /**
  *
@@ -192,4 +196,31 @@ public abstract class AbstractConfiguration extends AbstractNode {
     }
 
     public abstract void run();
+
+    protected void createOverlayNetwork(Graph g) {
+        Collection<Node> nodes = g.getNodes().toCollection();
+
+        try {
+            spawnWalletsFromNodes(nodes, false);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+
+        nodes.stream().forEach(node -> {
+            ActorRef wallet = walletByName(node.getLabel());
+            Edge[] edges = g.getEdges(node).toArray();
+
+            // Search for all reachable neighbours of the node
+            // by filtering the list of incident edges of the node
+            // and retrieve the respective ActorRef instance
+            List<ActorRef> overlayNeighbours = Arrays.stream(edges).filter(edge -> !edge.isDirected() || edge.getSource() == node).map(edge -> {
+                if (edge.getSource() == node) {
+                    return edge.getTarget();
+                }
+                return edge.getSource();
+            }).map(target -> walletByName(target.getLabel())).collect(Collectors.toList());
+
+            wallet.tell(new ActionAddOverlayNeighbours(overlayNeighbours), self());
+        });
+    }
 }
diff --git a/src/main/java/fucoin/configurations/GephiConfiguration.java b/src/main/java/fucoin/configurations/GephiConfiguration.java
index cc01d89..0e035f1 100644
--- a/src/main/java/fucoin/configurations/GephiConfiguration.java
+++ b/src/main/java/fucoin/configurations/GephiConfiguration.java
@@ -1,25 +1,12 @@
 package fucoin.configurations;
 
-import akka.actor.ActorRef;
-import fucoin.actions.control.ActionAddOverlayNeighbours;
 import fucoin.configurations.internal.ConfigurationName;
+import fucoin.configurations.internal.GephiLoader;
 import fucoin.gui.gephi.GraphWindow;
-import org.gephi.graph.api.Edge;
 import org.gephi.graph.api.Graph;
-import org.gephi.graph.api.GraphController;
-import org.gephi.graph.api.Node;
-import org.gephi.io.importer.api.Container;
-import org.gephi.io.importer.api.ImportController;
-import org.gephi.io.processor.plugin.DefaultProcessor;
-import org.gephi.project.api.ProjectController;
-import org.gephi.project.api.Workspace;
-import org.openide.util.Lookup;
 
-import java.io.File;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.List;
-import java.util.stream.Collectors;
+import java.io.FileNotFoundException;
+import java.net.URISyntaxException;
 
 @ConfigurationName("Gephi Test Configuration")
 public class GephiConfiguration extends AbstractConfiguration {
@@ -27,51 +14,20 @@ public class GephiConfiguration extends AbstractConfiguration {
     public void run() {
         initSupervisor();
 
-        ProjectController pc = Lookup.getDefault().lookup(ProjectController.class);
+        GephiLoader gephiLoader = new GephiLoader();
 
-        pc.newProject();
-        Workspace workspace = pc.getCurrentWorkspace();
-
-        Container container;
-        ImportController importController = Lookup.getDefault().lookup(ImportController.class);
+        Graph g;
         try {
-            File file = new File(getClass().getResource("/topology2.gexf").toURI());
-            container = importController.importFile(file);
-        } catch (Exception ex) {
-            ex.printStackTrace();
-            return;
-        }
-
-        importController.process(container, new DefaultProcessor(), workspace);
-
-        Graph g = Lookup.getDefault().lookup(GraphController.class).getGraphModel(workspace).getGraph();
-
-        Collection<Node> nodes = g.getNodes().toCollection();
-
-        try {
-            spawnWalletsFromNodes(nodes, false);
-        } catch (Exception e) {
+            g = gephiLoader.loadFileFromResources("/topology2.gexf");
+        } catch (URISyntaxException | FileNotFoundException e) {
             e.printStackTrace();
+            return;
         }
 
-        nodes.stream().forEach(node -> {
-            ActorRef wallet = walletByName(node.getLabel());
-            Edge[] edges = g.getEdges(node).toArray();
-
-            // Search for all reachable neighbours of the node
-            // by filtering the list of incident edges of the node
-            // and retrieve the respective ActorRef instance
-            List<ActorRef> overlayNeighbours = Arrays.stream(edges).filter(edge -> !edge.isDirected() || edge.getSource() == node).map(edge -> {
-                if (edge.getSource() == node) {
-                    return edge.getTarget();
-                }
-                return edge.getSource();
-            }).map(target -> walletByName(target.getLabel())).collect(Collectors.toList());
-
-            wallet.tell(new ActionAddOverlayNeighbours(overlayNeighbours), self());
-        });
+        createOverlayNetwork(g);
 
         GraphWindow graphWindow = new GraphWindow();
+        graphWindow.addNodeClickHandler((node, event) -> System.out.println(node.getLabel() + " wurde angeklickt!"));
 
         graphWindow.setVisible(true);
     }
diff --git a/src/main/java/fucoin/configurations/internal/GephiLoader.java b/src/main/java/fucoin/configurations/internal/GephiLoader.java
new file mode 100644
index 0000000..67f1644
--- /dev/null
+++ b/src/main/java/fucoin/configurations/internal/GephiLoader.java
@@ -0,0 +1,50 @@
+package fucoin.configurations.internal;
+
+import org.gephi.graph.api.Graph;
+import org.gephi.graph.api.GraphController;
+import org.gephi.graph.api.Node;
+import org.gephi.io.importer.api.Container;
+import org.gephi.io.importer.api.ImportController;
+import org.gephi.io.processor.plugin.DefaultProcessor;
+import org.gephi.project.api.ProjectController;
+import org.gephi.project.api.Workspace;
+import org.openide.util.Lookup;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.Collection;
+
+/**
+ * @author davidbohn
+ */
+public class GephiLoader {
+
+    Workspace workspace;
+
+    public Graph loadFileFromResources(String path) throws URISyntaxException, FileNotFoundException {
+        return loadFile(getClass().getResource(path).toURI());
+    }
+
+    public Graph loadFile(URI filename) throws FileNotFoundException {
+        ProjectController pc = Lookup.getDefault().lookup(ProjectController.class);
+
+        pc.newProject();
+        workspace = pc.getCurrentWorkspace();
+
+        Container container;
+        ImportController importController = Lookup.getDefault().lookup(ImportController.class);
+        File file = new File(filename);
+        container = importController.importFile(file);
+
+
+        importController.process(container, new DefaultProcessor(), workspace);
+
+        return Lookup.getDefault().lookup(GraphController.class).getGraphModel(workspace).getGraph();
+    }
+
+    public Workspace getWorkspace() {
+        return workspace;
+    }
+}
diff --git a/src/main/java/fucoin/configurations/internal/NodeClickHandler.java b/src/main/java/fucoin/configurations/internal/NodeClickHandler.java
new file mode 100644
index 0000000..01a207c
--- /dev/null
+++ b/src/main/java/fucoin/configurations/internal/NodeClickHandler.java
@@ -0,0 +1,12 @@
+package fucoin.configurations.internal;
+
+import org.gephi.graph.api.Node;
+import org.gephi.preview.api.PreviewMouseEvent;
+
+import java.util.function.BiConsumer;
+
+/**
+ * @author davidbohn
+ */
+public interface NodeClickHandler extends BiConsumer<Node, PreviewMouseEvent> {
+}
diff --git a/src/main/java/fucoin/gui/gephi/GraphWindow.java b/src/main/java/fucoin/gui/gephi/GraphWindow.java
index e2d1a85..d4e1a20 100644
--- a/src/main/java/fucoin/gui/gephi/GraphWindow.java
+++ b/src/main/java/fucoin/gui/gephi/GraphWindow.java
@@ -1,14 +1,24 @@
 package fucoin.gui.gephi;
 
+import fucoin.configurations.internal.NodeClickHandler;
+import org.gephi.graph.api.Node;
 import org.gephi.preview.api.*;
 import org.gephi.preview.types.DependantOriginalColor;
+import org.gephi.project.api.Workspace;
 import org.openide.util.Lookup;
 
 import javax.swing.*;
 import java.awt.*;
 import java.lang.reflect.Field;
+import java.util.*;
+import java.util.List;
+
+public class GraphWindow extends JFrame implements NodeMouseListener {
+
+    protected List<NodeClickHandler> clickHandlers = new ArrayList<>();
+    private final PreviewController previewController;
+    private final PreviewSketch previewSketch;
 
-public class GraphWindow extends JFrame {
     public GraphWindow() {
         super();
 
@@ -16,7 +26,7 @@ public class GraphWindow extends JFrame {
 
         setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
 
-        PreviewController previewController = Lookup.getDefault().lookup(PreviewController.class);
+        previewController = Lookup.getDefault().lookup(PreviewController.class);
         PreviewModel previewModel = previewController.getModel();
         previewModel.getProperties().putValue(PreviewProperty.SHOW_NODE_LABELS, Boolean.TRUE);
         previewModel.getProperties().putValue(PreviewProperty.NODE_LABEL_COLOR, new DependantOriginalColor(Color.BLACK));
@@ -26,9 +36,10 @@ public class GraphWindow extends JFrame {
         previewModel.getProperties().putValue(PreviewProperty.EDGE_CURVED, Boolean.FALSE);
         previewModel.getProperties().putValue(PreviewProperty.EDGE_OPACITY, 50);
         previewModel.getProperties().putValue(PreviewProperty.EDGE_RADIUS, 10f);
+        previewModel.getProperties().putValue("graphWindow.mouse.handler", this);
 
         G2DTarget target = (G2DTarget) previewController.getRenderTarget(RenderTarget.G2D_TARGET);
-        PreviewSketch previewSketch = new PreviewSketch(target, isRetina());
+        previewSketch = new PreviewSketch(target, isRetina());
 
         this.add(previewSketch, BorderLayout.CENTER);
 
@@ -58,4 +69,21 @@ public class GraphWindow extends JFrame {
         }
         return false;
     }
+
+    @Override
+    public void mouseClicked(Node node, PreviewMouseEvent event, PreviewProperties properties, Workspace workspace) {
+        clickHandlers.stream().forEach(nodeClickHandler -> nodeClickHandler.accept(node, event));
+    }
+
+    public void addNodeClickHandler(NodeClickHandler handler) {
+        clickHandlers.add(handler);
+    }
+
+    @Override
+    public void setVisible(boolean b) {
+        super.setVisible(b);
+
+        previewController.refreshPreview();
+        previewSketch.repaint();
+    }
 }
diff --git a/src/main/java/fucoin/gui/gephi/MouseListenerTemplate.java b/src/main/java/fucoin/gui/gephi/MouseListenerTemplate.java
index 99af506..5e5d39a 100644
--- a/src/main/java/fucoin/gui/gephi/MouseListenerTemplate.java
+++ b/src/main/java/fucoin/gui/gephi/MouseListenerTemplate.java
@@ -9,23 +9,20 @@ import org.gephi.project.api.Workspace;
 import org.openide.util.Lookup;
 import org.openide.util.lookup.ServiceProvider;
 
-import javax.swing.*;
-
 @ServiceProvider(service = PreviewMouseListener.class)
 public class MouseListenerTemplate implements PreviewMouseListener {
     @Override
     public void mouseClicked(PreviewMouseEvent event, PreviewProperties properties, Workspace workspace) {
         for (Node node : Lookup.getDefault().lookup(GraphController.class).getGraphModel(workspace).getGraph().getNodes()) {
             if (clickingInNode(node, event)) {
-                properties.putValue("display-label.node.id", node.getId());
-                System.err.println("Node " + node.getLabel() + " clicked!");//System.out is ignored in Netbeans platform applications!!
-                JOptionPane.showMessageDialog(null, "Node " + node.getLabel() + " clicked!");
-                event.setConsumed(true);//So the renderer is executed and the graph repainted
+                if (properties.hasProperty("graphWindow.mouse.handler")) {
+                    NodeMouseListener listener = properties.getValue("graphWindow.mouse.handler");
+                    listener.mouseClicked(node, event, properties, workspace);
+                }
+                event.setConsumed(true);
                 return;
             }
         }
-
-        properties.removeSimpleValue("display-label.node.id");
         event.setConsumed(true);//So the renderer is executed and the graph repainted
     }
 
diff --git a/src/main/java/fucoin/gui/gephi/NodeMouseListener.java b/src/main/java/fucoin/gui/gephi/NodeMouseListener.java
new file mode 100644
index 0000000..348028b
--- /dev/null
+++ b/src/main/java/fucoin/gui/gephi/NodeMouseListener.java
@@ -0,0 +1,10 @@
+package fucoin.gui.gephi;
+
+import org.gephi.graph.api.Node;
+import org.gephi.preview.api.PreviewMouseEvent;
+import org.gephi.preview.api.PreviewProperties;
+import org.gephi.project.api.Workspace;
+
+public interface NodeMouseListener {
+    public void mouseClicked(Node node, PreviewMouseEvent event, PreviewProperties properties, Workspace workspace);
+}
-- 
GitLab