/*
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.importer.plugin.file;
import java.awt.Color;
import java.io.IOException;
import java.io.LineNumberReader;
import java.io.Reader;
import java.io.StreamTokenizer;
import java.util.ArrayList;
import org.gephi.data.attributes.api.AttributeTable;
import org.gephi.data.attributes.api.AttributeColumn;
import org.gephi.data.attributes.api.AttributeType;
import org.gephi.io.importer.api.ContainerLoader;
import org.gephi.io.importer.api.EdgeDefault;
import org.gephi.io.importer.api.EdgeDraft;
import org.gephi.io.importer.api.ImportUtils;
import org.gephi.io.importer.api.Issue;
import org.gephi.io.importer.api.NodeDraft;
import org.gephi.io.importer.api.Report;
import org.gephi.io.importer.spi.FileImporter;
import org.gephi.utils.longtask.spi.LongTask;
import org.gephi.utils.progress.Progress;
import org.gephi.utils.progress.ProgressTicket;
import org.openide.util.NbBundle;
//Inspired from infovis.graph.io;
//Original author Jean-Daniel Fekete
public class ImporterGML implements FileImporter, LongTask {
//Architecture
private Reader reader;
private ContainerLoader container;
private Report report;
private ProgressTicket progressTicket;
private boolean cancel = false;
public boolean execute(ContainerLoader container) {
this.container = container;
this.report = new Report();
LineNumberReader lineReader = ImportUtils.getTextReader(reader);
try {
importData(lineReader);
} catch (Exception e) {
throw new RuntimeException(e);
}
return !cancel;
}
private void importData(LineNumberReader reader) throws Exception {
Progress.start(progressTicket);
ArrayList list;
StreamTokenizer tokenizer = new StreamTokenizer(reader);
tokenizer.ordinaryChar('[');
tokenizer.ordinaryChar(']');
tokenizer.wordChars('_', '_');
list = parseList(tokenizer);
boolean ret = false;
for (int i = 0; i < list.size(); i++) {
if ("graph".equals(list.get(i)) && list.size() >= i + 2 && list.get(i + 1) instanceof ArrayList) {
ret = parseGraph((ArrayList) list.get(i + 1));
}
}
if (!ret) {
report.logIssue(new Issue(NbBundle.getMessage(ImporterGML.class, "importerGML_error_badparsing"), Issue.Level.SEVERE));
}
Progress.finish(progressTicket);
}
private ArrayList parseList(StreamTokenizer tokenizer) throws IOException {
ArrayList list = new ArrayList();
loop:
while (true) {
int t = tokenizer.nextToken();
if (t == ']' || t == StreamTokenizer.TT_EOF) {
return list;
} else if (t != StreamTokenizer.TT_WORD) {
break;
}
String key = tokenizer.sval;
list.add(key);
t = tokenizer.nextToken();
switch (t) {
case '[':
list.add(parseList(tokenizer));
break;
case StreamTokenizer.TT_NUMBER:
list.add(new Double(tokenizer.nval));
break;
case StreamTokenizer.TT_WORD:
case '"':
list.add(tokenizer.sval);
break;
default:
break loop;
}
}
report.logIssue(new Issue(NbBundle.getMessage(ImporterGML.class, "importerGML_error_listtoken", tokenizer.lineno()), Issue.Level.SEVERE));
return list;
}
private boolean parseGraph(ArrayList list) {
if ((list.size() & 1) != 0) {
return false;
}
Progress.switchToDeterminate(progressTicket, list.size());
boolean ret = true;
for (int i = 0; i < list.size(); i += 2) {
Object key = list.get(i);
Object value = list.get(i + 1);
if ("node".equals(key)) {
ret = parseNode((ArrayList) value);
} else if ("edge".equals(key)) {
ret = parseEdge((ArrayList) value);
} else if ("directed".equals(key)) {
if (value instanceof Double) {
EdgeDefault edgeDefault = ((Double) value) == 1 ? EdgeDefault.DIRECTED : EdgeDefault.UNDIRECTED;
container.setEdgeDefault(edgeDefault);
} else {
report.logIssue(new Issue(NbBundle.getMessage(ImporterGML.class, "importerGML_error_directedgraphparse"), Issue.Level.WARNING));
}
} else {
}
if (!ret) {
break;
}
if (cancel) {
break;
}
Progress.progress(progressTicket);
}
return ret;
}
private boolean parseNode(ArrayList list) {
NodeDraft node = container.factory().newNodeDraft();
String id = null;
for (int i = 0; i < list.size(); i += 2) {
String key = (String) list.get(i);
Object value = list.get(i + 1);
if ("id".equals(key)) {
id = value.toString();
node.setId(id);
} else if ("label".equals(key)) {
String label = value.toString();
node.setLabel(label);
}
}
if (id == null) {
report.logIssue(new Issue(NbBundle.getMessage(ImporterGML.class, "importerGML_error_nodeidmissing"), Issue.Level.WARNING));
}
boolean ret = addNodeAttributes(node, "", list);
container.addNode(node);
return ret;
}
private boolean addNodeAttributes(NodeDraft node, String prefix, ArrayList list) {
boolean ret = true;
for (int i = 0; i < list.size(); i += 2) {
String key = (String) list.get(i);
Object value = list.get(i + 1);
if ("id".equals(key) || "label".equals(key)) {
continue; // already parsed
}
if (value instanceof ArrayList) {
// keep the hierarchy
ret = addNodeAttributes(node, prefix + "." + key, (ArrayList) value);
if (!ret) {
break;
}
} else if ("x".equals(key) && value instanceof Double) {
node.setX(((Double) value).floatValue());
} else if ("y".equals(key) && value instanceof Double) {
node.setY(((Double) value).floatValue());
} else if ("z".equals(key) && value instanceof Double) {
node.setZ(((Double) value).floatValue());
} else if ("w".equals(key) && value instanceof Double) {
node.setSize(((Double) value).floatValue());
} else if ("h".equals(key)) {
} else if ("fill".equals(key)) {
int colorHex = -1;
if (value instanceof String) {
String str = ((String) value).trim().replace("#", "");
try {
colorHex = Integer.valueOf(str, 16).intValue();
} catch (Exception e) {
}
}
if (colorHex != -1) {
node.setColor(new Color(colorHex));
}
} else {
AttributeTable nodeClass = container.getAttributeModel().getNodeTable();
AttributeColumn column = null;
if ((column = nodeClass.getColumn(key)) == null) {
column = nodeClass.addColumn(key, AttributeType.STRING);
report.log("Node attribute " + column.getTitle() + " (" + column.getType() + ")");
}
node.addAttributeValue(column, value.toString());
}
}
return ret;
}
private boolean parseEdge(ArrayList list) {
EdgeDraft edgeDraft = container.factory().newEdgeDraft();
for (int i = 0; i < list.size(); i += 2) {
String key = (String) list.get(i);
Object value = list.get(i + 1);
if ("source".equals(key)) {
NodeDraft source = container.getNode(value.toString());
edgeDraft.setSource(source);
} else if ("target".equals(key)) {
NodeDraft target = container.getNode(value.toString());
edgeDraft.setTarget(target);
} else if ("value".equals(key)) {
if (value instanceof Double) {
edgeDraft.setWeight(((Double) value).floatValue());
}
} else if ("label".equals(key)) {
edgeDraft.setLabel(value.toString());
}
}
boolean ret = addEdgeAttributes(edgeDraft, "", list);
container.addEdge(edgeDraft);
return ret;
}
private boolean addEdgeAttributes(EdgeDraft edge, String prefix, ArrayList list) {
boolean ret = true;
for (int i = 0; i < list.size(); i += 2) {
String key = (String) list.get(i);
Object value = list.get(i + 1);
if ("source".equals(key) || "target".equals(key) || "value".equals(key) || "label".equals(key)) {
continue; // already parsed
}
if (value instanceof ArrayList) {
// keep the hierarchy
ret = addEdgeAttributes(edge, prefix + "." + key, (ArrayList) value);
if (!ret) {
break;
}
} else if ("directed".equals(key)) {
if (value instanceof Double) {
EdgeDraft.EdgeType type = ((Double) value) == 1 ? EdgeDraft.EdgeType.DIRECTED : EdgeDraft.EdgeType.UNDIRECTED;
edge.setType(type);
} else {
report.logIssue(new Issue(NbBundle.getMessage(ImporterGML.class, "importerGML_error_directedparse", edge.toString()), Issue.Level.WARNING));
}
} else {
AttributeTable edgeClass = container.getAttributeModel().getEdgeTable();
AttributeColumn column = null;
if ((column = edgeClass.getColumn(key)) == null) {
column = edgeClass.addColumn(key, AttributeType.STRING);
report.log("Edge attribute " + column.getTitle() + " (" + column.getType() + ")");
}
edge.addAttributeValue(column, value.toString());
}
}
return ret;
}
public void setReader(Reader reader) {
this.reader = reader;
}
public ContainerLoader getContainer() {
return container;
}
public Report getReport() {
return report;
}
public boolean cancel() {
cancel = true;
return true;
}
public void setProgressTicket(ProgressTicket progressTicket) {
this.progressTicket = progressTicket;
}
}