/* 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.io.BufferedReader; import java.io.LineNumberReader; import java.io.Reader; import java.util.StringTokenizer; import org.gephi.io.importer.api.ContainerLoader; 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; /** * * @author Mathieu Bastian */ public class ImporterPajek implements FileImporter, LongTask { //Architecture private Reader reader; private LineNumberReader lineReader; private ContainerLoader container; private Report report; private ProgressTicket progressTicket; private boolean cancel = false; //Node data private NodeDraft[] verticesArray; public boolean execute(ContainerLoader container) { this.container = container; this.report = new Report(); 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); //Progress try { // ignore everything until we see '*Vertices' String curLine = skip(reader, "*vertices"); if (curLine == null) // no vertices in the graph; return empty graph { report.logIssue(new Issue(NbBundle.getMessage(ImporterPajek.class, "importerNET_error_dataformat1"), Issue.Level.CRITICAL)); } // create appropriate number of vertices StringTokenizer stringTokenizer = new StringTokenizer(curLine); stringTokenizer.nextToken(); // skip past "*vertices"; int num_vertices = Integer.parseInt(stringTokenizer.nextToken()); Progress.switchToDeterminate(progressTicket, num_vertices); //Progress verticesArray = new NodeDraft[num_vertices]; for (int i = 0; i < num_vertices; i++) { NodeDraft node = container.factory().newNodeDraft(); String label = "" + (i + 1); node.setId(label); node.setLabel(label); verticesArray[i] = node; } curLine = null; while (reader.ready()) { if (cancel) { reader.close(); return; } curLine = reader.readLine(); if (curLine == null || curLine.startsWith("*")) { break; } if (curLine.isEmpty()) { // skip blank lines report.logIssue(new Issue(NbBundle.getMessage(ImporterPajek.class, "importerNET_error_dataformat2", reader.getLineNumber()), Issue.Level.WARNING)); continue; } try { readVertex(curLine, num_vertices); } catch (IllegalArgumentException iae) { reader.close(); throw iae; } Progress.progress(progressTicket); } //Append nodes for (NodeDraft node : verticesArray) { container.addNode(node); } //Get arcs curLine = readArcsOrEdges(curLine, reader); //Get edges readArcsOrEdges(curLine, reader); reader.close(); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException(e); } Progress.finish(progressTicket); } private void readVertex(String curLine, int num_vertices) throws Exception { String[] parts = null; int firstParts = -1; // index of first coordinate in parts; -1 indicates no coordinates found String index; String label = null; // if there are quote marks on this line, split on them; label is surrounded by them if (curLine.indexOf('"') != -1) { String[] initial_split = curLine.trim().split("\""); // if there are any quote marks, there should be exactly 2 if (initial_split.length < 1 || initial_split.length > 3) { report.logIssue(new Issue(NbBundle.getMessage(ImporterPajek.class, "importerNET_error_dataformat3", lineReader.getLineNumber()), Issue.Level.SEVERE)); } index = initial_split[0].trim(); if (initial_split.length > 1) { label = initial_split[1].trim(); } if (initial_split.length == 3) { parts = initial_split[2].trim().split("\\s+", -1); } firstParts = 0; } else // no quote marks, but are there coordinates? { parts = curLine.trim().split("\\s+", -1); index = parts[0]; switch (parts.length) { case 1: // just the ID; nothing to do, continue break; case 2: // just the ID and a label label = parts[1]; break; case 3: // ID, no label, coordinates firstParts = 1; break; case 4: // ID, label, (x,y) coordinates firstParts = 2; break; } } int v_id = Integer.parseInt(index) - 1; // go from 1-based to 0-based index if (v_id >= num_vertices || v_id < 0) { report.logIssue(new Issue(NbBundle.getMessage(ImporterPajek.class, "importerNET_error_dataformat4", v_id, num_vertices), Issue.Level.SEVERE)); } NodeDraft node = verticesArray[v_id]; // only attach the label if there's one to attach if (label != null && label.length() > 0) { node.setLabel(label); } // parse the rest of the line if (firstParts != -1 && parts != null && parts.length >= firstParts + 2) { for (int i = firstParts; i < parts.length; i++) { //Coordinates if (i < parts.length - 1) { try { float x = Float.parseFloat(parts[i]); float y = Float.parseFloat(parts[i + 1]); node.setX(x); node.setY(y); i++; } catch (Exception e) { report.logIssue(new Issue(NbBundle.getMessage(ImporterPajek.class, "importerNET_error_dataformat5", lineReader.getLineNumber()), Issue.Level.WARNING)); } } if (parts[i].equals("ic")) { } } } } private String readArcsOrEdges(String curLine, BufferedReader br) throws Exception { String nextLine = curLine; boolean reading_arcs = false; boolean reading_edges = false; if (nextLine.toLowerCase().startsWith("*arcs")) { reading_arcs = true; } else if (nextLine.toLowerCase().startsWith("*edges")) { reading_edges = true; } if (!(reading_arcs || reading_edges)) { return nextLine; } boolean is_list = false; if (nextLine.toLowerCase().endsWith("list")) { is_list = true; } while (br.ready()) { if (cancel) { return nextLine; } nextLine = br.readLine(); if (nextLine == null || nextLine.startsWith("*")) { break; } if (nextLine.equals("")) { // skip blank lines report.logIssue(new Issue(NbBundle.getMessage(ImporterPajek.class, "importerNET_error_dataformat2", lineReader.getLineNumber()), Issue.Level.WARNING)); continue; } StringTokenizer st = new StringTokenizer(nextLine.trim()); int vid1 = Integer.parseInt(st.nextToken()) - 1; NodeDraft nodeFrom = verticesArray[vid1]; if (is_list) // one source, multiple destinations { do { int vid2 = Integer.parseInt(st.nextToken()) - 1; NodeDraft nodeTo = verticesArray[vid2]; EdgeDraft edge = container.factory().newEdgeDraft(); edge.setSource(nodeFrom); edge.setTarget(nodeTo); container.addEdge(edge); } while (st.hasMoreTokens()); } else // one source, one destination, at most one weight { int vid2 = Integer.parseInt(st.nextToken()) - 1; NodeDraft nodeTo = verticesArray[vid2]; EdgeDraft edge = container.factory().newEdgeDraft(); edge.setSource(nodeFrom); edge.setTarget(nodeTo); // get the edge weight if we care if (st.hasMoreTokens()) { float edgeWeight = 1f; try { edgeWeight = new Float(st.nextToken()); } catch (Exception e) { report.logIssue(new Issue(NbBundle.getMessage(ImporterPajek.class, "importerNET_error_dataformat5", lineReader.getLineNumber()), Issue.Level.WARNING)); } edge.setWeight(edgeWeight); } container.addEdge(edge); } } return nextLine; } private String skip(BufferedReader br, String str) throws Exception { while (br.ready()) { String curLine = br.readLine(); if (curLine == null) { break; } curLine = curLine.trim(); if (curLine.toLowerCase().startsWith(str)) { return curLine; } } return null; } public boolean cancel() { cancel = true; return true; } public void setReader(Reader reader) { this.reader = reader; } public ContainerLoader getContainer() { return container; } public Report getReport() { return report; } public void setProgressTicket(ProgressTicket progressTicket) { this.progressTicket = progressTicket; } }