/* Copyright 2008-2010 Gephi Authors : Martin Škurla Website : http://www.gephi.org This file is part of Gephi. Gephi is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Gephi 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with Gephi. If not, see <http://www.gnu.org/licenses/>. */ package org.gephi.neo4j.plugin.impl; import java.awt.Color; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import org.gephi.graph.api.Edge; import org.gephi.graph.api.EdgeData; import org.gephi.graph.api.Graph; import org.gephi.graph.api.GraphController; import org.gephi.graph.api.NodeData; import org.gephi.graph.api.Renderable; import org.gephi.neo4j.plugin.api.Neo4jDelegateNodeDebugger; import org.gephi.neo4j.plugin.api.Neo4jVisualDebugger; import org.gephi.neo4j.plugin.api.NoMoreElementsException; import org.gephi.neo4j.plugin.impl.GraphModelImportConverter.Neo4jGraphModel; import org.neo4j.graphdb.Path; import org.openide.util.Lookup; import org.openide.util.lookup.ServiceProvider; /** * * @author Martin Škurla */ @ServiceProvider(service = Neo4jVisualDebugger.class) public class Neo4jVisualDebuggerImpl implements Neo4jVisualDebugger { private static final Color NOT_CUSTOM_COLOR = new Color(-1); private final List<org.gephi.graph.api.Node> previousNodes = new LinkedList<org.gephi.graph.api.Node>(); private final List<Edge> previousEdges = new LinkedList<Edge>(); private final List<Color> previousNodeColors = new LinkedList<Color>(); private final List<Color> previousEdgeColors = new LinkedList<Color>(); private Graph graph; private Iterator<Path> paths; private Neo4jGraphModel neo4jModel; private Path currentPath; private boolean finishedTraversal = false; @Override public void initialize() { this.neo4jModel = GraphModelImportConverter.getNeo4jModelForCurrentWorkspace(); this.graph = Lookup.getDefault().lookup(GraphController.class).getModel().getGraphVisible(); } @Override public void restore() { restorePreviousEdgesColors(); restorePreviousNodesColors(); finishedTraversal = true; } @Override public void nextStep(Neo4jDelegateNodeDebugger neo4jDelegateNodeDebugger) throws NoMoreElementsException { if (paths == null || finishedTraversal == true) { this.paths = neo4jDelegateNodeDebugger.paths(GraphModelImportConverter.getGraphDBForCurrentWorkspace()).iterator(); this.finishedTraversal = false; this.currentPath = null; } if (paths.hasNext()) { Path path = paths.next(); try { update(neo4jDelegateNodeDebugger, path); } catch (NoMoreElementsRuntimeException nmere) { restore(); throw new NoMoreElementsException(); } } else { restore(); throw new NoMoreElementsException(); } } @Override public void update(Neo4jDelegateNodeDebugger neo4jDelegateNodeDebugger) { if (paths == null || finishedTraversal == true) { this.paths = neo4jDelegateNodeDebugger.paths(GraphModelImportConverter.getGraphDBForCurrentWorkspace()).iterator(); this.finishedTraversal = false; this.currentPath = null; } try { update(neo4jDelegateNodeDebugger, currentPath); } catch (NoMoreElementsRuntimeException nmere) { throw new AssertionError(); } } private void update(Neo4jDelegateNodeDebugger neo4jDebugger, Path path) { restorePreviousNodesColors(); restorePreviousEdgesColors(); currentPath = path; applyCurrentNodesColors(neo4jDebugger); applyCurrentEdgesColors(neo4jDebugger); } private void restorePreviousNodesColors() { if (!previousNodes.isEmpty()) { for (int index = 0; index < previousNodes.size(); index++) { setColor(previousNodes.get(index).getNodeData(), previousNodeColors.get(index)); } previousNodes.clear(); previousNodeColors.clear(); } } private void restorePreviousEdgesColors() { if (!previousEdges.isEmpty()) { for (int index = 0; index < previousEdges.size(); index++) { setColor(previousEdges.get(index).getEdgeData(), previousEdgeColors.get(index)); } previousEdges.clear(); previousEdgeColors.clear(); } } private void applyCurrentNodesColors(Neo4jDelegateNodeDebugger neo4jDebugger) { if (neo4jDebugger.isShowNodes()) { if (currentPath != null) { for (org.neo4j.graphdb.Node neoNode : currentPath.nodes()) { int nodeId = neo4jModel.getNeo4jToGephiNodeMap().get(neoNode.getId()); org.gephi.graph.api.Node currentGephiNode = graph.getNode(nodeId); if (currentGephiNode == null) { try { nextStep(neo4jDebugger); } catch (NoMoreElementsException nmee) { throw new NoMoreElementsRuntimeException(); } } previousNodes.add(currentGephiNode); NodeData currentNodeData = currentGephiNode.getNodeData(); previousNodeColors.add(new Color(currentNodeData.r(), currentNodeData.g(), currentNodeData.b())); setColor(currentNodeData, neo4jDebugger.getNodesColor()); } } } } private void applyCurrentEdgesColors(Neo4jDelegateNodeDebugger neo4jDebugger) { if (neo4jDebugger.isShowRelationships()) { int nodeCount = previousNodes.size(); if (nodeCount > 1) { for (int index = 0; index < nodeCount - 1; index++) { org.gephi.graph.api.Node startNode = previousNodes.get(index); org.gephi.graph.api.Node endNode = previousNodes.get(index + 1); Edge edge1 = graph.getEdge(startNode, endNode); Edge edge2 = graph.getEdge(endNode, startNode); Edge currentEdge = (edge1 != null) ? edge1 : edge2; previousEdges.add(currentEdge); EdgeData currentEdgeData = currentEdge.getEdgeData(); // special feature in Gephi when R part of the RGB has value -1, it // means Edge does not have custom color if (currentEdgeData.r() != -1) { previousEdgeColors.add(new Color(currentEdgeData.r(), currentEdgeData.g(), currentEdgeData.b())); } else { previousEdgeColors.add(NOT_CUSTOM_COLOR); } setColor(currentEdgeData, neo4jDebugger.getRelationshipsColor()); } } } } private void setColor(Renderable renderable, Color color) { if (color != NOT_CUSTOM_COLOR) { float[] rgbColorComponents = color.getRGBColorComponents(null); renderable.setR(rgbColorComponents[0]); renderable.setG(rgbColorComponents[1]); renderable.setB(rgbColorComponents[2]); } else { renderable.setR(-1); renderable.setG(0); renderable.setB(0); } } private class NoMoreElementsRuntimeException extends RuntimeException { } }