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; 033 034import java.io.IOException; 035import java.io.PrintWriter; 036 037/** 038 * Graph writer for the GraphViz DOT format. 039 */ 040public class FileSinkDOT extends FileSinkBase { 041 // Attribute 042 043 /** 044 * The output. 045 */ 046 protected PrintWriter out; 047 048 /** 049 * The graph name (set as soon as known). 050 */ 051 protected String graphName = ""; 052 053 /** 054 * Is the graph directed ? 055 */ 056 protected boolean digraph; 057 058 /** 059 * What element ?. 060 */ 061 protected enum What { 062 NODE, EDGE, OTHER 063 }; 064 065 /** 066 * Build a new DOT sink to export undirected graph. 067 */ 068 public FileSinkDOT() { 069 this(false); 070 } 071 072 /** 073 * Build a new DOT sink specifying if the graph is directed or not. 074 * 075 * @param digraph 076 * true if the graph is directed 077 */ 078 public FileSinkDOT(boolean digraph) { 079 this.digraph = digraph; 080 } 081 082 // Command 083 084 /** 085 * Set flag indicating if exported graph is directed or not. 086 * 087 * @param digraph 088 * true is exported graph is directed 089 */ 090 public void setDirected(boolean digraph) { 091 this.digraph = digraph; 092 } 093 094 /** 095 * Get the flag indicating if exported graph is directed or not. 096 * 097 * @return true if exported graph is directed 098 */ 099 public boolean isDirected() { 100 return digraph; 101 } 102 103 @Override 104 protected void outputHeader() throws IOException { 105 out = (PrintWriter) output; 106 out.printf("%s {%n", digraph ? "digraph" : "graph"); 107 108 if (graphName.length() > 0) 109 out.printf("\tgraph [label=%s];%n", graphName); 110 } 111 112 @Override 113 protected void outputEndOfFile() throws IOException { 114 out.printf("}%n"); 115 } 116 117 public void edgeAttributeAdded(String graphId, long timeId, String edgeId, 118 String attribute, Object value) { 119 // NOP 120 } 121 122 public void edgeAttributeChanged(String graphId, long timeId, 123 String edgeId, String attribute, Object oldValue, Object newValue) { 124 // NOP 125 } 126 127 public void edgeAttributeRemoved(String graphId, long timeId, 128 String edgeId, String attribute) { 129 // NOP 130 } 131 132 public void graphAttributeAdded(String graphId, long timeId, 133 String attribute, Object value) { 134 out 135 .printf("\tgraph [ %s ];%n", outputAttribute(attribute, value, 136 true)); 137 } 138 139 public void graphAttributeChanged(String graphId, long timeId, 140 String attribute, Object oldValue, Object newValue) { 141 out.printf("\tgraph [ %s ];%n", outputAttribute(attribute, newValue, 142 true)); 143 } 144 145 public void graphAttributeRemoved(String graphId, long timeId, 146 String attribute) { 147 // NOP 148 } 149 150 public void nodeAttributeAdded(String graphId, long timeId, String nodeId, 151 String attribute, Object value) { 152 out.printf("\t\"%s\" [ %s ];%n", nodeId, outputAttribute(attribute, 153 value, true)); 154 } 155 156 public void nodeAttributeChanged(String graphId, long timeId, 157 String nodeId, String attribute, Object oldValue, Object newValue) { 158 out.printf("\t\"%s\" [ %s ];%n", nodeId, outputAttribute(attribute, 159 newValue, true)); 160 } 161 162 public void nodeAttributeRemoved(String graphId, long timeId, 163 String nodeId, String attribute) { 164 // NOP 165 } 166 167 public void edgeAdded(String graphId, long timeId, String edgeId, 168 String fromNodeId, String toNodeId, boolean directed) { 169 if (digraph) { 170 out.printf("\t\"%s\" -> \"%s\"", fromNodeId, toNodeId); 171 172 if (!directed) 173 out.printf(" -> \"%s\"", fromNodeId); 174 175 out.printf("\n;"); 176 } else 177 out.printf("\t\"%s\" -- \"%s\";%n", fromNodeId, toNodeId); 178 } 179 180 public void edgeRemoved(String graphId, long timeId, String edgeId) { 181 // NOP 182 } 183 184 public void graphCleared(String graphId, long timeId) { 185 // NOP 186 } 187 188 public void nodeAdded(String graphId, long timeId, String nodeId) { 189 out.printf("\t\"%s\";%n", nodeId); 190 } 191 192 public void nodeRemoved(String graphId, long timeId, String nodeId) { 193 // NOP 194 } 195 196 public void stepBegins(String graphId, long timeId, double step) { 197 // NOP 198 } 199 200 // Utility 201 /* 202 * protected void outputAttributes(Map<String, Object> attributes, What 203 * what) throws IOException { out.printf(" ["); 204 * 205 * boolean first = true; 206 * 207 * for (String key : attributes.keySet()) { Object value = 208 * attributes.get(key); 209 * 210 * if (what == What.NODE) { // if( ! nodeForbiddenAttrs.contains( key ) ) { 211 * first = outputAttribute(key, value, first); } } else if (what == 212 * What.EDGE) { // if( ! edgeForbiddenAttrs.contains( key ) ) { first = 213 * outputAttribute(key, value, first); } } else { first = 214 * outputAttribute(key, value, first); } 215 * 216 * } 217 * 218 * out.printf("]"); } 219 */ 220 protected String outputAttribute(String key, Object value, boolean first) { 221 boolean quote = true; 222 223 if (value instanceof Number) 224 quote = false; 225 226 return String.format("%s\"%s\"=%s%s%s", first ? "" : ",", key, 227 quote ? "\"" : "", value, quote ? "\"" : ""); 228 } 229}