Example #1
0
func graphID(g graph.Graph, n graph.Node) string {
	switch g := g.(type) {
	case Node:
		return g.DOTID()
	default:
		return nodeID(n)
	}
}
Example #2
0
func (p *printer) print(g graph.Graph, name string, needsIndent, isSubgraph bool) error {
	nodes := g.Nodes()
	sort.Sort(ordered.ByID(nodes))

	p.buf.WriteString(p.prefix)
	if needsIndent {
		for i := 0; i < p.depth; i++ {
			p.buf.WriteString(p.indent)
		}
	}
	_, isDirected := g.(graph.Directed)
	if isSubgraph {
		p.buf.WriteString("sub")
	} else if isDirected {
		p.buf.WriteString("di")
	}
	p.buf.WriteString("graph")

	if name == "" {
		if g, ok := g.(Graph); ok {
			name = g.DOTID()
		}
	}
	if name != "" {
		p.buf.WriteByte(' ')
		p.buf.WriteString(name)
	}

	p.openBlock(" {")
	if a, ok := g.(Attributers); ok {
		p.writeAttributeComplex(a)
	}
	if s, ok := g.(Structurer); ok {
		for _, g := range s.Structure() {
			_, subIsDirected := g.(graph.Directed)
			if subIsDirected != isDirected {
				return errors.New("dot: mismatched graph type")
			}
			p.buf.WriteByte('\n')
			p.print(g, g.DOTID(), true, true)
		}
	}

	havePrintedNodeHeader := false
	for _, n := range nodes {
		if s, ok := n.(Subgrapher); ok {
			// If the node is not linked to any other node
			// the graph needs to be written now.
			if len(g.From(n)) == 0 {
				g := s.Subgraph()
				_, subIsDirected := g.(graph.Directed)
				if subIsDirected != isDirected {
					return errors.New("dot: mismatched graph type")
				}
				if !havePrintedNodeHeader {
					p.newline()
					p.buf.WriteString("// Node definitions.")
					havePrintedNodeHeader = true
				}
				p.newline()
				p.print(g, graphID(g, n), false, true)
			}
			continue
		}
		if !havePrintedNodeHeader {
			p.newline()
			p.buf.WriteString("// Node definitions.")
			havePrintedNodeHeader = true
		}
		p.newline()
		p.writeNode(n)
		if a, ok := n.(Attributer); ok {
			p.writeAttributeList(a)
		}
		p.buf.WriteByte(';')
	}

	havePrintedEdgeHeader := false
	for _, n := range nodes {
		to := g.From(n)
		sort.Sort(ordered.ByID(to))
		for _, t := range to {
			if isDirected {
				if p.visited[edge{inGraph: name, from: n.ID(), to: t.ID()}] {
					continue
				}
				p.visited[edge{inGraph: name, from: n.ID(), to: t.ID()}] = true
			} else {
				if p.visited[edge{inGraph: name, from: n.ID(), to: t.ID()}] {
					continue
				}
				p.visited[edge{inGraph: name, from: n.ID(), to: t.ID()}] = true
				p.visited[edge{inGraph: name, from: t.ID(), to: n.ID()}] = true
			}

			if !havePrintedEdgeHeader {
				p.buf.WriteByte('\n')
				p.buf.WriteString(strings.TrimRight(p.prefix, " \t\xa0")) // Trim whitespace suffix.
				p.newline()
				p.buf.WriteString("// Edge definitions.")
				havePrintedEdgeHeader = true
			}
			p.newline()

			if s, ok := n.(Subgrapher); ok {
				g := s.Subgraph()
				_, subIsDirected := g.(graph.Directed)
				if subIsDirected != isDirected {
					return errors.New("dot: mismatched graph type")
				}
				p.print(g, graphID(g, n), false, true)
			} else {
				p.writeNode(n)
			}
			e, edgeIsPorter := g.Edge(n, t).(Porter)
			if edgeIsPorter {
				p.writePorts(e.FromPort())
			}

			if isDirected {
				p.buf.WriteString(" -> ")
			} else {
				p.buf.WriteString(" -- ")
			}

			if s, ok := t.(Subgrapher); ok {
				g := s.Subgraph()
				_, subIsDirected := g.(graph.Directed)
				if subIsDirected != isDirected {
					return errors.New("dot: mismatched graph type")
				}
				p.print(g, graphID(g, t), false, true)
			} else {
				p.writeNode(t)
			}
			if edgeIsPorter {
				p.writePorts(e.ToPort())
			}

			if a, ok := g.Edge(n, t).(Attributer); ok {
				p.writeAttributeList(a)
			}

			p.buf.WriteByte(';')
		}
	}
	p.closeBlock("}")

	return nil
}