view trunk/src/docgen/graphutils/dotwriter.d @ 457:33a4cb255fcc

Cached images, small fixes, reorganizing.
author Jari-Matti M?kel? <jmjm@iki.fi>
date Tue, 30 Oct 2007 15:41:30 +0200
parents dbdc9fa5d479
children 1b5f1ce09f38
line wrap: on
line source

/**
 * Author: Aziz Köksal & Jari-Matti Mäkelä
 * License: GPL3
 */
module docgen.graphutils.dotwriter;
import docgen.graphutils.writer;

import tango.io.Print: Print;
import tango.text.convert.Layout : Layout;
import tango.io.FilePath;
import tango.text.Util;
debug import tango.io.Stdout;

/**
 * Creates a graph rule file for the dot utility.
 */
class DotWriter : AbstractGraphWriter {
  this(GraphWriterFactory factory, PageWriter writer) {
    super(factory, writer);
  }

  void generateDepImageFile(Vertex[] vertices, Edge[] edges, OutputStream imageFile) {
    auto image = new Print!(char)(new Layout!(char), imageFile);

    Vertex[][char[]] verticesByPckgName;
    if (factory.options.graph.groupByFullPackageName ||
        factory.options.graph.groupByPackageNames) {
      foreach (mod; vertices) {
        auto parts = mod.name.delimit(".");

        if (parts.length>1) {
          auto pkg = parts[0..$-1].join(".");
          verticesByPckgName[pkg] ~= mod;
        }
      }
    }

    if (factory.options.graph.highlightCyclicVertices ||
        factory.options.graph.highlightCyclicEdges)
      findCycles(vertices, edges);

    image("Digraph ModuleDependencies {\n");

    foreach (module_; vertices) {
      auto nodeName = 
        factory.options.graph.groupByPackageNames ?
        module_.name.split(".")[$-1] :
        module_.name;

      image.format(
        `  n{0} [label="{1}"{2}];`\n,
        module_.id,
        nodeName,
        (module_.isCyclic && factory.options.graph.highlightCyclicVertices ?
          ",style=filled,fillcolor=" ~ factory.options.graph.nodeColor :
          (module_.type == VertexType.UnlocatableModule ?
            ",style=filled,fillcolor=" ~ factory.options.graph.unlocatableNodeColor :
            ""
          )
        )
      );
    }

    foreach (edge; edges)
      image.format(
        `  n{0} -> n{1}{2};`\n,
        edge.outgoing.id,
        edge.incoming.id,
        (edge.isCyclic ? "[color=" ~ factory.options.graph.cyclicNodeColor ~ "]" : "")
      );

    if (factory.options.graph.groupByPackageNames)

      if (!factory.options.graph.groupByFullPackageName) {
        foreach (packageName, vertices; verticesByPckgName) {
          auto name = packageName.split(".");

          if (name.length > 1) {
            char[] pkg;
            foreach(part; name) {
              pkg ~= part ~ ".";
              image.format(
                `subgraph "cluster_{0}" {{`\n`  label="{0}"`\n,
                pkg[0..$-1],
                pkg[0..$-1]
              );
            }
            for (int i=0; i< name.length; i++) {
              image("}\n");
            }
          }
        }
      }
      foreach (packageName, vertices; verticesByPckgName) {
        image.format(
          `  subgraph "cluster_{0}" {{`\n`  label="{0}";color=`
          ~ factory.options.graph.clusterColor ~ `;`\n`  `,
          packageName,
          packageName
        );

        foreach (module_; vertices)
          image.format(`n{0};`, module_.id);
        image("\n  }\n");
      }

    image("}");
  }
        
  void generateImageTag(OutputStream imageFile) {
    // name of the .dot file
    char[] fn = (cast(Object)imageFile.conduit).toUtf8();
    fn = FilePath(fn).file;

    fn = fn[0..$-3] ~ imageFormatExts[factory.options.graph.imageFormat];
    
    writer.addGraphics(fn);
  }

  protected void generateDepGraph(Vertex[] vertices, Edge[] edges, OutputStream imageFile) {
    generateImageTag(imageFile);
    generateDepImageFile(vertices, edges, imageFile);
  }
}

class CachingDotWriter : DotWriter {
  CachingGraphWriterFactory factory;

  this(CachingGraphWriterFactory factory, PageWriter writer) {
    super(factory, writer);
  }

  protected void generateDepGraph(Vertex[] vertices, Edge[] edges, OutputStream imageFile) {
    generateImageTag(imageFile);

    auto cached = factory.getCachedGraph(vertices, edges, GraphFormat.Dot);

    if (cached) {
      auto image = new Print!(char)(new Layout!(char), imageFile);
      
      if (cached) {
        debug Stdout("Image cache hit.\n");
        image(cached);
      } else
        generateDepImageFile(vertices, edges, imageFile);
    }
  }
}