001/* 002 * Copyright 2006 - 2013 003 * Stefan Balev <stefan.balev@graphstream-project.org> 004 * Julien Baudry <julien.baudry@graphstream-project.org> 005 * Antoine Dutot <antoine.dutot@graphstream-project.org> 006 * Yoann Pigné <yoann.pigne@graphstream-project.org> 007 * Guilhelm Savin <guilhelm.savin@graphstream-project.org> 008 * 009 * This file is part of GraphStream <http://graphstream-project.org>. 010 * 011 * GraphStream is a library whose purpose is to handle static or dynamic 012 * graph, create them from scratch, file or any source and display them. 013 * 014 * This program is free software distributed under the terms of two licenses, the 015 * CeCILL-C license that fits European law, and the GNU Lesser General Public 016 * License. You can use, modify and/ or redistribute the software under the terms 017 * of the CeCILL-C license as circulated by CEA, CNRS and INRIA at the following 018 * URL <http://www.cecill.info> or under the terms of the GNU LGPL as published by 019 * the Free Software Foundation, either version 3 of the License, or (at your 020 * option) any later version. 021 * 022 * This program is distributed in the hope that it will be useful, but WITHOUT ANY 023 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 024 * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. 025 * 026 * You should have received a copy of the GNU Lesser General Public License 027 * along with this program. If not, see <http://www.gnu.org/licenses/>. 028 * 029 * The fact that you are presently reading this means that you have had 030 * knowledge of the CeCILL-C and LGPL licenses and that you accept their terms. 031 */ 032package org.graphstream.stream.file.pajek; 033 034import java.util.ArrayList; 035import java.util.Locale; 036 037import org.graphstream.graph.implementations.AbstractElement.AttributeChangeEvent; 038import org.graphstream.stream.SourceBase.ElementType; 039import org.graphstream.stream.file.FileSourcePajek; 040import org.graphstream.util.parser.ParseException; 041import org.graphstream.util.parser.Token; 042 043public class PajekContext { 044 FileSourcePajek pajek; 045 String sourceId; 046 047 protected boolean directed = false; 048 049 protected String weightAttributeName = "weight"; 050 051 public PajekContext(FileSourcePajek pajek) { 052 this.pajek = pajek; 053 this.sourceId = String.format("<Pajek stream %d>", System.currentTimeMillis()); 054 } 055 056 protected void setDirected(boolean on) { 057 directed = on; 058 } 059 060 protected int addNodes(Token nb) throws ParseException { 061 int n = getInt(nb); 062 063 for (int i = 1; i <= n; ++i) { 064 pajek.sendNodeAdded(sourceId, String.format("%d", i)); 065 } 066 067 return n; 068 } 069 070 protected void addGraphAttribute(String attr, String value) { 071 pajek.sendAttributeChangedEvent(sourceId, sourceId, ElementType.GRAPH, 072 attr, AttributeChangeEvent.ADD, null, value); 073 } 074 075 protected void addNodeLabel(String nb, String label) { 076 pajek.sendAttributeChangedEvent(sourceId, nb, ElementType.NODE, 077 "ui.label", AttributeChangeEvent.ADD, null, label); 078 } 079 080 protected void addNodeGraphics(String id, NodeGraphics graphics) { 081 pajek.sendAttributeChangedEvent(sourceId, id, ElementType.NODE, 082 "ui.style", AttributeChangeEvent.ADD, null, graphics.getStyle()); 083 } 084 085 protected void addNodePosition(String id, Token x, Token y, Token z) 086 throws ParseException { 087 Object pos[] = new Object[3]; 088 pos[0] = (Double) getReal(x); 089 pos[1] = (Double) getReal(y); 090 pos[2] = z != null ? (Double) getReal(z) : 0; 091 092 pajek.sendAttributeChangedEvent(sourceId, id, ElementType.NODE, 093 "xyz", AttributeChangeEvent.ADD, null, pos); 094 } 095 096 protected String addEdge(String src, String trg) { 097 String id = String.format("%s_%s_%d", src, trg, 098 (long) (Math.random() * 100000) + System.currentTimeMillis()); 099 100 pajek.sendEdgeAdded(sourceId, id, src, trg, directed); 101 102 return id; 103 } 104 105 protected void addEdges(EdgeMatrix mat) { 106 int size = mat.size(); 107 int edgeid = 0; 108 109 for (int line = 0; line < size; line++) { 110 for (int col = 0; col < size; col++) { 111 if (mat.hasEdge(line, col)) { 112 String id = String.format("%d_%d_%d", line + 1, col + 1, 113 edgeid++); 114 if (mat.hasEdge(col, line)) { 115 pajek.sendEdgeAdded(sourceId, id, 116 String.format("%d", line + 1), 117 String.format("%d", col + 1), false); 118 mat.set(col, line, false); 119 } else { 120 pajek.sendEdgeAdded(sourceId, id, 121 String.format("%d", line + 1), 122 String.format("%d", col + 1), true); 123 } 124 } 125 } 126 } 127 } 128 129 protected void addEdgeWeight(String id, Token nb) throws ParseException { 130 pajek.sendAttributeChangedEvent(sourceId, id, ElementType.EDGE, 131 weightAttributeName, AttributeChangeEvent.ADD, null, getReal(nb)); 132 } 133 134 protected void addEdgeGraphics(String id, EdgeGraphics graphics) { 135 pajek.sendAttributeChangedEvent(sourceId, id, ElementType.EDGE, 136 "ui.style", AttributeChangeEvent.ADD, null, graphics.getStyle()); 137 } 138 139 protected static int getInt(Token nb) throws ParseException { 140 try { 141 return Integer.parseInt(nb.image); 142 } catch (Exception e) { 143 throw new ParseException(String.format("%d:%d: %s not an integer", 144 nb.beginLine, nb.beginColumn, nb.image)); 145 } 146 } 147 148 protected static double getReal(Token nb) throws ParseException { 149 try { 150 return Double.parseDouble(nb.image); 151 } catch (Exception e) { 152 throw new ParseException(String.format("%d:%d: %s not a real", 153 nb.beginLine, nb.beginColumn, nb.image)); 154 } 155 } 156 157 public static String toColorValue(Token R, Token G, Token B) 158 throws ParseException { 159 double r = getReal(R); 160 double g = getReal(G); 161 double b = getReal(B); 162 163 return String.format("rgb(%d, %d, %d)", (int) (r * 255), 164 (int) (g * 255), (int) (b * 255)); 165 } 166} 167 168abstract class Graphics { 169 protected StringBuffer graphics = new StringBuffer(); 170 171 public abstract void addKey(String key, String value, Token tk) 172 throws ParseException; 173 174 public String getStyle() { 175 return graphics.toString(); 176 } 177 178 protected double getReal(String nb, Token tk) throws ParseException { 179 try { 180 return Double.parseDouble(nb); 181 } catch (Exception e) { 182 throw new ParseException(String.format("%d:%d: %s not a real", 183 tk.beginLine, tk.beginColumn, nb)); 184 } 185 } 186 187 protected int getInt(String nb, Token tk) throws ParseException { 188 try { 189 return Integer.parseInt(nb); 190 } catch (Exception e) { 191 throw new ParseException(String.format("%d:%d: %s not an integer", 192 tk.beginLine, tk.beginColumn, nb)); 193 } 194 } 195} 196 197class NodeGraphics extends Graphics { 198 @Override 199 public void addKey(String key, String value, Token tk) 200 throws ParseException { 201 if (key.equals("shape")) { 202 graphics.append(String.format("shape: %s;", value)); 203 } else if (key.equals("ic")) { 204 graphics.append(String.format("fill-color: %s;", value)); 205 } else if (key.equals("bc")) { 206 graphics.append(String.format( 207 "stroke-color: %s; stroke-mode: plain;", value)); 208 } else if (key.equals("bw")) { 209 graphics.append(String.format(Locale.US, "stroke-width: %fpx;", 210 getReal(value, tk))); 211 } else if (key.equals("s_size")) { 212 graphics.append(String.format(Locale.US, "size: %fpx;", 213 getReal(value, tk))); 214 } else if (key.equals("lc")) { 215 graphics.append(String.format("text-color: %s;", value)); 216 } else if (key.equals("fos")) { 217 graphics.append(String.format("text-size: %d;", getInt(value, tk))); 218 } else if (key.equals("font")) { 219 graphics.append(String.format("text-font: %s;", value)); 220 } 221 } 222} 223 224class EdgeGraphics extends Graphics { 225 @Override 226 public void addKey(String key, String value, Token tk) 227 throws ParseException { 228 if (key.equals("w")) { 229 graphics.append(String.format(Locale.US, "size: %fpx;", 230 getReal(value, tk))); 231 } else if (key.equals("c")) { 232 graphics.append(String.format("fill-color: %s;", value)); 233 } else if (key.equals("s")) { 234 double s = getReal(value, tk); 235 graphics.append(String.format("arrow-size: %spx, %spx;", s * 5, 236 s * 3)); 237 } else if (key.equals("l")) { 238 // ? 239 } else if (key.equals("p")) { 240 // ? 241 } else if (key.equals("lc")) { 242 graphics.append(String.format("text-color: %s;", value)); 243 } else if (key.equals("fos")) { 244 graphics.append(String.format("text-size: %d;", getInt(value, tk))); 245 } else if (key.equals("font")) { 246 graphics.append(String.format("text-font: %s;", value)); 247 } 248 } 249} 250 251class EdgeMatrix { 252 // Line first, col second. 253 // Line = from node, col = to node. 254 protected boolean mat[][]; 255 256 protected int curLine = 0; 257 258 public EdgeMatrix(int size) { 259 mat = new boolean[size][size]; // Horror ! 260 } 261 262 public int size() { 263 return mat.length; 264 } 265 266 public boolean hasEdge(int line, int col) { 267 return mat[line][col]; 268 } 269 270 public void set(int line, int col, boolean value) { 271 mat[line][col] = value; 272 } 273 274 public void addLine(ArrayList<String> line) { 275 if (curLine < mat.length) { 276 if (line.size() == mat.length) { 277 for (int i = 0; i < mat.length; i++) { 278 mat[curLine][i] = line.get(i).equals("1"); 279 } 280 curLine++; 281 } else if (line.size() == mat.length * mat.length) { 282 int n = mat.length * mat.length; 283 curLine = -1; 284 for (int i = 0; i < n; i++) { 285 if (i % mat.length == 0) 286 curLine++; 287 mat[curLine][i - (curLine * mat.length)] = line.get(i) 288 .equals("1"); 289 } 290 } 291 } 292 } 293 294 @Override 295 public String toString() { 296 StringBuffer buffer = new StringBuffer(); 297 for (int line = 0; line < mat.length; line++) { 298 for (int col = 0; col < mat.length; col++) { 299 buffer.append(String.format("%s ", mat[line][col] ? "1" : "0")); 300 } 301 buffer.append(String.format("%n")); 302 } 303 304 return buffer.toString(); 305 } 306}