/*
Copyright 2008-2010 Gephi
Authors : Mathieu Bastian <mathieu.bastian@gephi.org>
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.io.processor.plugin;
import java.util.HashMap;
import java.util.Map;
import org.gephi.data.attributes.api.AttributeController;
import org.gephi.data.properties.PropertiesColumn;
import org.gephi.dynamic.api.DynamicController;
import org.gephi.dynamic.api.DynamicModel.TimeFormat;
import org.gephi.graph.api.Edge;
import org.gephi.graph.api.GraphController;
import org.gephi.graph.api.GraphFactory;
import org.gephi.graph.api.GraphModel;
import org.gephi.graph.api.HierarchicalGraph;
import org.gephi.graph.api.Node;
import org.gephi.io.importer.api.EdgeDraft.EdgeType;
import org.gephi.io.importer.api.EdgeDraftGetter;
import org.gephi.io.importer.api.NodeDraftGetter;
import org.gephi.io.processor.spi.Processor;
import org.gephi.project.api.ProjectController;
import org.openide.util.Lookup;
import org.openide.util.NbBundle;
import org.openide.util.lookup.ServiceProvider;
/**
* Processor 'Append graph' that tries to find in the current workspace nodes and
* edges in the container to only append new elements. It uses elements' id and
* label to do the matching.
* <p>
* The attibutes are not merged and values are from the latest element imported.
*
* @author Mathieu Bastian
*/
@ServiceProvider(service = Processor.class)
public class AppendProcessor extends AbstractProcessor implements Processor {
public String getDisplayName() {
return NbBundle.getMessage(AppendProcessor.class, "AppendProcessor.displayName");
}
public void process() {
ProjectController pc = Lookup.getDefault().lookup(ProjectController.class);
//Workspace
if (workspace == null) {
workspace = pc.getCurrentWorkspace();
if (workspace == null) {
//Append mode but no workspace
workspace = pc.newWorkspace(pc.getCurrentProject());
pc.openWorkspace(workspace);
}
}
if (container.getSource() != null) {
pc.setSource(workspace, container.getSource());
}
//Architecture
GraphModel graphModel = Lookup.getDefault().lookup(GraphController.class).getModel();
HierarchicalGraph graph = null;
switch (container.getEdgeDefault()) {
case DIRECTED:
graph = graphModel.getHierarchicalDirectedGraph();
break;
case UNDIRECTED:
graph = graphModel.getHierarchicalUndirectedGraph();
break;
case MIXED:
graph = graphModel.getHierarchicalMixedGraph();
break;
default:
graph = graphModel.getHierarchicalMixedGraph();
break;
}
GraphFactory factory = graphModel.factory();
//Attributes - Creates columns for properties
attributeModel = Lookup.getDefault().lookup(AttributeController.class).getModel();
attributeModel.mergeModel(container.getAttributeModel());
//Dynamic
if (container.getTimeFormat() != null) {
DynamicController dynamicController = Lookup.getDefault().lookup(DynamicController.class);
dynamicController.setTimeFormat(container.getTimeFormat());
}
//Index existing graph
Map<String, Node> map = new HashMap<String, Node>();
for (Node n : graph.getNodes()) {
String id = n.getNodeData().getId();
if (id != null && !id.equalsIgnoreCase(String.valueOf(n.getId()))) {
map.put(id, n);
}
if (n.getNodeData().getLabel() != null && !n.getNodeData().getLabel().isEmpty()) {
map.put(n.getNodeData().getLabel(), n);
}
}
int nodeCount = 0;
//Create all nodes
for (NodeDraftGetter draftNode : container.getNodes()) {
Node n;
String id = draftNode.getId();
String label = draftNode.getLabel();
if (!draftNode.isAutoId() && id != null && map.get(id) != null) {
n = map.get(id);
} else if (label != null && map.get(label) != null) {
n = map.get(label);
} else {
n = factory.newNode(draftNode.isAutoId()?null:id);
nodeCount++;
}
flushToNode(draftNode, n);
draftNode.setNode(n);
}
//Push nodes in data structure
for (NodeDraftGetter draftNode : container.getNodes()) {
Node n = draftNode.getNode();
NodeDraftGetter[] parents = draftNode.getParents();
if (parents != null) {
for (int i = 0; i < parents.length; i++) {
Node parent = parents[i].getNode();
graph.addNode(n, parent);
}
} else {
graph.addNode(n);
}
}
//Create all edges and push to data structure
int edgeCount = 0;
for (EdgeDraftGetter edge : container.getEdges()) {
Node source = edge.getSource().getNode();
Node target = edge.getTarget().getNode();
if (graph.getEdge(source, target) == null) {
Edge e = null;
switch (container.getEdgeDefault()) {
case DIRECTED:
e = factory.newEdge(edge.isAutoId()?null:edge.getId(), source, target, edge.getWeight(), true);
break;
case UNDIRECTED:
e = factory.newEdge(edge.isAutoId()?null:edge.getId(), source, target, edge.getWeight(), false);
break;
case MIXED:
e = factory.newEdge(edge.isAutoId()?null:edge.getId(), source, target, edge.getWeight(), edge.getType().equals(EdgeType.UNDIRECTED) ? false : true);
break;
}
flushToEdge(edge, e);
edgeCount++;
graph.addEdge(e);
}
}
System.out.println("# New Nodes appended: " + nodeCount + "\n# New Edges appended: " + edgeCount);
workspace = null;
}
}