diff --git a/README.md b/README.md index 0bcb25a..905ce9e 100644 --- a/README.md +++ b/README.md @@ -2,15 +2,14 @@ [![Build Status](https://travis-ci.org/dspinellis/UMLGraph.svg?branch=master)](https://travis-ci.org/dspinellis/UMLGraph) -*UMLGraph* allows the declarative specification and drawing of -UML diagrams. +*UMLGraph* allows the declarative specification and drawing of UML diagrams. You can browse the system's documentation through [this link](http://www.spinellis.gr/umlgraph/doc/index.html), or print it through [this link](http://www.spinellis.gr/umlgraph/doc/indexw.html). -To install the elements required to run *UMLGraph*, simply copy -the contents of the *lib* directory to a location consistent with -your installation's conventions (for example to `/usr/local/lib`). +In order to run *UMLGraph*, you need to have [GraphViz](https://www.graphviz.org/) +installed in your system path. On most Linux distributions, this can be easily +installed using the regular package manager. To compile the Java doclet from the source code run *ant* on the *build.xml* file. @@ -19,3 +18,52 @@ If you change the source code, you can run regression tests by executing *ant test*. Visit the project's [home page](http://www.spinellis.gr/umlgraph) for more information. + +## Compatibility + +Currently, only Java 8 is supported by the Doclet. + +In Java 9 the JavaDoc Doclet API changed substantially, and the doclet therefore +needs to be largely rewritten. + +Sorry, this has not happened yet - volunteers for this task are welcome. + +## Development versions + +In order to use development versions, you can use [JitPack](https://jitpack.io/#dspinellis/UMLGraph/master-SNAPSHOT). +Note that as this is compiled on demand, you may sometimes see a "Read timed out" when the package is recompiled, +and it should be fine a few seconds later. And because the master branch can change any time, you may want to use +a versioned snapshot instead (see the Jitpack documentation for details). + +**Gradle**: +``` +repositories { maven { url 'https://jitpack.io' } } +configurations { umlgraph } +dependencies { umlgraph 'com.github.dspinellis:UMLGraph:master-SNAPSHOT' } +javadoc { + doclet = 'org.umlgraph.doclet.UmlGraphDoc' + docletpath = configurations.umlgraph.files.asType(List) + tags("hidden:X", "opt:X", "has:X", "navhas:X", "assoc:X", "navassoc:X", + "composed:X", "navcomposed:X", "stereotype:X", "depend:X") +} +``` + +**Maven**: +``` + + + jitpack.io + https://jitpack.io + + +... + + com.github.dspinellis + UMLGraph + master-SNAPSHOT + compile + +``` + +**Jar download**: + diff --git a/TODO b/TODO index 42d1f54..7b8d92a 100644 --- a/TODO +++ b/TODO @@ -1,5 +1,3 @@ -When UMLGraph 2.29 comes out use for italic fonts? - http://stackoverflow.com/questions/8609546/umlgraph-not-automatic-integrated-in-javadoc Support for all UML diagrams: state, use-case, etc. diff --git a/build.xml b/build.xml index 40f4672..75af9bd 100644 --- a/build.xml +++ b/build.xml @@ -64,6 +64,14 @@ + + + + + + + + @@ -119,36 +127,44 @@ class Version { public static String VERSION = "${VERSION}";} - - - - - - - - - - - - - - + + + + + + + + + + + + + + + - - + + - - + + + + + + + + + diff --git a/doc/ceg-adv.xml b/doc/ceg-adv.xml index 29c5075..1dc87f5 100644 --- a/doc/ceg-adv.xml +++ b/doc/ceg-adv.xml @@ -31,7 +31,7 @@ class SetTopController implements URLStreamHandler { void connect() {} } -/** @depend - - SetTopController */ +/** @depend - <friend> - SetTopController */ class ChannelIterator {} interface URLStreamHandler { diff --git a/doc/ceg-infer.xml b/doc/ceg-infer.xml index dc8e0e9..379ecf9 100644 --- a/doc/ceg-infer.xml +++ b/doc/ceg-infer.xml @@ -20,8 +20,8 @@ class UMLOptions {} class Person { House[] houses; - List dogs; - + List<Dog> dogs; + public Room getFavouriteRoom(House house) {} } @@ -29,7 +29,7 @@ class Person { * @opt inferreltype composed */ class House { - Map nameRoomMap; + Map<String, Room> nameRoomMap; } class Room {} @@ -37,7 +37,6 @@ class Room {} class Dog { Person owner; } - UML diagram with relationship inference diff --git a/doc/ceg-mv.xml b/doc/ceg-mv.xml index 7eb9d79..1da7d42 100644 --- a/doc/ceg-mv.xml +++ b/doc/ceg-mv.xml @@ -93,18 +93,18 @@ clean: build/%.dot : %.java mkdir -p $(dir $@) - $(jd) $(jd_flags) $(detailed_flags) -output $@ $< + $(jd) $(jd_flags) $(detailed_flags) -output $@ $< build/%-small.dot : %.java mkdir -p $(dir $@) - $(jd) $(jd_flags) -output $@ $< + $(jd) $(jd_flags) -output $@ $< %.png : %.dot - dot -Nheight=0.2 -Elabelfontcolor=DarkSlateBlue -Elabelfontsize=8 -Tpng -o $@ $< + dot -Nheight=0.2 -Elabelfontcolor=DarkSlateBlue -Elabelfontsize=8 -Tpng -o $@ $< build/%.png : %.fig mkdir -p $(dir $@) - fig2dev -L png -S 4 $< $@ + fig2dev -L png -S 4 $< $@ dot: $(dot_files) @@ -112,7 +112,7 @@ png: $(png_files) build/%.png : %.png mkdir -p $(dir $@) - cp $< $@ + cp $< $@ # Example usage: # make debug-java_files diff --git a/doc/uml-184.xml b/doc/uml-184.xml index a4adb65..7d0f3d3 100644 --- a/doc/uml-184.xml +++ b/doc/uml-184.xml @@ -30,7 +30,7 @@ async(); message(S,W,"liftReceiver"); sync(); active(S); message(W,S,"setDialTone()"); async(); message(S,W,"*dialDigit(d)"); sync(); -lconstraint(W,"{dialing.executionTime < 30s}"); +lconstraint(W,"{dialing.executionTime < 30s}"); active(W); message(W,W,"routeCalls(s,n)"); inactive(W); diff --git a/doc/ver.xml b/doc/ver.xml index f89f6eb..b75d125 100644 --- a/doc/ver.xml +++ b/doc/ver.xml @@ -13,6 +13,10 @@ this works well with -qualify -postfixpackage (and -!qualifyG To get the old -qualify behavior, you need to add -qualifyGenerics, the default is off, and it will not inherit from -qualify.
  • Better handling of complex names with generics and inner classes such as pkg.Outer<T>.Inner.
  • +
  • Use <i> tags for italic, because the old font naming approach does not work with SVG anymore. +Replace -nodefontabstractname and -nodefontclassabstractname +with a simple flag -nodefontabstractitalic instead.
  • +
  • Added -hideprivateinner to hide all private inner classes.
  • diff --git a/src/main/java/org/umlgraph/doclet/ClassGraph.java b/src/main/java/org/umlgraph/doclet/ClassGraph.java index 378cea7..fe2e21e 100644 --- a/src/main/java/org/umlgraph/doclet/ClassGraph.java +++ b/src/main/java/org/umlgraph/doclet/ClassGraph.java @@ -19,11 +19,21 @@ package org.umlgraph.doclet; +import static org.umlgraph.doclet.StringUtil.buildRelativePathFromClassNames; +import static org.umlgraph.doclet.StringUtil.escape; +import static org.umlgraph.doclet.StringUtil.fmt; +import static org.umlgraph.doclet.StringUtil.guilWrap; +import static org.umlgraph.doclet.StringUtil.guillemize; +import static org.umlgraph.doclet.StringUtil.htmlNewline; +import static org.umlgraph.doclet.StringUtil.removeTemplate; +import static org.umlgraph.doclet.StringUtil.splitPackageClass; +import static org.umlgraph.doclet.StringUtil.tokenize; + import java.io.BufferedOutputStream; import java.io.File; import java.io.FileOutputStream; -import java.io.OutputStream; import java.io.IOException; +import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.util.ArrayList; @@ -33,7 +43,6 @@ import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; -import java.util.regex.Pattern; import com.sun.javadoc.ClassDoc; import com.sun.javadoc.ConstructorDoc; @@ -61,23 +70,16 @@ import com.sun.javadoc.WildcardType; * @author Diomidis Spinellis */ class ClassGraph { - protected static final char FILE_SEPARATOR = '/'; - enum Font { - NORMAL, ABSTRACT, CLASS, CLASS_ABSTRACT, TAG, PACKAGE - } enum Align { - LEFT, CENTER, RIGHT + LEFT, CENTER, RIGHT; + + public final String lower; + + private Align() { + this.lower = toString().toLowerCase(); + } }; - public static Map associationMap = new HashMap(); - static { - associationMap.put(RelationType.ASSOC, "arrowhead=none"); - associationMap.put(RelationType.NAVASSOC, "arrowhead=open"); - associationMap.put(RelationType.HAS, "arrowhead=none, arrowtail=ediamond, dir=both"); - associationMap.put(RelationType.NAVHAS, "arrowhead=open, arrowtail=ediamond, dir=both"); - associationMap.put(RelationType.COMPOSED, "arrowhead=none, arrowtail=diamond, dir=both"); - associationMap.put(RelationType.NAVCOMPOSED, "arrowhead=open, arrowtail=diamond, dir=both"); - associationMap.put(RelationType.DEPEND, "arrowhead=open, style=dashed"); - } + protected Map classnames = new HashMap(); protected Set rootClasses; protected Map rootClassdocs = new HashMap(); @@ -90,7 +92,7 @@ class ClassGraph { // used only when generating context class diagrams in UMLDoc, to generate the proper // relative links to other classes in the image map - protected Doc contextDoc; + protected final String contextPackageName; /** * Create a new ClassGraph.

    The packages passed as an @@ -105,7 +107,6 @@ class ClassGraph { this.optionProvider = optionProvider; this.collectionClassDoc = root.classNamed("java.util.Collection"); this.mapClassDoc = root.classNamed("java.util.Map"); - this.contextDoc = contextDoc; // to gather the packages containing specified classes, loop thru them and gather // package definitions. User root.specifiedPackages is not safe, since the user @@ -113,133 +114,60 @@ class ClassGraph { rootClasses = new HashSet(); for (ClassDoc classDoc : root.classes()) { rootClasses.add(classDoc.qualifiedName()); - rootClassdocs.put(classDoc.qualifiedName(), classDoc); + rootClassdocs.put(classDoc.qualifiedName(), classDoc); } + // determine the context path, relative to the root + if (contextDoc instanceof ClassDoc) + contextPackageName = ((ClassDoc) contextDoc).containingPackage().name(); + else if (contextDoc instanceof PackageDoc) + contextPackageName = ((PackageDoc) contextDoc).name(); + else + contextPackageName = null; // Not available + Options opt = optionProvider.getGlobalOptions(); - if (opt.compact) { - linePrefix = ""; - linePostfix = ""; - } else { - linePrefix = "\t"; - linePostfix = "\n"; - } + linePrefix = opt.compact ? "" : "\t"; + linePostfix = opt.compact ? "" : "\n"; } /** Return the class's name, possibly by stripping the leading path */ private static String qualifiedName(Options opt, String r) { - // Nothing to do: + if (opt.hideGenerics) + r = removeTemplate(r); + // Fast path - nothing to do: if (opt.showQualified && (opt.showQualifiedGenerics || r.indexOf('<') < 0)) return r; StringBuilder buf = new StringBuilder(r.length()); - int last = 0, depth = 0; - boolean strip = !opt.showQualified; - for (int i = 0; i < r.length();) { - char c = r.charAt(i++); - // The last condition prevents losing the dot in A.B - if ((c == '.' || c == '$') && strip && last + 1 < i) - last = i; // skip - if (Character.isJavaIdentifierPart(c)) - continue; - // Handle nesting of generics - if (c == '<') { - ++depth; - strip = !opt.showQualifiedGenerics; - } else if (c == '>' && --depth == 0) - strip = !opt.showQualified; - if (last < i) { - buf.append(r, last, i); - last = i; - } - } - if (last < r.length()) - buf.append(r, last, r.length()); + qualifiedNameInner(opt, r, buf, 0, !opt.showQualified); return buf.toString(); } - /** - * Escape <, >, and & characters in the string with - * the corresponding HTML entity code. - */ - private String escape(String s) { - final Pattern toEscape = Pattern.compile("[&<>]"); - - if (toEscape.matcher(s).find()) { - StringBuilder sb = new StringBuilder(s); - for (int i = 0; i < sb.length();) { - switch (sb.charAt(i)) { - case '&': - sb.replace(i, i + 1, "&"); - i += "&".length(); - break; - case '<': - sb.replace(i, i + 1, "<"); - i += "<".length(); - break; - case '>': - sb.replace(i, i + 1, ">"); - i += ">".length(); - break; - default: - i++; - } + private static int qualifiedNameInner(Options opt, String r, StringBuilder buf, int last, boolean strip) { + strip = strip && last < r.length() && Character.isLowerCase(r.charAt(last)); + for (int i = last; i < r.length(); i++) { + char c = r.charAt(i); + if (c == '.' || c == '$') { + if (strip) + last = i + 1; // skip dot + strip = strip && last < r.length() && Character.isLowerCase(r.charAt(last)); + continue; } - return sb.toString(); - } else - return s; - } - - /** - * Convert embedded newlines into HTML line breaks - */ - private String htmlNewline(String s) { - if (s.indexOf('\n') == -1) - return (s); - - StringBuilder sb = new StringBuilder(s); - for (int i = 0; i < sb.length();) { - if (sb.charAt(i) == '\n') { - sb.replace(i, i + 1, "
    "); - i += "
    ".length(); - } else - i++; + if (Character.isJavaIdentifierPart(c)) + continue; + buf.append(r, last, i); + last = i; + // Handle nesting of generics + if (c == '<') { + buf.append('<'); + i = last = qualifiedNameInner(opt, r, buf, ++last, !opt.showQualifiedGenerics); + buf.append('>'); + } else if (c == '>') + return i + 1; } - return sb.toString(); - } - - - /** - * Convert < and > characters in the string to the respective guillemot characters. - */ - private String guillemize(Options opt, String s) { - StringBuilder r = new StringBuilder(s); - for (int i = 0; i < r.length();) - switch (r.charAt(i)) { - case '<': - r.replace(i, i + 1, opt.guilOpen); - i += opt.guilOpen.length(); - break; - case '>': - r.replace(i, i + 1, opt.guilClose); - i += opt.guilClose.length(); - break; - default: - i++; - break; - } - return r.toString(); - } - - /** - * Wraps a string in Guillemot (or an ASCII substitute) characters. - * - * @param str the String to be wrapped. - * @return the wrapped String. - */ - private String guilWrap(Options opt, String str) { - return opt.guilOpen + str + opt.guilClose; + buf.append(r, last, r.length()); + return r.length(); } /** @@ -247,66 +175,46 @@ class ClassGraph { * any stereotypes */ private String visibility(Options opt, ProgramElementDoc e) { - if (!opt.showVisibility) - return " "; - if (e.isPrivate()) - return "- "; - else if (e.isPublic()) - return "+ "; - else if (e.isProtected()) - return "# "; - else if (e.isPackagePrivate()) - return "~ "; - else - return " "; + return opt.showVisibility ? Visibility.get(e).symbol : " "; } /** Print the method parameter p */ private String parameter(Options opt, Parameter p[]) { - String par = ""; + StringBuilder par = new StringBuilder(1000); for (int i = 0; i < p.length; i++) { - par += p[i].name() + typeAnnotation(opt, p[i].type()); + par.append(p[i].name() + typeAnnotation(opt, p[i].type())); if (i + 1 < p.length) - par += ", "; + par.append(", "); } - return par; + return par.toString(); } /** Print a a basic type t */ private String type(Options opt, Type t, boolean generics) { - String type; - if (generics ? opt.showQualifiedGenerics : opt.showQualified) - type = t.qualifiedTypeName(); - else - type = t.typeName(); - type += typeParameters(opt, t.asParameterizedType()); - return type; + return ((generics ? opt.showQualifiedGenerics : opt.showQualified) ? // + t.qualifiedTypeName() : t.typeName()) // + + (opt.hideGenerics ? "" : typeParameters(opt, t.asParameterizedType())); } /** Print the parameters of the parameterized type t */ private String typeParameters(Options opt, ParameterizedType t) { - String tp = ""; if (t == null) - return tp; + return ""; + StringBuffer tp = new StringBuffer(1000).append("<"); Type args[] = t.typeArguments(); - tp += "<"; for (int i = 0; i < args.length; i++) { - tp += type(opt, args[i], true); + tp.append(type(opt, args[i], true)); if (i != args.length - 1) - tp += ", "; + tp.append(", "); } - tp += ">"; - return tp; + return tp.append(">").toString(); } /** Annotate an field/argument with its type t */ private String typeAnnotation(Options opt, Type t) { if (t.typeName().equals("void")) return ""; - String ta = " : "; - ta += type(opt, t, false); - ta += t.dimension(); - return ta; + return " : " + type(opt, t, false) + t.dimension(); } /** Print the class's attributes fd */ @@ -314,9 +222,8 @@ class ClassGraph { for (FieldDoc f : fd) { if (hidden(f)) continue; - String att; stereotype(opt, f, Align.LEFT); - att = visibility(opt, f) + f.name(); + String att = visibility(opt, f) + f.name(); if (opt.showType) att += typeAnnotation(opt, f.type()); tableLine(Align.LEFT, att); @@ -337,15 +244,11 @@ class ClassGraph { if (hidden(cd)) continue; stereotype(opt, cd, Align.LEFT); - String cs = visibility(opt, cd) + cd.name(); - if (opt.showType) { - cs += "(" + parameter(opt, cd.parameters()) + ")"; - } else { - cs += "()"; - } + String cs = visibility(opt, cd) + cd.name() // + + (opt.showType ? "(" + parameter(opt, cd.parameters()) + ")" : "()"); tableLine(Align.LEFT, cs); - printed = true; tagvalue(opt, cd); + printed = true; } return printed; } @@ -360,14 +263,10 @@ class ClassGraph { if (md.name().equals("") && md.isStatic() && md.isPackagePrivate()) continue; stereotype(opt, md, Align.LEFT); - String op = visibility(opt, md) + md.name(); - if (opt.showType) { - op += "(" + parameter(opt, md.parameters()) + ")" - + typeAnnotation(opt, md.returnType()); - } else { - op += "()"; - } - tableLine(Align.LEFT, op, opt, md.isAbstract() ? Font.ABSTRACT : Font.NORMAL); + String op = visibility(opt, md) + md.name() + // + (opt.showType ? "(" + parameter(opt, md.parameters()) + ")" + typeAnnotation(opt, md.returnType()) + : "()"); + tableLine(Align.LEFT, (md.isAbstract() ? Font.ABSTRACT : Font.NORMAL).wrap(opt, op)); printed = true; tagvalue(opt, md); @@ -377,10 +276,14 @@ class ClassGraph { /** Print the common class node's properties */ private void nodeProperties(Options opt) { - w.print(", fontname=\"" + opt.nodeFontName + "\""); - w.print(", fontcolor=\"" + opt.nodeFontColor + "\""); - w.print(", fontsize=" + opt.nodeFontSize); - w.print(opt.shape.graphvizAttribute()); + Options def = opt.getGlobalOptions(); + if (opt.nodeFontName != def.nodeFontName) + w.print(",fontname=\"" + opt.nodeFontName + "\""); + if (opt.nodeFontColor != def.nodeFontColor) + w.print(",fontcolor=\"" + opt.nodeFontColor + "\""); + if (opt.nodeFontSize != def.nodeFontSize) + w.print(",fontsize=" + fmt(opt.nodeFontSize)); + w.print(opt.shape.style); w.println("];"); } @@ -397,12 +300,12 @@ class ClassGraph { return; for (Tag tag : tags) { - String t[] = StringUtil.tokenize(tag.text()); + String t[] = tokenize(tag.text()); if (t.length != 2) { System.err.println("@tagvalue expects two fields: " + tag.text()); continue; } - tableLine(Align.RIGHT, "{" + t[0] + " = " + t[1] + "}", opt, Font.TAG); + tableLine(Align.RIGHT, Font.TAG.wrap(opt, "{" + t[0] + " = " + t[1] + "}")); } } @@ -412,7 +315,7 @@ class ClassGraph { */ private void stereotype(Options opt, Doc c, Align align) { for (Tag tag : c.tags("stereotype")) { - String t[] = StringUtil.tokenize(tag.text()); + String t[] = tokenize(tag.text()); if (t.length != 1) { System.err.println("@stereotype expects one field: " + tag.text()); continue; @@ -423,42 +326,39 @@ class ClassGraph { /** Return true if c has a @hidden tag associated with it */ private boolean hidden(ProgramElementDoc c) { - Tag tags[] = c.tags("hidden"); - if (tags.length > 0) + if (c.tags("hidden").length > 0 || c.tags("view").length > 0) return true; - tags = c.tags("view"); - if (tags.length > 0) - return true; - Options opt; - if(c instanceof ClassDoc) - opt = optionProvider.getOptionsFor((ClassDoc) c); - else - opt = optionProvider.getOptionsFor(c.containingClass()); - return opt.matchesHideExpression(c.toString()); + Options opt = optionProvider.getOptionsFor(c instanceof ClassDoc ? (ClassDoc) c : c.containingClass()); + return opt.matchesHideExpression(c.toString()) // + || (opt.hidePrivateInner && c instanceof ClassDoc && c.isPrivate() && ((ClassDoc) c).containingClass() != null); } - - protected ClassInfo getClassInfo(String className) { - return classnames.get(removeTemplate(className)); + + protected ClassInfo getClassInfo(ClassDoc cd, boolean create) { + return getClassInfo(cd, cd.toString(), create); } - - private ClassInfo newClassInfo(String className, boolean printed, boolean hidden) { - ClassInfo ci = new ClassInfo(printed, hidden); - classnames.put(removeTemplate(className), ci); - return ci; + + protected ClassInfo getClassInfo(String className, boolean create) { + return getClassInfo(null, className, create); + } + + protected ClassInfo getClassInfo(ClassDoc cd, String className, boolean create) { + className = removeTemplate(className); + ClassInfo ci = classnames.get(className); + if (ci == null && create) { + boolean hidden = cd != null ? hidden(cd) : optionProvider.getOptionsFor(className).matchesHideExpression(className); + ci = new ClassInfo(hidden); + classnames.put(className, ci); + } + return ci; } /** Return true if the class name is associated to an hidden class or matches a hide expression */ - private boolean hidden(String s) { - ClassInfo ci = getClassInfo(s); - Options opt = optionProvider.getOptionsFor(s); - if(ci != null) - return ci.hidden || opt.matchesHideExpression(s); - else - return opt.matchesHideExpression(s); + private boolean hidden(String className) { + className = removeTemplate(className); + ClassInfo ci = classnames.get(className); + return ci != null ? ci.hidden : optionProvider.getOptionsFor(className).matchesHideExpression(className); } - - /** * Prints the class if needed. *

    @@ -467,157 +367,122 @@ class ClassGraph { * relative links in diagrams for UMLDoc */ public String printClass(ClassDoc c, boolean rootClass) { - ClassInfo ci; - boolean toPrint; + ClassInfo ci = getClassInfo(c, true); + if(ci.nodePrinted || ci.hidden) + return ci.name; Options opt = optionProvider.getOptionsFor(c); - + if (c.isEnum() && !opt.showEnumerations) + return ci.name; String className = c.toString(); - if ((ci = getClassInfo(className)) != null) - toPrint = !ci.nodePrinted; - else { - toPrint = true; - ci = newClassInfo(className, true, hidden(c)); - } - if (toPrint && !hidden(c) && (!c.isEnum() || opt.showEnumerations)) { - // Associate classname's alias - String r = className; - w.println("\t// " + r); - // Create label - w.print("\t" + ci.name + " [label="); + // Associate classname's alias + w.println(linePrefix + "// " + className); + // Create label + w.print(linePrefix + ci.name + " [label="); - boolean showMembers = + boolean showMembers = (opt.showAttributes && c.fields().length > 0) || (c.isEnum() && opt.showEnumConstants && c.enumConstants().length > 0) || (opt.showOperations && c.methods().length > 0) || (opt.showConstructors && c.constructors().length > 0); - - externalTableStart(opt, c.qualifiedName(), classToUrl(c, rootClass)); - // Calculate the number of innerTable rows we will emmit - int nRows = 1; - if (showMembers) { - if (opt.showAttributes) - nRows++; - else if(!c.isEnum() && (opt.showConstructors || opt.showOperations)) - nRows++; - if (c.isEnum() && opt.showEnumConstants) - nRows++; - if (!c.isEnum() && (opt.showConstructors || opt.showOperations)) - nRows++; - } + final String url = classToUrl(c, rootClass); + externalTableStart(opt, c.qualifiedName(), url); - firstInnerTableStart(opt, nRows); - if (c.isInterface()) - tableLine(Align.CENTER, guilWrap(opt, "interface")); - if (c.isEnum()) - tableLine(Align.CENTER, guilWrap(opt, "enumeration")); - stereotype(opt, c, Align.CENTER); - Font font = c.isAbstract() && !c.isInterface() ? Font.CLASS_ABSTRACT : Font.CLASS; - String qualifiedName = qualifiedName(opt, r); - int startTemplate = qualifiedName.indexOf('<'); - int idx = qualifiedName.lastIndexOf('.', startTemplate < 0 ? qualifiedName.length() - 1 : startTemplate); - if (opt.showComment) - tableLine(Align.LEFT, htmlNewline(escape(c.commentText())), opt, Font.CLASS); - else if(opt.postfixPackage && idx > 0 && idx < (qualifiedName.length() - 1)) { - String packageName = qualifiedName.substring(0, idx); - String cn = qualifiedName.substring(idx + 1); - tableLine(Align.CENTER, escape(cn), opt, font); - tableLine(Align.CENTER, packageName, opt, Font.PACKAGE); - } else { - tableLine(Align.CENTER, escape(qualifiedName), opt, font); - } - tagvalue(opt, c); - firstInnerTableEnd(opt, nRows); - - /* - * Warning: The boolean expressions guarding innerTableStart() - * in this block, should match those in the code block above - * marked: "Calculate the number of innerTable rows we will emmit" - */ - if (showMembers) { - if (opt.showAttributes) { - innerTableStart(); - FieldDoc[] fields = c.fields(); - // if there are no fields, print an empty line to generate proper HTML - if (fields.length == 0) - tableLine(Align.LEFT, ""); - else - attributes(opt, c.fields()); - innerTableEnd(); - } else if(!c.isEnum() && (opt.showConstructors || opt.showOperations)) { - // show an emtpy box if we don't show attributes but - // we show operations - innerTableStart(); - tableLine(Align.LEFT, ""); - innerTableEnd(); - } - if (c.isEnum() && opt.showEnumConstants) { - innerTableStart(); - FieldDoc[] ecs = c.enumConstants(); - // if there are no constants, print an empty line to generate proper HTML - if (ecs.length == 0) { - tableLine(Align.LEFT, ""); - } else { - for (FieldDoc fd : c.enumConstants()) { - tableLine(Align.LEFT, fd.name()); - } - } - innerTableEnd(); - } - if (!c.isEnum() && (opt.showConstructors || opt.showOperations)) { - innerTableStart(); - boolean printedLines = false; - if (opt.showConstructors) - printedLines |= operations(opt, c.constructors()); - if (opt.showOperations) - printedLines |= operations(opt, c.methods()); - - if (!printedLines) - // if there are no operations nor constructors, - // print an empty line to generate proper HTML - tableLine(Align.LEFT, ""); - - innerTableEnd(); - } - } - externalTableEnd(); - w.print(", URL=\"" + classToUrl(c, rootClass) + "\""); - nodeProperties(opt); - - // If needed, add a note for this node - int ni = 0; - for (Tag t : c.tags("note")) { - String noteName = "n" + ni + "c" + ci.name; - w.print("\t// Note annotation\n"); - w.print("\t" + noteName + " [label="); - externalTableStart(UmlGraph.getCommentOptions(), c.qualifiedName(), classToUrl(c, rootClass)); - innerTableStart(); - tableLine(Align.LEFT, htmlNewline(escape(t.text())), UmlGraph.getCommentOptions(), Font.CLASS); - innerTableEnd(); - externalTableEnd(); - nodeProperties(UmlGraph.getCommentOptions()); - w.print("\t" + noteName + " -> " + relationNode(c) + "[arrowhead=none];\n"); - ni++; - } - ci.nodePrinted = true; + firstInnerTableStart(opt); + if (c.isInterface()) + tableLine(Align.CENTER, guilWrap(opt, "interface")); + if (c.isEnum()) + tableLine(Align.CENTER, guilWrap(opt, "enumeration")); + stereotype(opt, c, Align.CENTER); + Font font = c.isAbstract() && !c.isInterface() ? Font.CLASS_ABSTRACT : Font.CLASS; + String qualifiedName = qualifiedName(opt, className); + int idx = splitPackageClass(qualifiedName); + if (opt.showComment) + tableLine(Align.LEFT, Font.CLASS.wrap(opt, htmlNewline(escape(c.commentText())))); + else if (opt.postfixPackage && idx > 0 && idx < (qualifiedName.length() - 1)) { + String packageName = qualifiedName.substring(0, idx); + String cn = qualifiedName.substring(idx + 1); + tableLine(Align.CENTER, font.wrap(opt, escape(cn))); + tableLine(Align.CENTER, Font.PACKAGE.wrap(opt, packageName)); + } else { + tableLine(Align.CENTER, font.wrap(opt, escape(qualifiedName))); } - return ci.name; - } + tagvalue(opt, c); + firstInnerTableEnd(opt); - private String getNodeName(ClassDoc c) { - String className = c.toString(); - ClassInfo ci = getClassInfo(className); - if (ci == null) - ci = newClassInfo(className, false, hidden(c)); - return ci.name; - } - - /** Return a class's internal name */ - private String getNodeName(String c) { - ClassInfo ci = getClassInfo(c); + /* + * Warning: The boolean expressions guarding innerTableStart() + * in this block, should match those in the code block above + * marked: "Calculate the number of innerTable rows we will emmit" + */ + if (showMembers) { + if (opt.showAttributes) { + innerTableStart(); + FieldDoc[] fields = c.fields(); + // if there are no fields, print an empty line to generate proper HTML + if (fields.length == 0) + tableLine(Align.LEFT, ""); + else + attributes(opt, c.fields()); + innerTableEnd(); + } else if(!c.isEnum() && (opt.showConstructors || opt.showOperations)) { + // show an emtpy box if we don't show attributes but + // we show operations + innerTableStart(); + tableLine(Align.LEFT, ""); + innerTableEnd(); + } + if (c.isEnum() && opt.showEnumConstants) { + innerTableStart(); + FieldDoc[] ecs = c.enumConstants(); + // if there are no constants, print an empty line to generate proper HTML + if (ecs.length == 0) { + tableLine(Align.LEFT, ""); + } else { + for (FieldDoc fd : c.enumConstants()) { + tableLine(Align.LEFT, fd.name()); + } + } + innerTableEnd(); + } + if (!c.isEnum() && (opt.showConstructors || opt.showOperations)) { + innerTableStart(); + boolean printedLines = false; + if (opt.showConstructors) + printedLines |= operations(opt, c.constructors()); + if (opt.showOperations) + printedLines |= operations(opt, c.methods()); - if (ci == null) - ci = newClassInfo(c, false, false); + if (!printedLines) + // if there are no operations nor constructors, + // print an empty line to generate proper HTML + tableLine(Align.LEFT, ""); + + innerTableEnd(); + } + } + externalTableEnd(); + if (url != null) + w.print(", URL=\"" + url + "\""); + nodeProperties(opt); + + // If needed, add a note for this node + int ni = 0; + for (Tag t : c.tags("note")) { + String noteName = "n" + ni + "c" + ci.name; + w.print(linePrefix + "// Note annotation\n"); + w.print(linePrefix + noteName + " [label="); + externalTableStart(UmlGraph.getCommentOptions(), c.qualifiedName(), url); + innerTableStart(); + tableLine(Align.LEFT, Font.CLASS.wrap(UmlGraph.getCommentOptions(), htmlNewline(escape(t.text())))); + innerTableEnd(); + externalTableEnd(); + nodeProperties(UmlGraph.getCommentOptions()); + ClassInfo ci1 = getClassInfo(c, true); + w.print(linePrefix + noteName + " -> " + ci1.name + "[arrowhead=none];\n"); + ni++; + } + ci.nodePrinted = true; return ci.name; } @@ -630,14 +495,13 @@ class ClassGraph { private void allRelation(Options opt, RelationType rt, ClassDoc from) { String tagname = rt.lower; for (Tag tag : from.tags(tagname)) { - String t[] = StringUtil.tokenize(tag.text()); // l-src label l-dst target + String t[] = tokenize(tag.text()); // l-src label l-dst target + t = t.length == 1 ? new String[] { "-", "-", "-", t[0] } : t; // Shorthand if (t.length != 4) { System.err.println("Error in " + from + "\n" + tagname + " expects four fields (l-src label l-dst target): " + tag.text()); return; } ClassDoc to = from.findClass(t[3]); - - if (to != null) { if(hidden(to)) continue; @@ -659,27 +523,39 @@ class ClassGraph { */ private void relation(Options opt, RelationType rt, ClassDoc from, String fromName, ClassDoc to, String toName, String tailLabel, String label, String headLabel) { + tailLabel = (tailLabel != null && !tailLabel.isEmpty()) ? ",taillabel=\"" + tailLabel + "\"" : ""; + label = (label != null && !label.isEmpty()) ? ",label=\"" + guillemize(opt, label) + "\"" : ""; + headLabel = (headLabel != null && !headLabel.isEmpty()) ? ",headlabel=\"" + headLabel + "\"" : ""; + boolean unLabeled = tailLabel.isEmpty() && label.isEmpty() && headLabel.isEmpty(); + ClassInfo ci1 = getClassInfo(from, fromName, true), ci2 = getClassInfo(to, toName, true); + String n1 = ci1.name, n2 = ci2.name; + // For ranking we need to output extends/implements backwards. + if (rt.backorder) { // Swap: + n1 = ci2.name; + n2 = ci1.name; + String tmp = tailLabel; + tailLabel = headLabel; + headLabel = tmp; + } + Options def = opt.getGlobalOptions(); // print relation - String edgetype = associationMap.get(rt); - w.println("\t// " + fromName + " " + rt.toString() + " " + toName); - w.println("\t" + relationNode(from, fromName) + " -> " + relationNode(to, toName) + " [" + - "taillabel=\"" + tailLabel + "\", " + - ((label == null || label.isEmpty()) ? "label=\"\", " : "label=\"" + guillemize(opt, label) + "\", ") + - "headlabel=\"" + headLabel + "\", " + - "fontname=\"" + opt.edgeFontName + "\", " + - "fontcolor=\"" + opt.edgeFontColor + "\", " + - "fontsize=" + opt.edgeFontSize + ", " + - "color=\"" + opt.edgeColor + "\", " + - edgetype + "];" - ); + w.println(linePrefix + "// " + fromName + " " + rt.lower + " " + toName); + w.println(linePrefix + n1 + " -> " + n2 + " [" + rt.style + + (opt.edgeColor != def.edgeColor ? ",color=\"" + opt.edgeColor + "\"" : "") + + (unLabeled ? "" : + (opt.edgeFontName != def.edgeFontName ? ",fontname=\"" + opt.edgeFontName + "\"" : "") + + (opt.edgeFontColor != def.edgeFontColor ? ",fontcolor=\"" + opt.edgeFontColor + "\"" : "") + + (opt.edgeFontSize != def.edgeFontSize ? ",fontsize=" + fmt(opt.edgeFontSize) : "")) + + tailLabel + label + headLabel + + "];"); // update relation info RelationDirection d = RelationDirection.BOTH; if(rt == RelationType.NAVASSOC || rt == RelationType.DEPEND) d = RelationDirection.OUT; - getClassInfo(fromName).addRelation(toName, rt, d); - getClassInfo(toName).addRelation(fromName, rt, d.inverse()); + ci1.addRelation(toName, rt, d); + ci2.addRelation(fromName, rt, d.inverse()); } /** @@ -693,79 +569,33 @@ class ClassGraph { } - /** Return the full name of a relation's node. - * This may involve appending the port :p for the standard nodes - * whose outline is rendered through an inner table. - */ - private String relationNode(ClassDoc c) { - Options opt = optionProvider.getOptionsFor(c); - String name = getNodeName(c); - return name + opt.shape.landingPort(); - } - - /** Return the full name of a relation's node c. - * This may involve appending the port :p for the standard nodes - * whose outline is rendered through an inner table. - * @param c the node's class (may be null) - * @param cName the node's class name - */ - private String relationNode(ClassDoc c, String cName) { - Options opt; - if (c == null) - opt = optionProvider.getOptionsFor(cName); - else - opt = optionProvider.getOptionsFor(c); - String name = getNodeName(cName); - return name + opt.shape.landingPort(); - } - /** Print a class's relations */ public void printRelations(ClassDoc c) { Options opt = optionProvider.getOptionsFor(c); if (hidden(c) || c.name().equals("")) // avoid phantom classes, they may pop up when the source uses annotations return; - String className = c.toString(); - // Print generalization (through the Java superclass) Type s = c.superclassType(); - if (s != null && - !s.toString().equals("java.lang.Object") && - !c.isEnum() && - !hidden(s.asClassDoc())) { - ClassDoc sc = s.asClassDoc(); - w.println("\t//" + c + " extends " + s + "\n" + - "\t" + relationNode(sc) + " -> " + relationNode(c) + " [dir=back,arrowtail=empty];"); - getClassInfo(className).addRelation(sc.toString(), RelationType.EXTENDS, RelationDirection.OUT); - getClassInfo(sc.toString()).addRelation(className, RelationType.EXTENDS, RelationDirection.IN); - } - + ClassDoc sc = s != null && !s.qualifiedTypeName().equals(Object.class.getName()) ? s.asClassDoc() : null; + if (sc != null && !c.isEnum() && !hidden(sc)) + relation(opt, RelationType.EXTENDS, c, sc, null, null, null); // Print generalizations (through @extends tags) for (Tag tag : c.tags("extends")) - if (!hidden(tag.text())) { - ClassDoc from = c.findClass(tag.text()); - w.println("\t//" + c + " extends " + tag.text() + "\n" + - "\t" + relationNode(from, tag.text()) + " -> " + relationNode(c) + " [dir=back,arrowtail=empty];"); - getClassInfo(className).addRelation(tag.text(), RelationType.EXTENDS, RelationDirection.OUT); - getClassInfo(tag.text()).addRelation(className, RelationType.EXTENDS, RelationDirection.IN); - } + if (!hidden(tag.text())) + relation(opt, RelationType.EXTENDS, c, c.findClass(tag.text()), null, null, null); // Print realizations (Java interfaces) for (Type iface : c.interfaceTypes()) { ClassDoc ic = iface.asClassDoc(); - if (!hidden(ic)) { - w.println("\t//" + c + " implements " + ic + "\n\t" + - relationNode(ic) + " -> " + relationNode(c) + " [dir=back,arrowtail=empty,style=dashed];" - ); - getClassInfo(className).addRelation(ic.toString(), RelationType.IMPLEMENTS, RelationDirection.OUT); - getClassInfo(ic.toString()).addRelation(className, RelationType.IMPLEMENTS, RelationDirection.IN); - } + if (!hidden(ic)) + relation(opt, RelationType.IMPLEMENTS, c, ic, null, null, null); } // Print other associations - allRelation(opt, RelationType.ASSOC, c); - allRelation(opt, RelationType.NAVASSOC, c); - allRelation(opt, RelationType.HAS, c); - allRelation(opt, RelationType.NAVHAS, c); allRelation(opt, RelationType.COMPOSED, c); allRelation(opt, RelationType.NAVCOMPOSED, c); + allRelation(opt, RelationType.HAS, c); + allRelation(opt, RelationType.NAVHAS, c); + allRelation(opt, RelationType.ASSOC, c); + allRelation(opt, RelationType.NAVASSOC, c); allRelation(opt, RelationType.DEPEND, c); } @@ -773,82 +603,69 @@ class ClassGraph { public void printExtraClasses(RootDoc root) { Set names = new HashSet(classnames.keySet()); for(String className: names) { - ClassInfo info = getClassInfo(className); - if (!info.nodePrinted) { - ClassDoc c = root.classNamed(className); - if(c != null) { - printClass(c, false); - } else { - Options opt = optionProvider.getOptionsFor(className); - if(opt.matchesHideExpression(className)) - continue; - w.println("\t// " + className); - w.print("\t" + info.name + "[label="); - externalTableStart(opt, className, classToUrl(className)); - innerTableStart(); - String qualifiedName = qualifiedName(opt, className); - int startTemplate = qualifiedName.indexOf('<'); - int idx = qualifiedName.lastIndexOf('.', startTemplate < 0 ? qualifiedName.length() - 1 : startTemplate); - if(opt.postfixPackage && idx > 0 && idx < (qualifiedName.length() - 1)) { - String packageName = qualifiedName.substring(0, idx); - String cn = qualifiedName.substring(idx + 1); - tableLine(Align.CENTER, escape(cn), opt, Font.CLASS); - tableLine(Align.CENTER, packageName, opt, Font.PACKAGE); - } else { - tableLine(Align.CENTER, escape(qualifiedName), opt, Font.CLASS); - } - innerTableEnd(); - externalTableEnd(); - if (className == null || className.length() == 0) - w.print(", URL=\"" + classToUrl(className) + "\""); - nodeProperties(opt); - } + ClassInfo info = getClassInfo(className, true); + if (info.nodePrinted) + continue; + ClassDoc c = root.classNamed(className); + if(c != null) { + printClass(c, false); + continue; } + // Handle missing classes: + Options opt = optionProvider.getOptionsFor(className); + if(opt.matchesHideExpression(className)) + continue; + w.println(linePrefix + "// " + className); + w.print(linePrefix + info.name + "[label="); + externalTableStart(opt, className, classToUrl(className)); + innerTableStart(); + String qualifiedName = qualifiedName(opt, className); + int startTemplate = qualifiedName.indexOf('<'); + int idx = qualifiedName.lastIndexOf('.', startTemplate < 0 ? qualifiedName.length() - 1 : startTemplate); + if(opt.postfixPackage && idx > 0 && idx < (qualifiedName.length() - 1)) { + String packageName = qualifiedName.substring(0, idx); + String cn = qualifiedName.substring(idx + 1); + tableLine(Align.CENTER, Font.CLASS.wrap(opt, escape(cn))); + tableLine(Align.CENTER, Font.PACKAGE.wrap(opt, packageName)); + } else { + tableLine(Align.CENTER, Font.CLASS.wrap(opt, escape(qualifiedName))); + } + innerTableEnd(); + externalTableEnd(); + if (className == null || className.length() == 0) + w.print(",URL=\"" + classToUrl(className) + "\""); + nodeProperties(opt); } } - /** - * Prints associations recovered from the fields of a class. An association is inferred only - * if another relation between the two classes is not already in the graph. - * @param classes - */ - public void printInferredRelations(ClassDoc[] classes) { - for (ClassDoc c : classes) { - printInferredRelations(c); - } - } - /** * Prints associations recovered from the fields of a class. An association is inferred only * if another relation between the two classes is not already in the graph. * @param classes */ public void printInferredRelations(ClassDoc c) { - Options opt = optionProvider.getOptionsFor(c); - // check if the source is excluded from inference if (hidden(c)) return; + Options opt = optionProvider.getOptionsFor(c); + for (FieldDoc field : c.fields(false)) { if(hidden(field)) continue; - // skip statics if(field.isStatic()) continue; - // skip primitives FieldRelationInfo fri = getFieldRelationInfo(field); if (fri == null) continue; - // check if the destination is excluded from inference if (hidden(fri.cd)) continue; // if source and dest are not already linked, add a dependency - RelationPattern rp = getClassInfo(c.toString()).getRelation(fri.cd.toString()); + RelationPattern rp = getClassInfo(c, true).getRelation(fri.cd.toString()); if (rp == null) { String destAdornment = fri.multiple ? "*" : ""; relation(opt, opt.inferRelationshipType, c, fri.cd, "", "", destAdornment); @@ -856,18 +673,6 @@ class ClassGraph { } } - /** - * Prints dependencies recovered from the methods of a class. A - * dependency is inferred only if another relation between the two - * classes is not already in the graph. - * @param classes - */ - public void printInferredDependencies(ClassDoc[] classes) { - for (ClassDoc c : classes) { - printInferredDependencies(c); - } - } - /** Returns an array representing the imported classes of c. * Disables the deprecation warning, which is output, because the * imported classed are an implementation detail. @@ -884,12 +689,10 @@ class ClassGraph { * @param classes */ public void printInferredDependencies(ClassDoc c) { - Options opt = optionProvider.getOptionsFor(c); - - String sourceName = c.toString(); if (hidden(c)) return; + Options opt = optionProvider.getOptionsFor(c); Set types = new HashSet(); // harvest method return and parameter types for (MethodDoc method : filterByVisibility(c.methods(false), opt.inferDependencyVisibility)) { @@ -939,7 +742,7 @@ class ClassGraph { continue; // if source and dest are not already linked, add a dependency - RelationPattern rp = getClassInfo(sourceName).getRelation(fc.toString()); + RelationPattern rp = getClassInfo(c, true).getRelation(fc.toString()); if (rp == null || rp.matchesOne(new RelationPattern(RelationDirection.OUT))) { relation(opt, RelationType.DEPEND, c, fc, "", "", ""); } @@ -1015,120 +818,36 @@ class ClassGraph { return null; } - /** Removes the template specs from a class name. */ - private String removeTemplate(String name) { - int openIdx = name.indexOf('<'); - if(openIdx == -1) - return name; - StringBuilder buf = new StringBuilder(name.length()); - for (int i = 0, depth = 0; i < name.length(); i++) { - char c = name.charAt(i); - if (c == '<') - depth++; - else if (c == '>') - depth--; - else if (depth == 0) - buf.append(c); - } - return buf.toString(); - } - /** Convert the class name into a corresponding URL */ public String classToUrl(ClassDoc cd, boolean rootClass) { // building relative path for context and package diagrams - if(contextDoc != null && rootClass) { - // determine the context path, relative to the root - String packageName; - if (contextDoc instanceof ClassDoc) { - packageName = ((ClassDoc) contextDoc).containingPackage().name(); - } else if (contextDoc instanceof PackageDoc) { - packageName = ((PackageDoc) contextDoc).name(); - } else { - return classToUrl(cd.qualifiedName()); - } - return buildRelativePath(packageName, cd.containingPackage().name()) + cd.name() + ".html"; - } else { - return classToUrl(cd.qualifiedName()); - } + if(contextPackageName != null && rootClass) + return buildRelativePathFromClassNames(contextPackageName, cd.containingPackage().name()) + cd.name() + ".html"; + return classToUrl(cd.qualifiedName()); } - protected static String buildRelativePath(String contextPackageName, String classPackageName) { - // path, relative to the root, of the destination class - String[] contextClassPath = contextPackageName.split("\\."); - String[] currClassPath = classPackageName.split("\\."); - - // compute relative path between the context and the destination - // ... first, compute common part - int i = 0; - while (i < contextClassPath.length && i < currClassPath.length - && contextClassPath[i].equals(currClassPath[i])) - i++; - // ... go up with ".." to reach the common root - StringBuilder buf = new StringBuilder(); - if (i == contextClassPath.length) { - buf.append(".").append(FILE_SEPARATOR); - } else { - for (int j = i; j < contextClassPath.length; j++) { - buf.append("..").append(FILE_SEPARATOR); - } - } - // ... go down from the common root to the destination - for (int j = i; j < currClassPath.length; j++) { - buf.append(currClassPath[j]).append(FILE_SEPARATOR); - } - return buf.toString(); - } - - private String getPackageName(String className) { - if (this.rootClassdocs.get(className) == null) { - int idx = className.lastIndexOf('.'); - return idx > 0 ? className.substring(0, idx) : ""; - } else { - return this.rootClassdocs.get(className).containingPackage().name(); - } - } - - private String getUnqualifiedName(String className) { - if (this.rootClassdocs.get(className) == null) { - int idx = className.lastIndexOf('.'); - return idx > 0 ? className.substring(idx + 1) : className; - } else { - return this.rootClassdocs.get(className).name(); - } - } - /** Convert the class name into a corresponding URL */ public String classToUrl(String className) { - String docRoot = mapApiDocRoot(className); - if (docRoot != null) { - StringBuilder buf = new StringBuilder(docRoot); - buf.append(getPackageName(className).replace('.', FILE_SEPARATOR) + FILE_SEPARATOR); - buf.append(getUnqualifiedName(className)); - buf.append(".html"); - return buf.toString(); - } else { - return null; - } - } - - /** - * Returns the appropriate URL "root" for a given class name. - * The root will be used as the prefix of the URL used to link the class in - * the final diagram to the associated JavaDoc page. - */ - private String mapApiDocRoot(String className) { - String root; - /* If no packages are specified, we use apiDocRoot for all of them. */ - if (rootClasses.contains(className)) { - root = optionProvider.getGlobalOptions().apiDocRoot; - } else { - Options globalOptions = optionProvider.getGlobalOptions(); - root = globalOptions.getApiDocRoot(className); + ClassDoc classDoc = rootClassdocs.get(className); + if (classDoc != null) { + String docRoot = optionProvider.getGlobalOptions().apiDocRoot; + if (docRoot == null) + return null; + return new StringBuilder(docRoot.length() + className.length() + 10).append(docRoot) // + .append(classDoc.containingPackage().name().replace('.', '/')) // + .append('/').append(classDoc.name()).append(".html").toString(); } - return root; + String docRoot = optionProvider.getGlobalOptions().getApiDocRoot(className); + if (docRoot == null) + return null; + int split = splitPackageClass(className); + StringBuilder buf = new StringBuilder(docRoot.length() + className.length() + 10).append(docRoot); + if (split > 0) // Avoid -1, and the extra slash then. + buf.append(className.substring(0, split).replace('.', '/')).append('/'); + return buf.append(className, Math.min(split + 1, className.length()), className.length()) // + .append(".html").toString(); } - /** Dot prologue * @throws IOException */ public void prologue() throws IOException { @@ -1140,11 +859,7 @@ class ClassGraph { else { // prepare output file. Use the output file name as a full path unless the output // directory is specified - File file; - if (opt.outputDirectory != null) - file = new File(opt.outputDirectory, opt.outputFileName); - else - file = new File(opt.outputFileName); + File file = new File(opt.outputDirectory, opt.outputFileName); // make sure the output directory are there, otherwise create them if (file.getParentFile() != null && !file.getParentFile().exists()) @@ -1162,19 +877,24 @@ class ClassGraph { Version.VERSION + " (http://www.spinellis.gr/umlgraph/)\n" + "#\n\n" + "digraph G {\n" + - "\tedge [fontname=\"" + opt.edgeFontName + - "\",fontsize=10,labelfontname=\"" + opt.edgeFontName + - "\",labelfontsize=10];\n" + - "\tnode [fontname=\"" + opt.nodeFontName + - "\",fontsize=10,shape=plaintext];" + linePrefix + "graph [fontnames=\"svg\"]\n" + + linePrefix + "edge [fontname=\"" + opt.edgeFontName + + "\",fontsize=" + fmt(opt.edgeFontSize) + + ",labelfontname=\"" + opt.edgeFontName + + "\",labelfontsize=" + fmt(opt.edgeFontSize) + + ",color=\"" + opt.edgeColor + "\"];\n" + + linePrefix + "node [fontname=\"" + opt.nodeFontName + + "\",fontcolor=\"" + opt.nodeFontColor + + "\",fontsize=" + fmt(opt.nodeFontSize) + + ",shape=plaintext,margin=0,width=0,height=0];" ); - w.println("\tnodesep=" + opt.nodeSep + ";"); - w.println("\tranksep=" + opt.rankSep + ";"); + w.println(linePrefix + "nodesep=" + opt.nodeSep + ";"); + w.println(linePrefix + "ranksep=" + opt.rankSep + ";"); if (opt.horizontal) - w.println("\trankdir=LR;"); + w.println(linePrefix + "rankdir=LR;"); if (opt.bgColor != null) - w.println("\tbgcolor=\"" + opt.bgColor + "\";\n"); + w.println(linePrefix + "bgcolor=\"" + opt.bgColor + "\";\n"); } /** Dot epilogue */ @@ -1185,16 +905,11 @@ class ClassGraph { } private void externalTableStart(Options opt, String name, String url) { - String bgcolor = ""; - if (opt.nodeFillColor != null) - bgcolor = " bgcolor=\""+ opt.nodeFillColor + "\""; - String href = ""; - if (url != null) - href = " href=\"" + url + "\" target=\"_parent\""; - + String bgcolor = opt.nodeFillColor == null ? "" : (" bgcolor=\"" + opt.nodeFillColor + "\""); + String href = url == null ? "" : (" href=\"" + url + "\" target=\"_parent\""); w.print("<" + linePostfix); + "cellpadding=\"2\"" + bgcolor + href + ">" + linePostfix); } private void externalTableEnd() { @@ -1208,10 +923,9 @@ class ClassGraph { /** * Start the first inner table of a class. - * @param nRows the total number of rows in this table. */ - private void firstInnerTableStart(Options opt, int nRows) { - w.print(linePrefix + linePrefix + "" + opt.shape.extraColumn(nRows) + + private void firstInnerTableStart(Options opt) { + w.print(linePrefix + linePrefix + "" + opt.shape.extraColumn() + "" + - opt.shape.extraColumn(nRows) + "" + linePostfix); + opt.shape.extraColumn() + "" + linePostfix); } private void tableLine(Align align, String text) { - tableLine(align, text, null, Font.NORMAL); + w.print(linePrefix + linePrefix // + + "" + linePostfix); } - - private void tableLine(Align align, String text, Options opt, Font font) { - String open; - String close = ""; - String prefix = linePrefix + linePrefix + linePrefix; - String alignText; - if(align == Align.CENTER) - alignText = "center"; - else if(align == Align.LEFT) - alignText = "left"; - else if(align == Align.RIGHT) - alignText = "right"; - else - throw new RuntimeException("Unknown alignement type " + align); - - text = fontWrap(" " + text + " ", opt, font); - open = "") : ""; + public String extraColumn() { + return this == Shape.ACTIVECLASS ? ("") : ""; } /** Return the cell border required for the shape */ - String cellBorder() { - return (name.equals("class") || name.equals("activeclass")) ? "1" : "0"; + public String cellBorder() { + return this == CLASS || this == ACTIVECLASS ? "1" : "0"; } } diff --git a/src/main/java/org/umlgraph/doclet/StringUtil.java b/src/main/java/org/umlgraph/doclet/StringUtil.java index 2aa9eac..e122e0b 100644 --- a/src/main/java/org/umlgraph/doclet/StringUtil.java +++ b/src/main/java/org/umlgraph/doclet/StringUtil.java @@ -20,9 +20,11 @@ package org.umlgraph.doclet; import java.util.*; +import java.util.regex.Pattern; /** * String utility functions + * * @version $Revision$ * @author Diomidis Spinellis */ @@ -62,4 +64,168 @@ class StringUtil { return r.toArray(new String[0]); } + private final static Pattern ESCAPE_BASIC_XML = Pattern.compile("[&<>]"); + + /** + * Escape <, >, and & characters in the string with the corresponding + * HTML entity code. + */ + public static String escape(String s) { + if (ESCAPE_BASIC_XML.matcher(s).find()) { + StringBuilder sb = new StringBuilder(s); + for (int i = 0; i < sb.length();) { + switch (sb.charAt(i)) { + case '&': + sb.replace(i, i + 1, "&"); + i += "&".length(); + break; + case '<': + sb.replace(i, i + 1, "<"); + i += "<".length(); + break; + case '>': + sb.replace(i, i + 1, ">"); + i += ">".length(); + break; + default: + i++; + } + } + return sb.toString(); + } else + return s; + } + + /** + * Convert embedded newlines into HTML line breaks + */ + public static String htmlNewline(String s) { + if (s.indexOf('\n') == -1) + return s; + + StringBuilder sb = new StringBuilder(s); + for (int i = 0; i < sb.length();) { + if (sb.charAt(i) == '\n') { + sb.replace(i, i + 1, "
    "); + i += "
    ".length(); + } else + i++; + } + return sb.toString(); + } + + /** + * Convert < and > characters in the string to the respective guillemot + * characters. + */ + public static String guillemize(Options opt, String s) { + StringBuilder r = new StringBuilder(s); + for (int i = 0; i < r.length();) + switch (r.charAt(i)) { + case '<': + r.replace(i, i + 1, opt.guilOpen); + i += opt.guilOpen.length(); + break; + case '>': + r.replace(i, i + 1, opt.guilClose); + i += opt.guilClose.length(); + break; + default: + i++; + break; + } + return r.toString(); + } + + /** + * Wraps a string in Guillemot (or an ASCII substitute) characters. + * + * @param str the String to be wrapped. + * @return the wrapped String. + */ + public static String guilWrap(Options opt, String str) { + return opt.guilOpen + str + opt.guilClose; + } + + /** Removes the template specs from a class name. */ + public static String removeTemplate(String name) { + int openIdx = name.indexOf('<'); + if (openIdx == -1) + return name; + StringBuilder buf = new StringBuilder(name.length()); + for (int i = 0, depth = 0; i < name.length(); i++) { + char c = name.charAt(i); + if (c == '<') + depth++; + else if (c == '>') + depth--; + else if (depth == 0) + buf.append(c); + } + return buf.toString(); + } + + public static String buildRelativePathFromClassNames(String contextPackageName, String classPackageName) { + // path, relative to the root, of the destination class + String[] contextClassPath = contextPackageName.split("\\."); + String[] currClassPath = classPackageName.split("\\."); + + // compute relative path between the context and the destination + // ... first, compute common part + int i = 0, e = Math.min(contextClassPath.length, currClassPath.length); + while (i < e && contextClassPath[i].equals(currClassPath[i])) + i++; + // ... go up with ".." to reach the common root + StringBuilder buf = new StringBuilder(classPackageName.length()); + for (int j = i; j < contextClassPath.length; j++) + buf.append("../"); + // ... go down from the common root to the destination + for (int j = i; j < currClassPath.length; j++) + buf.append(currClassPath[j]).append('/'); // Always use HTML seperators + return buf.toString(); + } + + /** + * We can't just always use the last dot, because there are inner classes. And + * these may have frequent names. But the prime example is + * {@link java.util.Map.Entry}, which we want to show up as package + * java.util and class Map.Entry. + *

    + * Note: this is only a heuristic. We only have the string here, and must assume + * users adhere to Java conventions, of beginning package names with a lowercase + * letter. + * + * @param className + * @return Splitting point (Either referring to a dot, or -1) + */ + public static int splitPackageClass(String className) { + int gen = className.indexOf('<'); // Begin before generics. + int end = gen >= 0 ? gen : className.length(); + int start = className.lastIndexOf('.', end); + // No package name special cases: + if (start < 0) + return gen >= 0 || className.isEmpty() ? -1 // + : Character.isLowerCase(className.charAt(0)) ? end : -1; + int split = end; + while (true) { + if (Character.isLowerCase(className.charAt(start + 1))) + return split; + split = start; // Continue, this looks like a class name. + if (start < 0) + return -1; + start = className.lastIndexOf('.', start - 1); + } + } + + /** + * Format a double to a string. + *

    + * Avoids printing "10.0" for exact values like 10. + * + * @param val Value + * @return Formatted value + */ + public static String fmt(double val) { + return val == Math.round(val) ? Long.toString((long) val) : Double.toString(val); + } } diff --git a/src/main/java/org/umlgraph/doclet/SubclassMatcher.java b/src/main/java/org/umlgraph/doclet/SubclassMatcher.java index 0588eda..999b823 100644 --- a/src/main/java/org/umlgraph/doclet/SubclassMatcher.java +++ b/src/main/java/org/umlgraph/doclet/SubclassMatcher.java @@ -25,17 +25,12 @@ public class SubclassMatcher implements ClassMatcher { return true; // recurse on supeclass, if available - if(cd.superclass() != null) - return matches(cd.superclass()); - - return false; + return cd.superclass() == null ? false : matches(cd.superclass()); } public boolean matches(String name) { ClassDoc cd = root.classNamed(name); - if(cd == null) - return false; - return matches(cd); + return cd == null ? false : matches(cd); } } diff --git a/src/main/java/org/umlgraph/doclet/UmlGraph.java b/src/main/java/org/umlgraph/doclet/UmlGraph.java index 7087772..edd3825 100644 --- a/src/main/java/org/umlgraph/doclet/UmlGraph.java +++ b/src/main/java/org/umlgraph/doclet/UmlGraph.java @@ -84,7 +84,7 @@ public class UmlGraph { commentOptions = new Options(); commentOptions.setOptions(root.options()); commentOptions.setOptions(findClass(root, "UMLNoteOptions")); - commentOptions.shape = new Shape("note"); + commentOptions.shape = Shape.NOTE; Options opt = new Options(); opt.setOptions(root.options()); @@ -113,14 +113,16 @@ public class UmlGraph { ClassGraph c = new ClassGraph(root, op, contextDoc); c.prologue(); - for (int i = 0; i < classes.length; i++) - c.printClass(classes[i], true); - for (int i = 0; i < classes.length; i++) - c.printRelations(classes[i]); + for (ClassDoc cd : classes) + c.printClass(cd, true); + for (ClassDoc cd : classes) + c.printRelations(cd); if(opt.inferRelationships) - c.printInferredRelations(classes); + for (ClassDoc cd : classes) + c.printInferredRelations(cd); if(opt.inferDependencies) - c.printInferredDependencies(classes); + for (ClassDoc cd : classes) + c.printInferredDependencies(cd); c.printExtraClasses(root); c.epilogue(); diff --git a/src/main/java/org/umlgraph/doclet/UmlGraphDoc.java b/src/main/java/org/umlgraph/doclet/UmlGraphDoc.java index fe6bbf1..dca406f 100644 --- a/src/main/java/org/umlgraph/doclet/UmlGraphDoc.java +++ b/src/main/java/org/umlgraph/doclet/UmlGraphDoc.java @@ -62,12 +62,10 @@ public class UmlGraphDoc { opt.strictMatching = true; // root.printNotice(opt.toString()); - root = new WrappedRootDoc(root); generatePackageDiagrams(root, opt, outputFolder); generateContextDiagrams(root, opt, outputFolder); } catch(Throwable t) { - root.printWarning("Error!"); - root.printWarning(t.toString()); + root.printWarning("Error: " + t.toString()); t.printStackTrace(); return false; } @@ -117,14 +115,18 @@ public class UmlGraphDoc { ContextView view = null; for (ClassDoc classDoc : classDocs) { - if(view == null) - view = new ContextView(outputFolder, classDoc, root, opt); - else - view.setContextCenter(classDoc); - UmlGraph.buildGraph(root, view, classDoc); - runGraphviz(opt.dotExecutable, outputFolder, classDoc.containingPackage().name(), classDoc.name(), root); - alterHtmlDocs(opt, outputFolder, classDoc.containingPackage().name(), classDoc.name(), - classDoc.name() + ".html", Pattern.compile(".*(Class|Interface|Enum) " + classDoc.name() + ".*") , root); + try { + if(view == null) + view = new ContextView(outputFolder, classDoc, root, opt); + else + view.setContextCenter(classDoc); + UmlGraph.buildGraph(root, view, classDoc); + runGraphviz(opt.dotExecutable, outputFolder, classDoc.containingPackage().name(), classDoc.name(), root); + alterHtmlDocs(opt, outputFolder, classDoc.containingPackage().name(), classDoc.name(), + classDoc.name() + ".html", Pattern.compile(".*(Class|Interface|Enum) " + classDoc.name() + ".*") , root); + } catch (Exception e) { + throw new RuntimeException("Error generating " + classDoc.name(), e); + } } } diff --git a/src/main/java/org/umlgraph/doclet/Version.java b/src/main/java/org/umlgraph/doclet/Version.java index 0c0439e..03f857d 100644 --- a/src/main/java/org/umlgraph/doclet/Version.java +++ b/src/main/java/org/umlgraph/doclet/Version.java @@ -1,4 +1,4 @@ /* Automatically generated file */ package org.umlgraph.doclet; -class Version { public static String VERSION = "R5_7_2-49-ge25953";} +class Version { public static String VERSION = "R5_7_2-60-g0e99a6";} \ No newline at end of file diff --git a/src/main/java/org/umlgraph/doclet/View.java b/src/main/java/org/umlgraph/doclet/View.java index 808afd7..8659a1c 100644 --- a/src/main/java/org/umlgraph/doclet/View.java +++ b/src/main/java/org/umlgraph/doclet/View.java @@ -140,36 +140,30 @@ public class View implements OptionProvider { boolean outputSet = false; for (String[] opts : globalOptions) { - if (opts[0].equals("-output")) + if (Options.matchOption(opts[0], "output")) outputSet = true; go.setOption(opts); } if (!outputSet) - go.setOption(new String[] { "-output", viewDoc.name() + ".dot" }); + go.setOption(new String[] { "output", viewDoc.name() + ".dot" }); return go; } public void overrideForClass(Options opt, ClassDoc cd) { provider.overrideForClass(opt, cd); - for (ClassMatcher cm : optionOverrides.keySet()) { - if(cm.matches(cd)) { - for (String[] override : optionOverrides.get(cm)) { + for (ClassMatcher cm : optionOverrides.keySet()) + if(cm.matches(cd)) + for (String[] override : optionOverrides.get(cm)) opt.setOption(override); - } - } - } } public void overrideForClass(Options opt, String className) { provider.overrideForClass(opt, className); - for (ClassMatcher cm : optionOverrides.keySet()) { - if(cm.matches(className)) { - for (String[] override : optionOverrides.get(cm)) { + for (ClassMatcher cm : optionOverrides.keySet()) + if(cm.matches(className)) + for (String[] override : optionOverrides.get(cm)) opt.setOption(override); - } - } - } } public String getDisplayName() { diff --git a/src/main/java/org/umlgraph/doclet/Visibility.java b/src/main/java/org/umlgraph/doclet/Visibility.java index 0e631f6..408a551 100644 --- a/src/main/java/org/umlgraph/doclet/Visibility.java +++ b/src/main/java/org/umlgraph/doclet/Visibility.java @@ -24,10 +24,15 @@ import com.sun.javadoc.ProgramElementDoc; * Enumerates the possible visibilities in a Java program. For brevity, package * private visibility is referred as PACKAGE. * @author wolf - * */ public enum Visibility { - PRIVATE, PACKAGE, PROTECTED, PUBLIC; + PRIVATE("- "), PACKAGE("~ "), PROTECTED("# "), PUBLIC("+ "); + + final public String symbol; + + private Visibility(String symbol) { + this.symbol = symbol; + } public static Visibility get(ProgramElementDoc doc) { if (doc.isPrivate()) @@ -38,6 +43,5 @@ public enum Visibility { return PROTECTED; else return PUBLIC; - } -} \ No newline at end of file +} diff --git a/src/main/java/org/umlgraph/doclet/WrappedClassDoc.java b/src/main/java/org/umlgraph/doclet/WrappedClassDoc.java deleted file mode 100644 index 081e458..0000000 --- a/src/main/java/org/umlgraph/doclet/WrappedClassDoc.java +++ /dev/null @@ -1,369 +0,0 @@ -/* - * Create a graphviz graph based on the classes in the specified java - * source files. - * - * (C) Copyright 2002-2005 Diomidis Spinellis - * - * Permission to use, copy, and distribute this software and its - * documentation for any purpose and without fee is hereby granted, - * provided that the above copyright notice appear in all copies and that - * both that copyright notice and this permission notice appear in - * supporting documentation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF - * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * - */ - -package org.umlgraph.doclet; - -import com.sun.javadoc.AnnotatedType; -import com.sun.javadoc.AnnotationDesc; -import com.sun.javadoc.AnnotationTypeDoc; -import com.sun.javadoc.ClassDoc; -import com.sun.javadoc.ConstructorDoc; -import com.sun.javadoc.FieldDoc; -import com.sun.javadoc.MethodDoc; -import com.sun.javadoc.PackageDoc; -import com.sun.javadoc.ParamTag; -import com.sun.javadoc.ParameterizedType; -import com.sun.javadoc.SeeTag; -import com.sun.javadoc.SourcePosition; -import com.sun.javadoc.Tag; -import com.sun.javadoc.Type; -import com.sun.javadoc.TypeVariable; -import com.sun.javadoc.WildcardType; - -/** - * A ClassDoc wrapper that caches answer to the most common requests performed - * by UMLGraph, considerably improving the overall UMLDoc performance (ClassDoc - * computes most of the results for more fine grained information at each call). - *

    - * Unfortunately this has a side effect, since it breaks the equals() call between - * plain ClassDoc instances and WrappedClassDoc ones, so use it with due care. - *

    - * In particular, don't provide WrappedClassDoc instances to the standard doclet. - * @author wolf - * - */ -public class WrappedClassDoc implements ClassDoc { - ClassDoc wrapped; - String toString; - String name; - Tag[] tags; - - public WrappedClassDoc(ClassDoc wrapped) { - this.wrapped = wrapped; - } - - public AnnotationDesc[] annotations() { - return wrapped.annotations(); - } - - public AnnotationTypeDoc asAnnotationTypeDoc() { - return wrapped.asAnnotationTypeDoc(); - } - - public ClassDoc asClassDoc() { - return wrapped.asClassDoc(); - } - - public ParameterizedType asParameterizedType() { - return wrapped.asParameterizedType(); - } - - public TypeVariable asTypeVariable() { - return wrapped.asTypeVariable(); - } - - public WildcardType asWildcardType() { - return wrapped.asWildcardType(); - } - - public String commentText() { - return wrapped.commentText(); - } - - public int compareTo(Object arg0) { - if (arg0 instanceof WrappedClassDoc) { - WrappedClassDoc other = (WrappedClassDoc) arg0; - return wrapped.compareTo(other.wrapped); - } - return wrapped.compareTo(arg0); - } - - public ConstructorDoc[] constructors() { - return wrapped.constructors(); - } - - public ConstructorDoc[] constructors(boolean arg0) { - return wrapped.constructors(arg0); - } - - public ClassDoc containingClass() { - return wrapped.containingClass(); - } - - public PackageDoc containingPackage() { - return wrapped.containingPackage(); - } - - public boolean definesSerializableFields() { - return wrapped.definesSerializableFields(); - } - - public String dimension() { - return wrapped.dimension(); - } - - public FieldDoc[] enumConstants() { - return wrapped.enumConstants(); - } - - public FieldDoc[] fields() { - return wrapped.fields(); - } - - public FieldDoc[] fields(boolean arg0) { - return wrapped.fields(arg0); - } - - public ClassDoc findClass(String arg0) { - return wrapped.findClass(arg0); - } - - public Tag[] firstSentenceTags() { - return wrapped.firstSentenceTags(); - } - - public String getRawCommentText() { - return wrapped.getRawCommentText(); - } - - /** @deprecated */ - public @Deprecated ClassDoc[] importedClasses() { - return wrapped.importedClasses(); - } - - /** @deprecated */ - public @Deprecated PackageDoc[] importedPackages() { - return wrapped.importedPackages(); - } - - public Tag[] inlineTags() { - return wrapped.inlineTags(); - } - - public ClassDoc[] innerClasses() { - return wrapped.innerClasses(); - } - - public ClassDoc[] innerClasses(boolean arg0) { - return wrapped.innerClasses(arg0); - } - - public ClassDoc[] interfaces() { - return wrapped.interfaces(); - } - - public Type[] interfaceTypes() { - return wrapped.interfaceTypes(); - } - - public boolean isAbstract() { - return wrapped.isAbstract(); - } - - public boolean isAnnotationType() { - return wrapped.isAnnotationType(); - } - - public boolean isAnnotationTypeElement() { - return wrapped.isAnnotationTypeElement(); - } - - public boolean isClass() { - return wrapped.isClass(); - } - - public boolean isConstructor() { - return wrapped.isConstructor(); - } - - public boolean isEnum() { - return wrapped.isEnum(); - } - - public boolean isEnumConstant() { - return wrapped.isEnumConstant(); - } - - public boolean isError() { - return wrapped.isError(); - } - - public boolean isException() { - return wrapped.isException(); - } - - public boolean isExternalizable() { - return wrapped.isExternalizable(); - } - - public boolean isField() { - return wrapped.isField(); - } - - public boolean isFinal() { - return wrapped.isFinal(); - } - - public boolean isIncluded() { - return wrapped.isIncluded(); - } - - public boolean isInterface() { - return wrapped.isInterface(); - } - - public boolean isMethod() { - return wrapped.isMethod(); - } - - public boolean isOrdinaryClass() { - return wrapped.isOrdinaryClass(); - } - - public boolean isPackagePrivate() { - return wrapped.isPackagePrivate(); - } - - public boolean isPrimitive() { - return wrapped.isPrimitive(); - } - - public boolean isPrivate() { - return wrapped.isPrivate(); - } - - public boolean isProtected() { - return wrapped.isProtected(); - } - - public boolean isPublic() { - return wrapped.isPublic(); - } - - public boolean isSerializable() { - return wrapped.isSerializable(); - } - - public boolean isStatic() { - return wrapped.isStatic(); - } - - public MethodDoc[] methods() { - return wrapped.methods(); - } - - public MethodDoc[] methods(boolean arg0) { - return wrapped.methods(arg0); - } - - public String modifiers() { - return wrapped.modifiers(); - } - - public int modifierSpecifier() { - return wrapped.modifierSpecifier(); - } - - public String name() { - if (name == null) - name = wrapped.name(); - return name; - } - - public SourcePosition position() { - return wrapped.position(); - } - - public String qualifiedName() { - return wrapped.qualifiedName(); - } - - public String qualifiedTypeName() { - return wrapped.qualifiedTypeName(); - } - - public SeeTag[] seeTags() { - return wrapped.seeTags(); - } - - public FieldDoc[] serializableFields() { - return wrapped.serializableFields(); - } - - public MethodDoc[] serializationMethods() { - return wrapped.serializationMethods(); - } - - public void setRawCommentText(String arg0) { - wrapped.setRawCommentText(arg0); - } - - public String simpleTypeName() { - return wrapped.simpleTypeName(); - } - - public boolean subclassOf(ClassDoc arg0) { - return wrapped.subclassOf(arg0); - } - - public ClassDoc superclass() { - return wrapped.superclass(); - } - - public Type superclassType() { - return wrapped.superclassType(); - } - - public Tag[] tags() { - if (tags == null) - tags = wrapped.tags(); - return tags; - } - - public Tag[] tags(String arg0) { - return wrapped.tags(arg0); - } - - public String toString() { - if (toString == null) { - toString = wrapped.toString(); - } - return toString; - } - - public String typeName() { - return wrapped.typeName(); - } - - public TypeVariable[] typeParameters() { - return wrapped.typeParameters(); - } - - public ParamTag[] typeParamTags() { - return wrapped.typeParamTags(); - } - - public AnnotatedType asAnnotatedType() { - return wrapped.asAnnotatedType(); - } - - public Type getElementType() { - return wrapped.getElementType(); - } -} diff --git a/src/main/java/org/umlgraph/doclet/WrappedRootDoc.java b/src/main/java/org/umlgraph/doclet/WrappedRootDoc.java deleted file mode 100644 index 0bfc396..0000000 --- a/src/main/java/org/umlgraph/doclet/WrappedRootDoc.java +++ /dev/null @@ -1,191 +0,0 @@ -/* - * Create a graphviz graph based on the classes in the specified java - * source files. - * - * (C) Copyright 2002-2005 Diomidis Spinellis - * - * Permission to use, copy, and distribute this software and its - * documentation for any purpose and without fee is hereby granted, - * provided that the above copyright notice appear in all copies and that - * both that copyright notice and this permission notice appear in - * supporting documentation. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF - * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * - */ - -package org.umlgraph.doclet; - -import com.sun.javadoc.ClassDoc; -import com.sun.javadoc.PackageDoc; -import com.sun.javadoc.RootDoc; -import com.sun.javadoc.SeeTag; -import com.sun.javadoc.SourcePosition; -import com.sun.javadoc.Tag; - -/** - * RootDoc wrapper that provides WrappedClassDoc instances instead of plain ClassDoc in order - * to optimize the overall performance of UMLDoc. - * @author wolf - */ -public class WrappedRootDoc implements RootDoc { - RootDoc wrapped; - WrappedClassDoc[] wrappedClassDocs; - - public WrappedRootDoc(RootDoc wrapped) { - this.wrapped = wrapped; - ClassDoc[] classes = wrapped.classes(); - wrappedClassDocs = new WrappedClassDoc[classes.length]; - for (int i = 0; i < classes.length; i++) { - wrappedClassDocs[i] = new WrappedClassDoc(classes[i]); - } - } - - public ClassDoc[] classes() { - return wrappedClassDocs; - } - - public ClassDoc classNamed(String arg0) { - return wrapped.classNamed(arg0); - } - - public String commentText() { - return wrapped.commentText(); - } - - public int compareTo(Object arg0) { - return wrapped.compareTo(arg0); - } - - public Tag[] firstSentenceTags() { - return wrapped.firstSentenceTags(); - } - - public String getRawCommentText() { - return wrapped.getRawCommentText(); - } - - public Tag[] inlineTags() { - return wrapped.inlineTags(); - } - - public boolean isAnnotationType() { - return wrapped.isAnnotationType(); - } - - public boolean isAnnotationTypeElement() { - return wrapped.isAnnotationTypeElement(); - } - - public boolean isClass() { - return wrapped.isClass(); - } - - public boolean isConstructor() { - return wrapped.isConstructor(); - } - - public boolean isEnum() { - return wrapped.isEnum(); - } - - public boolean isEnumConstant() { - return wrapped.isEnumConstant(); - } - - public boolean isError() { - return wrapped.isError(); - } - - public boolean isException() { - return wrapped.isException(); - } - - public boolean isField() { - return wrapped.isField(); - } - - public boolean isIncluded() { - return wrapped.isIncluded(); - } - - public boolean isInterface() { - return wrapped.isInterface(); - } - - public boolean isMethod() { - return wrapped.isMethod(); - } - - public boolean isOrdinaryClass() { - return wrapped.isOrdinaryClass(); - } - - public String name() { - return wrapped.name(); - } - - public String[][] options() { - return wrapped.options(); - } - - public PackageDoc packageNamed(String arg0) { - return wrapped.packageNamed(arg0); - } - - public SourcePosition position() { - return wrapped.position(); - } - - public void printError(SourcePosition arg0, String arg1) { - wrapped.printError(arg0, arg1); - } - - public void printError(String arg0) { - wrapped.printError(arg0); - } - - public void printNotice(SourcePosition arg0, String arg1) { - wrapped.printNotice(arg0, arg1); - } - - public void printNotice(String arg0) { - wrapped.printNotice(arg0); - } - - public void printWarning(SourcePosition arg0, String arg1) { - wrapped.printWarning(arg0, arg1); - } - - public void printWarning(String arg0) { - wrapped.printWarning(arg0); - } - - public SeeTag[] seeTags() { - return wrapped.seeTags(); - } - - public void setRawCommentText(String arg0) { - wrapped.setRawCommentText(arg0); - } - - public ClassDoc[] specifiedClasses() { - return wrapped.specifiedClasses(); - } - - public PackageDoc[] specifiedPackages() { - return wrapped.specifiedPackages(); - } - - public Tag[] tags() { - return wrapped.tags(); - } - - public Tag[] tags(String arg0) { - return wrapped.tags(arg0); - } - -} diff --git a/src/test/java/org/umlgraph/test/BasicTest.java b/src/test/java/org/umlgraph/test/BasicTest.java index 8c7fcc2..28f1cad 100644 --- a/src/test/java/org/umlgraph/test/BasicTest.java +++ b/src/test/java/org/umlgraph/test/BasicTest.java @@ -64,6 +64,7 @@ public class BasicTest { pw.println(); pw.println(); pw.flush(); + System.exit(differences.size() > 0 ? 1 : 0); } private static void performViewTests(List differences, File outFolder) diff --git a/src/test/java/org/umlgraph/test/DotDiff.java b/src/test/java/org/umlgraph/test/DotDiff.java index 32ae72a..266981a 100644 --- a/src/test/java/org/umlgraph/test/DotDiff.java +++ b/src/test/java/org/umlgraph/test/DotDiff.java @@ -166,16 +166,15 @@ public class DotDiff { int closedBracketIdx = line.lastIndexOf(']'); int arrowIdx = line.indexOf("->"); if (openBrackedIdx < 0 && closedBracketIdx < 0 || line.startsWith("edge") - || line.startsWith("node")) + || line.startsWith("node") || line.startsWith("graph")) extraLines.add(line); else if (arrowIdx > 0 && arrowIdx < openBrackedIdx) { // that's an arc arcLines.add(line); } else { // that's a node String attributes = line.substring(openBrackedIdx + 1, closedBracketIdx); Map attMap = parseAttributes(attributes); - String name = line.substring(0, openBrackedIdx - 1).trim(); - String label = attMap.get("label"); - DotNode node = new DotNode(name, label, attMap, line); + String name = trim(line.substring(0, openBrackedIdx - 1)); + DotNode node = new DotNode(name, attMap.get("label"), attMap, line); nodes.put(name, node); nodeList.add(node); } @@ -185,19 +184,21 @@ public class DotDiff { int closedBracketIdx = line.lastIndexOf(']'); String attributes = line.substring(openBrackedIdx + 1, closedBracketIdx); String[] names = line.substring(0, openBrackedIdx).split("->"); - DotNode from = nodes.get(names[0].trim()); - DotNode to = nodes.get(names[1].trim()); - if (from == null) { - from = new DotNode(names[0], "", new HashMap(), ""); - } - if (to == null) { - to = new DotNode(names[1], "", new HashMap(), ""); - } + DotNode from = nodes.get(names[0] = trim(names[0])); + DotNode to = nodes.get(names[1] = trim(names[1])); + from = from != null ? from : new DotNode(names[0], "", new HashMap(), ""); + to = to != null? to : new DotNode(names[1], "", new HashMap(), ""); arcs.add(new DotArc(from, to, parseAttributes(attributes), line)); } return extraLines; } + // Trim space AND port. + private String trim(String name) { + name = name.trim(); + return name.endsWith(":p") ? name.substring(0, name.length() - 2) : name; + } + private Map parseAttributes(String attributes) throws IOException { Map map = new HashMap(); diff --git a/src/test/java/org/umlgraph/test/UmlDocTest.java b/src/test/java/org/umlgraph/test/UmlDocTest.java index 19b7551..d470b4f 100644 --- a/src/test/java/org/umlgraph/test/UmlDocTest.java +++ b/src/test/java/org/umlgraph/test/UmlDocTest.java @@ -148,10 +148,11 @@ public class UmlDocTest { private static void runDoclet(String[] options) { pw.print("Run javadoc -doclet " + doclet); for (String o : options) - pw.print(o + " "); + pw.print(" " + o); pw.println(); com.sun.tools.javadoc.Main.execute("UMLDoc test", pw, pw, pw, doclet, options); + System.exit(0); } } diff --git a/testdata/dot-ref/.gitignore b/testdata/dot-ref/.gitignore index b38f805..e33609d 100644 --- a/testdata/dot-ref/.gitignore +++ b/testdata/dot-ref/.gitignore @@ -1,2 +1 @@ -*.dot *.png diff --git a/testdata/dot-ref/Abstr.dot b/testdata/dot-ref/Abstr.dot index 708dba4..1528241 100644 --- a/testdata/dot-ref/Abstr.dot +++ b/testdata/dot-ref/Abstr.dot @@ -5,21 +5,22 @@ # digraph G { - edge [fontname="Helvetica",fontsize=10,labelfontname="Helvetica",labelfontsize=10]; - node [fontname="Helvetica",fontsize=10,shape=plaintext]; - nodesep=0.25; - ranksep=0.5; - // test.AbstractNode - c1 [label=<

    " + linePostfix); } @@ -1222,83 +936,19 @@ class ClassGraph { /** * End the first inner table of a class. - * @param nRows the total number of rows in this table. */ - private void firstInnerTableEnd(Options opt, int nRows) { + private void firstInnerTableEnd(Options opt) { w.print(linePrefix + linePrefix + "
    " // + + text // MAY contain markup! + + "
    "; - w.print(open + text + close + linePostfix); - } - - /** - * Wraps the text with the appropriate font according to the specified font type - * @param opt - * @param text - * @param font - * @return - */ - private String fontWrap(String text, Options opt, Font font) { - if(font == Font.ABSTRACT) { - return fontWrap(text, opt.nodeFontAbstractName, opt.nodeFontSize); - } else if(font == Font.CLASS) { - return fontWrap(text, opt.nodeFontClassName, opt.nodeFontClassSize); - } else if(font == Font.CLASS_ABSTRACT) { - String name; - if(opt.nodeFontClassAbstractName == null) - name = opt.nodeFontAbstractName; - else - name = opt.nodeFontClassAbstractName; - return fontWrap(text, name, opt.nodeFontClassSize); - } else if(font == Font.PACKAGE) { - return fontWrap(text, opt.nodeFontPackageName, opt.nodeFontPackageSize); - } else if(font == Font.TAG) { - return fontWrap(text, opt.nodeFontTagName, opt.nodeFontTagSize); - } else { - return text; - } - } - - /** - * Wraps the text with the appropriate font tags when the font name - * and size are not void - * @param text the text to be wrapped - * @param fontName considered void when it's null - * @param fontSize considered void when it's <= 0 - */ - private String fontWrap(String text, String fontName, double fontSize) { - if(fontName == null && fontSize == -1) - return text; - else if(fontName == null) - return "" + text + ""; - else if(fontSize <= 0) - return "" + text + ""; - else - return "" + text + ""; - } - private static class FieldRelationInfo { ClassDoc cd; boolean multiple; diff --git a/src/main/java/org/umlgraph/doclet/ClassInfo.java b/src/main/java/org/umlgraph/doclet/ClassInfo.java index 75727cf..f498210 100644 --- a/src/main/java/org/umlgraph/doclet/ClassInfo.java +++ b/src/main/java/org/umlgraph/doclet/ClassInfo.java @@ -20,7 +20,6 @@ package org.umlgraph.doclet; import java.util.HashMap; -import java.util.List; import java.util.Map; /** @@ -32,7 +31,7 @@ import java.util.Map; class ClassInfo { private static int classNumber; /** Alias name for the class */ - String name; + final String name; /** True if the class class node has been printed */ boolean nodePrinted; /** True if the class class node is hidden */ @@ -44,10 +43,9 @@ class ClassInfo { */ Map relatedClasses = new HashMap(); - ClassInfo(boolean p, boolean h) { - nodePrinted = p; + ClassInfo(boolean h) { hidden = h; - name = "c" + (new Integer(classNumber)).toString(); + name = "c" + classNumber; classNumber++; } diff --git a/src/main/java/org/umlgraph/doclet/ContextMatcher.java b/src/main/java/org/umlgraph/doclet/ContextMatcher.java index e1fe4db..cc59d00 100644 --- a/src/main/java/org/umlgraph/doclet/ContextMatcher.java +++ b/src/main/java/org/umlgraph/doclet/ContextMatcher.java @@ -67,9 +67,9 @@ public class ContextMatcher implements ClassMatcher { this.root = root; this.keepParentHide = keepParentHide; opt = (Options) options.clone(); - opt.setOption(new String[] { "-!hide" }); - opt.setOption(new String[] { "-!attributes" }); - opt.setOption(new String[] { "-!operations" }); + opt.setOption(new String[] { "!hide" }); + opt.setOption(new String[] { "!attributes" }); + opt.setOption(new String[] { "!operations" }); this.cg = new ClassGraphHack(root, opt); setContextCenter(pattern); @@ -97,26 +97,23 @@ public class ContextMatcher implements ClassMatcher { /** * Adds the specified class to the internal class graph along with its - * relations and depencies, eventually inferring them, according to the + * relations and dependencies, eventually inferring them, according to the * Options specified for this matcher * @param cd */ private void addToGraph(ClassDoc cd) { // avoid adding twice the same class, but don't rely on cg.getClassInfo - // since there - // are other ways to add a classInfor than printing the class + // since there are other ways to add a classInfor than printing the class if (visited.contains(cd.toString())) return; visited.add(cd.toString()); cg.printClass(cd, false); cg.printRelations(cd); - if (opt.inferRelationships) { + if (opt.inferRelationships) cg.printInferredRelations(cd); - } - if (opt.inferDependencies) { + if (opt.inferDependencies) cg.printInferredDependencies(cd); - } } /** @@ -144,10 +141,8 @@ public class ContextMatcher implements ClassMatcher { return true; for (ClassDoc mcd : matched) { - String mcName = mcd.toString(); - ClassInfo ciMatched = cg.getClassInfo(mcName); - RelationPattern rp = ciMatched.getRelation(name); - if (ciMatched != null && rp != null && opt.contextRelationPattern.matchesOne(rp)) + RelationPattern rp = cg.getClassInfo(mcd, true).getRelation(name); + if (rp != null && opt.contextRelationPattern.matchesOne(rp)) return true; } return false; diff --git a/src/main/java/org/umlgraph/doclet/ContextView.java b/src/main/java/org/umlgraph/doclet/ContextView.java index 6d6d03e..040725e 100755 --- a/src/main/java/org/umlgraph/doclet/ContextView.java +++ b/src/main/java/org/umlgraph/doclet/ContextView.java @@ -26,7 +26,7 @@ public class ContextView implements OptionProvider { private Options hideOptions; private Options centerOptions; private Options packageOptions; - private static final String[] HIDE_OPTIONS = new String[] { "-hide" }; + private static final String[] HIDE_OPTIONS = new String[] { "hide" }; public ContextView(String outputFolder, ClassDoc cd, RootDoc root, Options parent) throws IOException { @@ -42,7 +42,7 @@ public class ContextView implements OptionProvider { this.packageOptions.showQualified = false; this.myGlobalOptions = parent.getGlobalOptions(); - this.myGlobalOptions.setOption(new String[] { "-output", outputPath }); + this.myGlobalOptions.setOption(new String[] { "output", outputPath }); this.myGlobalOptions.setOption(HIDE_OPTIONS); this.hideOptions = parent.getGlobalOptions(); @@ -52,7 +52,7 @@ public class ContextView implements OptionProvider { this.centerOptions.nodeFillColor = "lemonChiffon"; this.centerOptions.showQualified = false; - this.matcher = new ContextMatcher(root, Pattern.compile(cd.qualifiedName()), + this.matcher = new ContextMatcher(root, Pattern.compile(Pattern.quote(cd.toString())), myGlobalOptions, true); } @@ -61,8 +61,8 @@ public class ContextView implements OptionProvider { this.cd = contextCenter; String outputPath = cd.containingPackage().name().replace('.', '/') + "/" + cd.name() + ".dot"; - this.myGlobalOptions.setOption(new String[] { "-output", outputPath }); - matcher.setContextCenter(Pattern.compile(cd.toString())); + this.myGlobalOptions.setOption(new String[] { "output", outputPath }); + matcher.setContextCenter(Pattern.compile(Pattern.quote(cd.toString()))); } public String getDisplayName() { @@ -91,7 +91,7 @@ public class ContextView implements OptionProvider { } public Options getOptionsFor(String name) { - Options opt; + Options opt; if (!matcher.matches(name)) opt = hideOptions; else if (name.equals(cd.name())) diff --git a/src/main/java/org/umlgraph/doclet/Font.java b/src/main/java/org/umlgraph/doclet/Font.java new file mode 100644 index 0000000..09355ea --- /dev/null +++ b/src/main/java/org/umlgraph/doclet/Font.java @@ -0,0 +1,101 @@ +package org.umlgraph.doclet; + +/** + * Class to represent a font for graphviz. + *

    + * This is a fairly complicated model, because it is rather an API into graphviz + * formatting strings rather than a standalone thing.

    } tags, and these can be omitted if not + * set. Inheritance of properties then happens in graphviz. + * + * @author Erich Schubert + */ +public enum Font { + /** Edge label font */ + EDGE, // + /** Node basic */ + NODE, // + /** Normal operation font */ + NORMAL, // + /** Abstract operation font */ + ABSTRACT, // + /** Class name. Inherits from null. */ + CLASS, // + /** Class name of abstract classes (usually italic) */ + CLASS_ABSTRACT, // + /** Package names Inherits from null. */ + PACKAGE, // + /** Tags Inherits from null. */ + TAG; + + public static final String DEFAULT_FONT; + + // Static initialization of further values. + static { + // use an appropriate font depending on the current operating system + if (System.getProperty("os.name").toLowerCase().contains("windows")) { + DEFAULT_FONT = "Arial"; + } else { + DEFAULT_FONT = "Helvetica"; // TODO: can we use just "sans"? + } + } + + /** + * Wraps the text with the appropriate font according to the specified font type + * + * @param opt Options + * @param text Text to wrap + * @return Wrapped text + */ + public String wrap(Options opt, String text) { + if (text.isEmpty() || this == NORMAL) + return text; + String face = null; + double size = -1; + boolean italic = false; + switch (this) { + case EDGE: + case NODE: + // Not used with the wrap function. + throw new UnsupportedOperationException(); + case ABSTRACT: + italic = opt.nodeFontAbstractItalic; + case NORMAL: + break; + case CLASS_ABSTRACT: + italic = opt.nodeFontAbstractItalic; + case CLASS: + face = opt.nodeFontClassName; + size = opt.nodeFontClassSize; + break; + case PACKAGE: + face = opt.nodeFontPackageName; + size = opt.nodeFontPackageSize; + break; + case TAG: + face = opt.nodeFontTagName; + size = opt.nodeFontTagSize; + break; + } + if (face == null && size < 0 && !italic) + return text; + StringBuilder buf = new StringBuilder(text.length() + 100); + if (face != null || size > 0) { + buf.append(" 0) + buf.append(" point-size=\"").append(size).append('"'); + buf.append('>'); + } + if (italic) + buf.append(""); + buf.append(text); + if (italic) + buf.append(""); + if (face != null || size > 0) + buf.append(""); + return buf.toString(); + } +} diff --git a/src/main/java/org/umlgraph/doclet/InterfaceMatcher.java b/src/main/java/org/umlgraph/doclet/InterfaceMatcher.java index 6841cc0..6c63b98 100644 --- a/src/main/java/org/umlgraph/doclet/InterfaceMatcher.java +++ b/src/main/java/org/umlgraph/doclet/InterfaceMatcher.java @@ -26,23 +26,17 @@ public class InterfaceMatcher implements ClassMatcher { // for each interface, recurse, since classes and interfaces // are treated the same in the doclet API - for (ClassDoc iface : cd.interfaces()) { + for (ClassDoc iface : cd.interfaces()) if(matches(iface)) return true; - } // recurse on supeclass, if available - if(cd.superclass() != null) - return matches(cd.superclass()); - - return false; + return cd.superclass() == null ? false : matches(cd.superclass()); } public boolean matches(String name) { ClassDoc cd = root.classNamed(name); - if(cd == null) - return false; - return matches(cd); + return cd == null ? false : matches(cd); } } diff --git a/src/main/java/org/umlgraph/doclet/Options.java b/src/main/java/org/umlgraph/doclet/Options.java index 4efa0e7..90b7542 100644 --- a/src/main/java/org/umlgraph/doclet/Options.java +++ b/src/main/java/org/umlgraph/doclet/Options.java @@ -48,69 +48,54 @@ import com.sun.javadoc.Tag; * @author Diomidis Spinellis */ public class Options implements Cloneable, OptionProvider { - // dot's font platform dependence workaround - private static String defaultFont; - private static String defaultItalicFont; // reused often, especially in UmlGraphDoc, worth creating just once and reusing private static final Pattern allPattern = Pattern.compile(".*"); protected static final String DEFAULT_EXTERNAL_APIDOC = "http://docs.oracle.com/javase/7/docs/api/"; - static { - // use an appropriate font depending on the current operating system - // (on windows graphviz is unable to locate "Helvetica-Oblique" - if(System.getProperty("os.name").toLowerCase().contains("windows")) { - defaultFont = "arial"; - defaultItalicFont = "arial italic"; - } else { - defaultFont = "Helvetica"; - defaultItalicFont = "Helvetica-Oblique"; - } - } - // instance fields - List hidePatterns; - List includePatterns; - boolean showQualified; - boolean showQualifiedGenerics; - boolean showAttributes; - boolean showEnumerations; - boolean showEnumConstants; - boolean showOperations; - boolean showConstructors; - boolean showVisibility; + List hidePatterns = new ArrayList(); + List includePatterns = new ArrayList(); + boolean showQualified = false; + boolean showQualifiedGenerics = false; + boolean hideGenerics = false; + boolean showAttributes = false; + boolean showEnumerations = false; + boolean showEnumConstants = false; + boolean showOperations = false; + boolean showConstructors = false; + boolean showVisibility = false; boolean horizontal; - boolean showType; - boolean showComment; - boolean autoSize; - String edgeFontName; - String edgeFontColor; - String edgeColor; - double edgeFontSize; - String nodeFontName; - String nodeFontAbstractName; - String nodeFontColor; - double nodeFontSize; - String nodeFillColor; - double nodeFontClassSize; - String nodeFontClassName; - String nodeFontClassAbstractName; - double nodeFontTagSize; - String nodeFontTagName; - double nodeFontPackageSize; - String nodeFontPackageName; - Shape shape; - String bgColor; - public String outputFileName; - String outputEncoding; - Map apiDocMap; - String apiDocRoot; - boolean postfixPackage; - boolean useGuillemot; - boolean findViews; - String viewName; - double nodeSep; - double rankSep; - public String outputDirectory; + boolean showType = false; + boolean showComment = false; + boolean autoSize = true; + String edgeFontName = Font.DEFAULT_FONT; + String edgeFontColor = "black"; + String edgeColor = "black"; + double edgeFontSize = 10; + String nodeFontName = Font.DEFAULT_FONT; + boolean nodeFontAbstractItalic = true; + String nodeFontColor = "black"; + double nodeFontSize = 10; + String nodeFillColor = null; + double nodeFontClassSize = -1; + String nodeFontClassName = null; + double nodeFontTagSize = -1; + String nodeFontTagName = null; + double nodeFontPackageSize = -1; + String nodeFontPackageName = null; + Shape shape = Shape.CLASS; + String bgColor = null; + public String outputFileName = "graph.dot"; + String outputEncoding = "ISO-8859-1"; // TODO: default to UTF-8 now? + Map apiDocMap = new HashMap(); + String apiDocRoot = null; + boolean postfixPackage = false; + boolean useGuillemot = true; + boolean findViews = false; + String viewName = null; + double nodeSep = 0.25; + double rankSep = 0.5; + public String outputDirectory = null; /* * Numeric values are preferable to symbolic here. * Symbolic reportedly fail on MacOSX, and also are @@ -120,81 +105,28 @@ public class Options implements Cloneable, OptionProvider { String guilOpen = "«"; // « \u00ab /** Guillemot right (close) */ String guilClose = "»"; // » \u00bb - boolean inferRelationships; - boolean inferDependencies; - boolean collapsibleDiagrams; - RelationPattern contextRelationPattern; - boolean useImports; - Visibility inferDependencyVisibility; - boolean inferDepInPackage; - RelationType inferRelationshipType; - private List collPackages; - boolean compact; + boolean inferRelationships = false; + boolean inferDependencies = false; + boolean collapsibleDiagrams = false; + RelationPattern contextRelationPattern = new RelationPattern(RelationDirection.BOTH); + boolean useImports = false; + Visibility inferDependencyVisibility = Visibility.PRIVATE; + boolean inferDepInPackage = false; + RelationType inferRelationshipType = RelationType.NAVASSOC; + private List collPackages = new ArrayList(); + boolean compact = false; + boolean hidePrivateInner = false; // internal option, used by UMLDoc to generate relative links between classes - boolean relativeLinksForSourcePackages; + boolean relativeLinksForSourcePackages = false; // internal option, used by UMLDoc to force strict matching on the class names // and avoid problems with packages in the template declaration making UmlGraph hide // classes outside of them (for example, class gr.spinellis.Foo // would have been hidden by the hide pattern "java.*" // TODO: consider making this standard behaviour - boolean strictMatching; - String dotExecutable; + boolean strictMatching = false; + String dotExecutable = "dot"; Options() { - showQualified = false; - showQualifiedGenerics = false; - showAttributes = false; - showEnumConstants = false; - showOperations = false; - showVisibility = false; - showEnumerations = false; - showConstructors = false; - showType = false; - autoSize = true; - showComment = false; - edgeFontName = defaultFont; - edgeFontColor = "black"; - edgeColor = "black"; - edgeFontSize = 10; - nodeFontColor = "black"; - nodeFontName = defaultFont; - nodeFontAbstractName = defaultItalicFont; - nodeFontSize = 10; - nodeFontClassSize = -1; - nodeFontClassName = null; - nodeFontClassAbstractName = null; - nodeFontTagSize = -1; - nodeFontTagName = null; - nodeFontPackageSize = -1; - nodeFontPackageName = null; - nodeFillColor = null; - bgColor = null; - shape = new Shape(); - outputFileName = "graph.dot"; - outputDirectory= null; - outputEncoding = "ISO-8859-1"; - hidePatterns = new ArrayList(); - includePatterns = new ArrayList(); - apiDocMap = new HashMap(); - apiDocRoot = null; - postfixPackage = false; - useGuillemot = true; - findViews = false; - viewName = null; - contextRelationPattern = new RelationPattern(RelationDirection.BOTH); - inferRelationships = false; - inferDependencies = false; - collapsibleDiagrams = false; - inferDependencyVisibility = Visibility.PRIVATE; - inferDepInPackage = false; - useImports = false; - inferRelationshipType = RelationType.NAVASSOC; - collPackages = new ArrayList(); - compact = false; - relativeLinksForSourcePackages = false; - nodeSep = 0.25; - rankSep = 0.5; - dotExecutable = "dot"; } @Override @@ -203,7 +135,7 @@ public class Options implements Cloneable, OptionProvider { try { clone = (Options) super.clone(); } catch (CloneNotSupportedException e) { - // Should not happen + throw new RuntimeException("Cannot clone?!?", e); // Should not happen } // deep clone the hide and collection patterns clone.hidePatterns = new ArrayList(hidePatterns); @@ -223,6 +155,34 @@ public class Options implements Cloneable, OptionProvider { showVisibility = true; showType = true; } + + /** + * Match strings, ignoring leading -, -!, and !. + * + * @param given Given string + * @param expect Expected string + * @return {@code true} on success + */ + protected static boolean matchOption(String given, String expect) { + return matchOption(given, expect, false); + } + + /** + * Match strings, ignoring leading -, -!, and !. + * + * @param given Given string + * @param expect Expected string + * @param negative May be negative + * @return {@code true} on success + */ + protected static boolean matchOption(String given, String expect, boolean negative) { + int begin = 0, end = given.length(); + if (begin < end && given.charAt(begin) == '-') + ++begin; + if (negative && begin < end && given.charAt(begin) == '!') + ++begin; + return expect.length() == end - begin && expect.regionMatches(0, given, begin, end - begin); + } /** * Return the number of arguments associated with the specified option. @@ -230,65 +190,67 @@ public class Options implements Cloneable, OptionProvider { * Will return 0 if the option is not supported. */ public static int optionLength(String option) { - if(option.equals("-qualify") || option.equals("-!qualify") || - option.equals("-horizontal") || option.equals("-!horizontal") || - option.equals("-attributes") || option.equals("-!attributes") || - option.equals("-enumconstants") || option.equals("-!enumconstants") || - option.equals("-operations") || option.equals("-!operations") || - option.equals("-enumerations") || option.equals("-!enumerations") || - option.equals("-constructors") || option.equals("-!constructors") || - option.equals("-visibility") || option.equals("-!visibility") || - option.equals("-types") || option.equals("-!types") || - option.equals("-autosize") || option.equals("-!autosize") || - option.equals("-commentname") || option.equals("-!commentname") || - option.equals("-all") || - option.equals("-postfixpackage") || - option.equals("-noguillemot") || - option.equals("-views") || - option.equals("-inferrel") || - option.equals("-useimports") || - option.equals("-collapsible") || - option.equals("-inferdep") || - option.equals("-inferdepinpackage") || - option.equals("-compact")) + if(matchOption(option, "qualify", true) || + matchOption(option, "qualifyGenerics", true) || + matchOption(option, "hideGenerics", true) || + matchOption(option, "horizontal", true) || + matchOption(option, "all") || + matchOption(option, "attributes", true) || + matchOption(option, "enumconstants", true) || + matchOption(option, "operations", true) || + matchOption(option, "enumerations", true) || + matchOption(option, "constructors", true) || + matchOption(option, "visibility", true) || + matchOption(option, "types", true) || + matchOption(option, "autosize", true) || + matchOption(option, "commentname", true) || + matchOption(option, "nodefontabstractitalic", true) || + matchOption(option, "postfixpackage", true) || + matchOption(option, "noguillemot", true) || + matchOption(option, "views", true) || + matchOption(option, "inferrel", true) || + matchOption(option, "useimports", true) || + matchOption(option, "collapsible", true) || + matchOption(option, "inferdep", true) || + matchOption(option, "inferdepinpackage", true) || + matchOption(option, "hideprivateinner", true) || + matchOption(option, "compact", true)) return 1; - else if(option.equals("-nodefillcolor") || - option.equals("-nodefontcolor") || - option.equals("-nodefontsize") || - option.equals("-nodefontname") || - option.equals("-nodefontabstractname") || - option.equals("-nodefontclasssize") || - option.equals("-nodefontclassname") || - option.equals("-nodefontclassabstractname") || - option.equals("-nodefonttagsize") || - option.equals("-nodefonttagname") || - option.equals("-nodefontpackagesize") || - option.equals("-nodefontpackagename") || - option.equals("-edgefontcolor") || - option.equals("-edgecolor") || - option.equals("-edgefontsize") || - option.equals("-edgefontname") || - option.equals("-shape") || - option.equals("-output") || - option.equals("-outputencoding") || - option.equals("-bgcolor") || - option.equals("-hide") || - option.equals("-include") || - option.equals("-apidocroot") || - option.equals("-apidocmap") || - option.equals("-d") || - option.equals("-view") || - option.equals("-inferreltype") || - option.equals("-inferdepvis") || - option.equals("-collpackages") || - option.equals("-nodesep") || - option.equals("-ranksep") || - option.equals("-dotexecutable") || - option.equals("-link")) + else if(matchOption(option, "nodefillcolor") || + matchOption(option, "nodefontcolor") || + matchOption(option, "nodefontsize") || + matchOption(option, "nodefontname") || + matchOption(option, "nodefontclasssize") || + matchOption(option, "nodefontclassname") || + matchOption(option, "nodefonttagsize") || + matchOption(option, "nodefonttagname") || + matchOption(option, "nodefontpackagesize") || + matchOption(option, "nodefontpackagename") || + matchOption(option, "edgefontcolor") || + matchOption(option, "edgecolor") || + matchOption(option, "edgefontsize") || + matchOption(option, "edgefontname") || + matchOption(option, "shape") || + matchOption(option, "output") || + matchOption(option, "outputencoding") || + matchOption(option, "bgcolor") || + matchOption(option, "hide") || + matchOption(option, "include") || + matchOption(option, "apidocroot") || + matchOption(option, "apidocmap") || + matchOption(option, "d") || + matchOption(option, "view") || + matchOption(option, "inferreltype") || + matchOption(option, "inferdepvis") || + matchOption(option, "collpackages") || + matchOption(option, "nodesep") || + matchOption(option, "ranksep") || + matchOption(option, "dotexecutable") || + matchOption(option, "link")) return 2; - else if(option.equals("-contextPattern") || - option.equals("-linkoffline")) + else if(matchOption(option, "contextPattern") || + matchOption(option, "linkoffline")) return 3; else return 0; @@ -296,247 +258,168 @@ public class Options implements Cloneable, OptionProvider { /** Set the options based on a single option and its arguments */ void setOption(String[] opt) { - if(!opt[0].equals("-hide") && optionLength(opt[0]) > opt.length) { + if(!matchOption(opt[0], "hide") && optionLength(opt[0]) > opt.length) { System.err.println("Skipping option '" + opt[0] + "', missing argument"); return; } + boolean dash = opt[0].length() > 1 && opt[0].charAt(0) == '-'; + boolean positive = !(opt[0].length() > 1 && opt[0].charAt(dash ? 1 : 0) == '!'); - if(opt[0].equals("-qualify")) { - showQualified = true; - } else if (opt[0].equals("-!qualify")) { - showQualified = false; - } else if(opt[0].equals("-qualifyGenerics")) { - showQualifiedGenerics = true; - } else if (opt[0].equals("-!qualifyGenerics")) { - showQualifiedGenerics = false; - } else if(opt[0].equals("-horizontal")) { - horizontal = true; - } else if (opt[0].equals("-!horizontal")) { - horizontal = false; - } else if(opt[0].equals("-attributes")) { - showAttributes = true; - } else if (opt[0].equals("-!attributes")) { - showAttributes = false; - } else if(opt[0].equals("-enumconstants")) { - showEnumConstants = true; - } else if (opt[0].equals("-!enumconstants")) { - showEnumConstants = false; - } else if(opt[0].equals("-operations")) { - showOperations = true; - } else if (opt[0].equals("-!operations")) { - showOperations = false; - } else if(opt[0].equals("-enumerations")) { - showEnumerations = true; - } else if (opt[0].equals("-!enumerations")) { - showEnumerations = false; - } else if(opt[0].equals("-constructors")) { - showConstructors = true; - } else if (opt[0].equals("-!constructors")) { - showConstructors = false; - } else if(opt[0].equals("-visibility")) { - showVisibility = true; - } else if (opt[0].equals("-!visibility")) { - showVisibility = false; - } else if(opt[0].equals("-types")) { - showType = true; - } else if (opt[0].equals("-!types")) { - showType = false; - } else if(opt[0].equals("-autoSize")) { - autoSize = true; - } else if (opt[0].equals("-!autoSize")) { - autoSize = false; - } else if(opt[0].equals("-commentname")) { - showComment = true; - } else if (opt[0].equals("-!commentname")) { - showComment = false; - } else if(opt[0].equals("-all")) { + if(matchOption(opt[0], "qualify", true)) { + showQualified = positive; + } else if(matchOption(opt[0], "qualifyGenerics", true)) { + showQualifiedGenerics = positive; + } else if(matchOption(opt[0], "hideGenerics", true)) { + hideGenerics = positive; + } else if(matchOption(opt[0], "horizontal", true)) { + horizontal = positive; + } else if(matchOption(opt[0], "attributes", true)) { + showAttributes = positive; + } else if(matchOption(opt[0], "enumconstants", true)) { + showEnumConstants = positive; + } else if(matchOption(opt[0], "operations", true)) { + showOperations = positive; + } else if(matchOption(opt[0], "enumerations", true)) { + showEnumerations = positive; + } else if(matchOption(opt[0], "constructors", true)) { + showConstructors = positive; + } else if(matchOption(opt[0], "visibility", true)) { + showVisibility = positive; + } else if(matchOption(opt[0], "types", true)) { + showType = positive; + } else if(matchOption(opt[0], "autoSize", true)) { + autoSize = positive; + } else if(matchOption(opt[0], "commentname", true)) { + showComment = positive; + } else if(matchOption(opt[0], "all")) { setAll(); - } else if(opt[0].equals("-bgcolor")) { - bgColor = opt[1]; - } else if (opt[0].equals("-!bgcolor")) { - bgColor = null; - } else if(opt[0].equals("-edgecolor")) { - edgeColor = opt[1]; - } else if (opt[0].equals("-!edgecolor")) { - edgeColor = "black"; - } else if(opt[0].equals("-edgefontcolor")) { - edgeFontColor = opt[1]; - } else if (opt[0].equals("-!edgefontcolor")) { - edgeFontColor = "black"; - } else if(opt[0].equals("-edgefontname")) { - edgeFontName = opt[1]; - } else if (opt[0].equals("-!edgefontname")) { - edgeFontName = defaultFont; - } else if(opt[0].equals("-edgefontsize")) { - edgeFontSize = Integer.parseInt(opt[1]); - } else if (opt[0].equals("-!edgefontsize")) { - edgeFontSize = 10; - } else if(opt[0].equals("-nodefontcolor")) { - nodeFontColor = opt[1]; - } else if (opt[0].equals("-!nodefontcolor")) { - nodeFontColor = "black"; - } else if(opt[0].equals("-nodefontname")) { - nodeFontName = opt[1]; - } else if (opt[0].equals("-!nodefontname")) { - nodeFontName = defaultFont; - } else if(opt[0].equals("-nodefontabstractname")) { - nodeFontAbstractName = opt[1]; - } else if (opt[0].equals("-!nodefontabstractname")) { - nodeFontAbstractName = defaultItalicFont; - } else if(opt[0].equals("-nodefontsize")) { - nodeFontSize = Integer.parseInt(opt[1]); - } else if (opt[0].equals("-!nodefontsize")) { - nodeFontSize = 10; - } else if(opt[0].equals("-nodefontclassname")) { - nodeFontClassName = opt[1]; - } else if (opt[0].equals("-!nodefontclassname")) { - nodeFontClassName = null; - } else if(opt[0].equals("-nodefontclassabstractname")) { - nodeFontClassAbstractName = opt[1]; - } else if (opt[0].equals("-!nodefontclassabstractname")) { - nodeFontClassAbstractName = null; - } else if(opt[0].equals("-nodefontclasssize")) { - nodeFontClassSize = Integer.parseInt(opt[1]); - } else if (opt[0].equals("-!nodefontclasssize")) { - nodeFontClassSize = -1; - } else if(opt[0].equals("-nodefonttagname")) { - nodeFontTagName = opt[1]; - } else if (opt[0].equals("-!nodefonttagname")) { - nodeFontTagName = null; - } else if(opt[0].equals("-nodefonttagsize")) { - nodeFontTagSize = Integer.parseInt(opt[1]); - } else if (opt[0].equals("-!nodefonttagsize")) { - nodeFontTagSize = -1; - } else if(opt[0].equals("-nodefontpackagename")) { - nodeFontPackageName = opt[1]; - } else if (opt[0].equals("-!nodefontpackagename")) { - nodeFontPackageName = null; - } else if(opt[0].equals("-nodefontpackagesize")) { - nodeFontPackageSize = Integer.parseInt(opt[1]); - } else if (opt[0].equals("-!nodefontpackagesize")) { - nodeFontPackageSize = -1; - } else if(opt[0].equals("-nodefillcolor")) { - nodeFillColor = opt[1]; - } else if (opt[0].equals("-!nodefillcolor")) { - nodeFillColor = null; - } else if(opt[0].equals("-shape")) { - shape = new Shape(opt[1]); - } else if (opt[0].equals("-!shape")) { - shape = new Shape(); - } else if(opt[0].equals("-output")) { - outputFileName = opt[1]; - } else if (opt[0].equals("-!output")) { - outputFileName = "graph.dot"; - } else if(opt[0].equals("-outputencoding")) { - outputEncoding = opt[1]; - } else if (opt[0].equals("-!outputencoding")) { - outputEncoding = "ISO-8859-1"; - } else if(opt[0].equals("-hide")) { - if(opt.length == 1) { + } else if(matchOption(opt[0], "bgcolor", true)) { + bgColor = positive ? opt[1] : null; + } else if(matchOption(opt[0], "edgecolor", true)) { + edgeColor = positive ? opt[1] : "black"; + } else if(matchOption(opt[0], "edgefontcolor", true)) { + edgeFontColor = positive ? opt[1] : "black"; + } else if(matchOption(opt[0], "edgefontname", true)) { + edgeFontName = positive ? opt[1] : Font.DEFAULT_FONT; + } else if(matchOption(opt[0], "edgefontsize", true)) { + edgeFontSize = positive ? Double.parseDouble(opt[1]) : 10; + } else if(matchOption(opt[0], "nodefontcolor", true)) { + nodeFontColor = positive ? opt[1] : "black"; + } else if(matchOption(opt[0], "nodefontname", true)) { + nodeFontName = positive ? opt[1] : Font.DEFAULT_FONT; + } else if(matchOption(opt[0], "nodefontabstractitalic", true)) { + nodeFontAbstractItalic = positive; + } else if(matchOption(opt[0], "nodefontsize", true)) { + nodeFontSize = positive ? Double.parseDouble(opt[1]) : 10; + } else if(matchOption(opt[0], "nodefontclassname", true)) { + nodeFontClassName = positive ? opt[1] : null; + } else if(matchOption(opt[0], "nodefontclasssize", true)) { + nodeFontClassSize = positive ? Double.parseDouble(opt[1]) : -1; + } else if(matchOption(opt[0], "nodefonttagname", true)) { + nodeFontTagName = positive ? opt[1] : null; + } else if(matchOption(opt[0], "nodefonttagsize", true)) { + nodeFontTagSize = positive ? Double.parseDouble(opt[1]) : -1; + } else if(matchOption(opt[0], "nodefontpackagename", true)) { + nodeFontPackageName = positive ? opt[1] : null; + } else if(matchOption(opt[0], "nodefontpackagesize", true)) { + nodeFontPackageSize = positive ? Double.parseDouble(opt[1]) : -1; + } else if(matchOption(opt[0], "nodefillcolor", true)) { + nodeFillColor = positive ? opt[1] : null; + } else if(matchOption(opt[0], "shape", true)) { + shape = positive ? Shape.of(opt[1]) : Shape.CLASS; + } else if(matchOption(opt[0], "output", true)) { + outputFileName = positive ? opt[1] : "graph.dot"; + } else if(matchOption(opt[0], "outputencoding", true)) { + outputEncoding = positive ? opt[1] : "ISO-8859-1"; + } else if(matchOption(opt[0], "hide", true)) { + if (positive) { + if (opt.length == 1) { + hidePatterns.clear(); + hidePatterns.add(allPattern); + } else { + try { + hidePatterns.add(Pattern.compile(opt[1])); + } catch (PatternSyntaxException e) { + System.err.println("Skipping invalid pattern " + opt[1]); + } + } + } else hidePatterns.clear(); - hidePatterns.add(allPattern); - } else { + } else if(matchOption(opt[0], "include", true)) { + if (positive) { try { - hidePatterns.add(Pattern.compile(opt[1])); + includePatterns.add(Pattern.compile(opt[1])); } catch (PatternSyntaxException e) { System.err.println("Skipping invalid pattern " + opt[1]); } - } - } else if (opt[0].equals("-!hide")) { - hidePatterns.clear(); - } else if(opt[0].equals("-include")) { - try { - includePatterns.add(Pattern.compile(opt[1])); - } catch (PatternSyntaxException e) { - System.err.println("Skipping invalid pattern " + opt[1]); - } - } else if (opt[0].equals("-!include")) { - includePatterns.clear(); - } else if(opt[0].equals("-apidocroot")) { - apiDocRoot = fixApiDocRoot(opt[1]); - } else if (opt[0].equals("-!apidocroot")) { - apiDocRoot = null; - } else if(opt[0].equals("-apidocmap")) { - setApiDocMapFile(opt[1]); - } else if (opt[0].equals("-!apidocmap")) { - apiDocMap.clear(); - } else if(opt[0].equals("-noguillemot")) { - guilOpen = "<<"; - guilClose = ">>"; - } else if (opt[0].equals("-!noguillemot")) { - guilOpen = "\u00ab"; - guilClose = "\u00bb"; - } else if (opt[0].equals("-view")) { - viewName = opt[1]; - } else if (opt[0].equals("-!view")) { - viewName = null; - } else if (opt[0].equals("-views")) { - findViews = true; - } else if (opt[0].equals("-!views")) { - findViews = false; - } else if (opt[0].equals("-d")) { - outputDirectory = opt[1]; - } else if (opt[0].equals("-!d")) { - outputDirectory = null; - } else if(opt[0].equals("-inferrel")) { - inferRelationships = true; - } else if(opt[0].equals("-!inferrel")) { - inferRelationships = false; - } else if(opt[0].equals("-inferreltype")) { + } else + includePatterns.clear(); + } else if(matchOption(opt[0], "apidocroot", true)) { + apiDocRoot = positive ? fixApiDocRoot(opt[1]) : null; + } else if(matchOption(opt[0], "apidocmap", true)) { + if (positive) + setApiDocMapFile(opt[1]); + else + apiDocMap.clear(); + } else if(matchOption(opt[0], "noguillemot", true)) { + guilOpen = positive ? "<<" : "\u00ab"; + guilClose = positive ? ">>" : "\u00bb"; + } else if (matchOption(opt[0], "view", true)) { + viewName = positive ? opt[1] : null; + } else if (matchOption(opt[0], "views", true)) { + findViews = positive; + } else if (matchOption(opt[0], "d", true)) { + outputDirectory = positive ? opt[1] : null; + } else if(matchOption(opt[0], "inferrel", true)) { + inferRelationships = positive; + } else if(matchOption(opt[0], "inferreltype", true)) { + if (positive) { try { inferRelationshipType = RelationType.valueOf(opt[1].toUpperCase()); } catch(IllegalArgumentException e) { System.err.println("Unknown association type " + opt[1]); } - } else if(opt[0].equals("-!inferreltype")) { - inferRelationshipType = RelationType.NAVASSOC; - } else if(opt[0].equals("-inferdepvis")) { - try { - Visibility vis = Visibility.valueOf(opt[1].toUpperCase()); - inferDependencyVisibility = vis; - } catch(IllegalArgumentException e) { - System.err.println("Ignoring invalid visibility specification for " + - "dependency inference: " + opt[1]); - } - } else if(opt[0].equals("-!inferdepvis")) { - inferDependencyVisibility = Visibility.PRIVATE; - } else if(opt[0].equals("-collapsible")) { - collapsibleDiagrams = true; - } else if(opt[0].equals("-!collapsible")) { - collapsibleDiagrams = false; - } else if(opt[0].equals("-inferdep")) { - inferDependencies = true; - } else if(opt[0].equals("-!inferdep")) { - inferDependencies = false; - } else if(opt[0].equals("-inferdepinpackage")) { - inferDepInPackage = true; - } else if(opt[0].equals("-!inferdepinpackage")) { - inferDepInPackage = false; - } else if(opt[0].equals("-useimports")) { - useImports = true; - } else if(opt[0].equals("-!useimports")) { - useImports = false; - } else if (opt[0].equals("-collpackages")) { - try { - collPackages.add(Pattern.compile(opt[1])); - } catch (PatternSyntaxException e) { - System.err.println("Skipping invalid pattern " + opt[1]); - } - } else if (opt[0].equals("-!collpackages")) { - collPackages.clear(); - } else if (opt[0].equals("-compact")) { - compact = true; - } else if (opt[0].equals("-!compact")) { - compact = false; - } else if (opt[0].equals("-postfixpackage")) { - postfixPackage = true; - } else if (opt[0].equals("-!postfixpackage")) { - postfixPackage = false; - } else if (opt[0].equals("-link")) { + } else + inferRelationshipType = RelationType.NAVASSOC; + } else if(matchOption(opt[0], "inferdepvis", true)) { + if (positive) { + try { + Visibility vis = Visibility.valueOf(opt[1].toUpperCase()); + inferDependencyVisibility = vis; + } catch(IllegalArgumentException e) { + System.err.println("Ignoring invalid visibility specification for " + + "dependency inference: " + opt[1]); + } + } else + inferDependencyVisibility = Visibility.PRIVATE; + } else if(matchOption(opt[0], "collapsible", true)) { + collapsibleDiagrams = positive; + } else if(matchOption(opt[0], "inferdep", true)) { + inferDependencies = positive; + } else if(matchOption(opt[0], "inferdepinpackage", true)) { + inferDepInPackage = positive; + } else if (matchOption(opt[0], "hideprivateinner", true)) { + hidePrivateInner = positive; + } else if(matchOption(opt[0], "useimports", true)) { + useImports = positive; + } else if (matchOption(opt[0], "collpackages", true)) { + if (positive) { + try { + collPackages.add(Pattern.compile(opt[1])); + } catch (PatternSyntaxException e) { + System.err.println("Skipping invalid pattern " + opt[1]); + } + } else + collPackages.clear(); + } else if (matchOption(opt[0], "compact", true)) { + compact = positive; + } else if (matchOption(opt[0], "postfixpackage", true)) { + postfixPackage = positive; + } else if (matchOption(opt[0], "link")) { addApiDocRoots(opt[1]); - } else if (opt[0].equals("-linkoffline")) { + } else if (matchOption(opt[0], "linkoffline")) { addApiDocRootsOffline(opt[1], opt[2]); - } else if(opt[0].equals("-contextPattern")) { + } else if(matchOption(opt[0], "contextPattern")) { RelationDirection d; RelationType rt; try { d = RelationDirection.valueOf(opt[2].toUpperCase()); @@ -550,27 +433,22 @@ public class Options implements Cloneable, OptionProvider { } - } else if (opt[0].equals("-nodesep")) { + } else if (matchOption(opt[0], "nodesep", true)) { try { - nodeSep = Double.parseDouble(opt[1]); + nodeSep = positive ? Double.parseDouble(opt[1]) : 0.25; } catch (NumberFormatException e) { System.err.println("Skipping invalid nodesep " + opt[1]); } - } else if (opt[0].equals("-!nodesep")) { - nodeSep = 0.25; - } else if (opt[0].equals("-ranksep")) { + } else if (matchOption(opt[0], "ranksep", true)) { try { - rankSep = Double.parseDouble(opt[1]); + rankSep = positive ? Double.parseDouble(opt[1]) : 0.5; } catch (NumberFormatException e) { System.err.println("Skipping invalid ranksep " + opt[1]); } - } else if (opt[0].equals("-!ranksep")) { - rankSep = 0.5; - } else if (opt[0].equals("-dotexecutable")) { - dotExecutable = opt[1]; + } else if (matchOption(opt[0], "dotexecutable")) { + dotExecutable = opt[1]; } else - ; // Do nothing, javadoc will handle the option or complain, if - // needed. + ; // Do nothing, javadoc will handle the option or complain, if needed. } /** @@ -642,11 +520,10 @@ public class Options implements Cloneable, OptionProvider { userMap.load(is); for (Map.Entry mapEntry : userMap.entrySet()) { try { - Pattern regex = Pattern.compile((String) mapEntry.getKey()); String thisRoot = (String) mapEntry.getValue(); if (thisRoot != null) { thisRoot = fixApiDocRoot(thisRoot); - apiDocMap.put(regex, thisRoot); + apiDocMap.put(Pattern.compile((String) mapEntry.getKey()), thisRoot); } else { System.err.println("No URL for pattern " + mapEntry.getKey()); } @@ -667,7 +544,7 @@ public class Options implements Cloneable, OptionProvider { * match the class name against the regular expressions specified in the * apiDocMap; if a match is found, the associated URL * will be returned. - * + *

    * NOTE: The match order of the match attempts is the one specified by the * constructor of the api doc root, so it depends on the order of "-link" and "-apiDocMap" * parameters. @@ -677,9 +554,7 @@ public class Options implements Cloneable, OptionProvider { apiDocMap.put(Pattern.compile(".*"), DEFAULT_EXTERNAL_APIDOC); for (Map.Entry mapEntry : apiDocMap.entrySet()) { - Pattern regex = mapEntry.getKey(); - Matcher matcher = regex.matcher(className); - if (matcher.matches()) + if (mapEntry.getKey().matcher(className).matches()) return mapEntry.getValue(); } return null; @@ -687,16 +562,15 @@ public class Options implements Cloneable, OptionProvider { /** Trim and append a file separator to the string */ private String fixApiDocRoot(String str) { - String fixed = null; - if (str != null) { - fixed = str.trim(); - if (fixed.length() > 0) { - if (!File.separator.equals("/")) - fixed = fixed.replace(File.separator.charAt(0), '/'); - if (!fixed.endsWith("/")) - fixed = fixed + "/"; - } - } + if (str == null) + return null; + String fixed = str.trim(); + if (fixed.isEmpty()) + return ""; + if (File.separatorChar != '/') + fixed = fixed.replace(File.separatorChar, '/'); + if (!fixed.endsWith("/")) + fixed = fixed + "/"; return fixed; } @@ -712,11 +586,8 @@ public class Options implements Cloneable, OptionProvider { if (p == null) return; - for (Tag tag : p.tags("opt")) { - String[] opt = StringUtil.tokenize(tag.text()); - opt[0] = "-" + opt[0]; - setOption(opt); - } + for (Tag tag : p.tags("opt")) + setOption(StringUtil.tokenize(tag.text())); } /** @@ -731,13 +602,8 @@ public class Options implements Cloneable, OptionProvider { return true; Matcher m = hidePattern.matcher(s); - if (strictMatching) { - if (m.matches()) { - return true; - } - } else if (m.find()) { + if (strictMatching ? m.matches() : m.find()) return true; - } } return false; } @@ -750,13 +616,8 @@ public class Options implements Cloneable, OptionProvider { public boolean matchesIncludeExpression(String s) { for (Pattern includePattern : includePatterns) { Matcher m = includePattern.matcher(s); - if (strictMatching) { - if (m.matches()) { - return true; - } - } else if (m.find()) { + if (strictMatching ? m.matches() : m.find()) return true; - } } return false; } @@ -769,13 +630,8 @@ public class Options implements Cloneable, OptionProvider { public boolean matchesCollPackageExpression(String s) { for (Pattern collPattern : collPackages) { Matcher m = collPattern.matcher(s); - if (strictMatching) { - if (m.matches()) { - return true; - } - } else if (m.find()) { + if (strictMatching ? m.matches() : m.find()) return true; - } } return false; } diff --git a/src/main/java/org/umlgraph/doclet/PackageMatcher.java b/src/main/java/org/umlgraph/doclet/PackageMatcher.java index c44c85e..99bd7ff 100644 --- a/src/main/java/org/umlgraph/doclet/PackageMatcher.java +++ b/src/main/java/org/umlgraph/doclet/PackageMatcher.java @@ -16,10 +16,9 @@ public class PackageMatcher implements ClassMatcher { } public boolean matches(String name) { - for (ClassDoc cd : packageDoc.allClasses()) { + for (ClassDoc cd : packageDoc.allClasses()) if (cd.qualifiedName().equals(name)) return true; - } return false; } diff --git a/src/main/java/org/umlgraph/doclet/PackageView.java b/src/main/java/org/umlgraph/doclet/PackageView.java index f1dbfbd..c66bf6d 100755 --- a/src/main/java/org/umlgraph/doclet/PackageView.java +++ b/src/main/java/org/umlgraph/doclet/PackageView.java @@ -17,7 +17,7 @@ import com.sun.javadoc.RootDoc; */ public class PackageView implements OptionProvider { - private static final String[] HIDE = new String[] { "-hide" }; + private static final String[] HIDE = new String[] { "hide" }; private PackageDoc pd; private OptionProvider parent; private ClassMatcher matcher; @@ -40,7 +40,7 @@ public class PackageView implements OptionProvider { public Options getGlobalOptions() { Options go = parent.getGlobalOptions(); - go.setOption(new String[] { "-output", outputPath }); + go.setOption(new String[] { "output", outputPath }); go.setOption(HIDE); return go; @@ -63,8 +63,8 @@ public class PackageView implements OptionProvider { boolean inPackage = matcher.matches(cd); if (inPackage) opt.showQualified = false; - if (!(inPackage || this.opt.matchesIncludeExpression(cd.qualifiedName())) - || this.opt.matchesHideExpression(cd.qualifiedName())) + boolean included = inPackage || this.opt.matchesIncludeExpression(cd.qualifiedName()); + if (!included || this.opt.matchesHideExpression(cd.qualifiedName())) opt.setOption(HIDE); } @@ -73,8 +73,8 @@ public class PackageView implements OptionProvider { boolean inPackage = matcher.matches(className); if (inPackage) opt.showQualified = false; - if (!(inPackage || this.opt.matchesIncludeExpression(className)) - || this.opt.matchesHideExpression(className)) + boolean included = inPackage || this.opt.matchesIncludeExpression(className); + if (!included || this.opt.matchesHideExpression(className)) opt.setOption(HIDE); } diff --git a/src/main/java/org/umlgraph/doclet/PatternMatcher.java b/src/main/java/org/umlgraph/doclet/PatternMatcher.java index 84a1fb1..78a9135 100644 --- a/src/main/java/org/umlgraph/doclet/PatternMatcher.java +++ b/src/main/java/org/umlgraph/doclet/PatternMatcher.java @@ -16,7 +16,6 @@ */ package org.umlgraph.doclet; -import java.util.regex.Matcher; import java.util.regex.Pattern; import com.sun.javadoc.ClassDoc; @@ -38,8 +37,7 @@ public class PatternMatcher implements ClassMatcher { } public boolean matches(String name) { - Matcher matcher = pattern.matcher(name); - return matcher.matches(); + return pattern.matcher(name).matches(); } } diff --git a/src/main/java/org/umlgraph/doclet/RelationDirection.java b/src/main/java/org/umlgraph/doclet/RelationDirection.java index 2203f12..4d3595c 100644 --- a/src/main/java/org/umlgraph/doclet/RelationDirection.java +++ b/src/main/java/org/umlgraph/doclet/RelationDirection.java @@ -13,12 +13,9 @@ public enum RelationDirection { * @return */ public RelationDirection sum(RelationDirection d) { - if (this == NONE) - return d; - - if ((this == IN && d == OUT) || (this == OUT && d == IN) || this == BOTH || d == BOTH) - return BOTH; - return this; + // Handle same and nones first: + return (this == d || d == NONE) ? this : // + this == NONE ? d : BOTH; // They are different and not none. } /** @@ -28,10 +25,7 @@ public enum RelationDirection { * @return */ public boolean contains(RelationDirection d) { - if (this == BOTH) - return true; - else - return d == this; + return this == BOTH ? true : (d == this); } /** @@ -40,12 +34,7 @@ public enum RelationDirection { * @return */ public RelationDirection inverse() { - if (this == IN) - return OUT; - else if (this == OUT) - return IN; - else - return this; + return this == IN ? OUT : this == OUT ? IN : this; } }; diff --git a/src/main/java/org/umlgraph/doclet/RelationType.java b/src/main/java/org/umlgraph/doclet/RelationType.java index ba4eeb5..09f33a1 100644 --- a/src/main/java/org/umlgraph/doclet/RelationType.java +++ b/src/main/java/org/umlgraph/doclet/RelationType.java @@ -1,16 +1,34 @@ package org.umlgraph.doclet; /** - * The type of relation that links two entities - * @author wolf + * The type of relation that links two entities, and the graphviz format * + * @author Erich Schubert */ public enum RelationType { - ASSOC(), NAVASSOC(), HAS(), NAVHAS(), COMPOSED(), NAVCOMPOSED(), DEPEND(), EXTENDS(), IMPLEMENTS(); + DEPEND("arrowhead=open,style=dashed,weight=0", false), // Weakest + NAVASSOC("arrowhead=open,weight=1", false), // + ASSOC("arrowhead=none,weight=2", false), // + NAVHAS("arrowhead=open,arrowtail=ediamond,dir=both,weight=3", false), // + HAS("arrowhead=none,arrowtail=ediamond,dir=back,weight=4", false), // + NAVCOMPOSED("arrowhead=open,arrowtail=diamond,dir=both,weight=5", false), // + COMPOSED("arrowhead=none,arrowtail=diamond,dir=back,weight=6", false), // + IMPLEMENTS("arrowtail=empty,style=dashed,dir=back,weight=9", true), // + EXTENDS("arrowtail=empty,dir=back,weight=10", true); + /** Lower case version of the label */ public final String lower; - private RelationType() { - this.lower = toString().toLowerCase(); + /** Graphviz style */ + public final String style; + + /** Backwards edges with respect to node ranking */ + public final boolean backorder; + + /** Enum constructors must be private */ + private RelationType(String style, boolean backorder) { + this.lower = toString().toLowerCase(); + this.style = style; + this.backorder = backorder; } } diff --git a/src/main/java/org/umlgraph/doclet/Shape.java b/src/main/java/org/umlgraph/doclet/Shape.java index b1b9870..54a8cdd 100644 --- a/src/main/java/org/umlgraph/doclet/Shape.java +++ b/src/main/java/org/umlgraph/doclet/Shape.java @@ -18,80 +18,66 @@ package org.umlgraph.doclet; -import java.io.IOException; -import java.io.PrintWriter; -import java.util.ArrayList; -import java.util.List; - -import com.sun.javadoc.ClassDoc; -import com.sun.javadoc.Doc; -import com.sun.javadoc.LanguageVersion; -import com.sun.javadoc.RootDoc; +import java.util.HashMap; +import java.util.Locale; /** * Properties of node shapes * * @version $Revision$ - * @author Diomidis Spinellis + * @author Erich Schubert */ -public class Shape { +public enum Shape { + CLASS(""), // + NOTE(", shape=note"), // + NODE(", shape=box3d"), // + COMPONENT(", shape=component"), // + PACKAGE(", shape=tab"), // + COLLABORATION(", shape=ellipse, style=dashed"), // + USECASE(", shape=ellipse"), // + ACTIVECLASS(""); - /** Shape's UMLGraph name */ - private String name; + /** Graphviz style */ + public final String style; - /** Construct a default (class) Shape */ - public Shape() { - name = "class"; - } + /** Map for valid shape names */ + private static final HashMap index = new HashMap(16); - /** Construct a Shape through the specified UMLGraph name */ - public Shape(String n) { - name = n; - if (graphvizAttribute() == null) { - System.err.println("Ignoring invalid shape " + n); - name = "class"; + /** Initialize the lookup index */ + static { + for (Shape s : Shape.values()) { + index.put(s.name(), s); + index.put(s.name().toLowerCase(Locale.ROOT), s); } } /** - * Return the GraphViz shape name corresponding to the shape + * Get the shape from a string. This allows both the uppercase and the lowercase + * name. Prefer this to {{@link #valueOf(String)} which only accepts uppercase. + * + * @param s String + * @return Shape */ - public String graphvizAttribute() { - if (name.equals("class")) - return ""; // Default; plaintext - else if (name.equals("note")) - return ", shape=note"; - else if (name.equals("node")) - return ", shape=box3d"; - else if (name.equals("component")) - return ", shape=component"; - else if (name.equals("package")) - return ", shape=tab"; - else if (name.equals("collaboration")) - return ", shape=ellipse, style=dashed"; - else if (name.equals("usecase")) - return ", shape=ellipse"; - else if (name.equals("activeclass")) - return ""; // Default; plaintext - else - return null; + public static Shape of(String s) { + Shape shp = index.get(s); + if (shp != null) + return shp; + System.err.println("Ignoring invalid shape: " + s); + return CLASS; } - /** Return the shape's GraphViz landing port */ - String landingPort() { - if (name.equals("class") || name.equals("activeclass")) - return ":p"; - else - return ""; + /** Enum constructor, must be private! */ + private Shape(String style) { + this.style = style; } /** Return the table border required for the shape */ - String extraColumn(int nRows) { - return name.equals("activeclass") ? ("

    AbstractNode
    abstractMethod()
    concreteMethod()
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // test.InnerNode - c2 [label=<
    InnerNode
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // test.Leaf - c3 [label=<
    Leaf
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - //test.InnerNode extends test.AbstractNode - c1:p -> c2:p [dir=back,arrowtail=empty]; - // test.InnerNode COMPOSED test.AbstractNode - c2:p -> c1:p [taillabel="1", label="has", headlabel="*", fontname="Helvetica", fontcolor="black", fontsize=10.0, color="black", arrowhead=none, arrowtail=diamond, dir=both]; - //test.Leaf extends test.AbstractNode - c1:p -> c3:p [dir=back,arrowtail=empty]; +graph [fontnames="svg"] +edge [fontname="Helvetica",fontsize=10,labelfontname="Helvetica",labelfontsize=10,color="black"]; +node [fontname="Helvetica",fontcolor="black",fontsize=10,shape=plaintext,margin=0,width=0,height=0]; +nodesep=0.25; +ranksep=0.5; +// test.AbstractNode +c1 [label=<
    AbstractNode
    abstractMethod()
    concreteMethod()
    >]; +// test.InnerNode +c2 [label=<
    InnerNode
    >]; +// test.Leaf +c3 [label=<
    Leaf
    >]; +// test.InnerNode extends test.AbstractNode +c1 -> c2 [arrowtail=empty,dir=back,weight=10]; +// test.InnerNode composed test.AbstractNode +c2 -> c1 [arrowhead=none,arrowtail=diamond,dir=back,weight=6,taillabel="1", label="has", headlabel="*"]; +// test.Leaf extends test.AbstractNode +c1 -> c3 [arrowtail=empty,dir=back,weight=10]; } diff --git a/testdata/dot-ref/Inference.dot b/testdata/dot-ref/Inference.dot index 4158b30..64737cf 100644 --- a/testdata/dot-ref/Inference.dot +++ b/testdata/dot-ref/Inference.dot @@ -5,45 +5,46 @@ # digraph G { - edge [fontname="Helvetica",fontsize=10,labelfontname="Helvetica",labelfontsize=10]; - node [fontname="Helvetica",fontsize=10,shape=plaintext]; - nodesep=0.25; - ranksep=0.5; - // A - c66 [label=<
    A
    first : B
    second : B
    third : C
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // B - c67 [label=<
    B
    doSomething(b : B, c : C) : A
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // C - c68 [label=<
    C
    collectionOfA : List<A>
    collectionOfB : ArrayList<B>
    mapOfD : Map<String, D>
    childs : C[]
    anOpaqueList : List<>
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // MyFunnyList - c69 [label=<
    MyFunnyList<T, V>
    myField : V
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // MyList - c70 [label=<
    MyList
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // D - c71 [label=<
    D
    anotherListOfA : MyList
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - //MyFunnyList extends java.util.ArrayList - c72:p -> c69:p [dir=back,arrowtail=empty]; - //MyList extends MyFunnyList - c69:p -> c70:p [dir=back,arrowtail=empty]; - // A HAS B - c66:p -> c67:p [taillabel="", label="", headlabel="", fontname="Helvetica", fontcolor="black", fontsize=10.0, color="black", arrowhead=none, arrowtail=ediamond, dir=both]; - // A HAS C - c66:p -> c68:p [taillabel="", label="", headlabel="", fontname="Helvetica", fontcolor="black", fontsize=10.0, color="black", arrowhead=none, arrowtail=ediamond, dir=both]; - // C NAVASSOC B - c68:p -> c67:p [taillabel="", label="", headlabel="*", fontname="Helvetica", fontcolor="black", fontsize=10.0, color="black", arrowhead=open]; - // C NAVASSOC D - c68:p -> c71:p [taillabel="", label="", headlabel="*", fontname="Helvetica", fontcolor="black", fontsize=10.0, color="black", arrowhead=open]; - // C NAVASSOC C - c68:p -> c68:p [taillabel="", label="", headlabel="*", fontname="Helvetica", fontcolor="black", fontsize=10.0, color="black", arrowhead=open]; - // C NAVASSOC java.util.List - c68:p -> c73:p [taillabel="", label="", headlabel="", fontname="Helvetica", fontcolor="black", fontsize=10.0, color="black", arrowhead=open]; - // D NAVASSOC MyList - c71:p -> c70:p [taillabel="", label="", headlabel="", fontname="Helvetica", fontcolor="black", fontsize=10.0, color="black", arrowhead=open]; - // B DEPEND A - c67:p -> c66:p [taillabel="", label="", headlabel="", fontname="Helvetica", fontcolor="black", fontsize=10.0, color="black", arrowhead=open, style=dashed]; - // java.util.List - c73 [label=<
    «interface»
    List<E>
    size() : int
    isEmpty() : boolean
    contains(arg0 : Object) : boolean
    iterator() : Iterator<E>
    toArray() : Object[]
    toArray(arg0 : T[]) : T[]
    add(arg0 : E) : boolean
    remove(arg0 : Object) : boolean
    containsAll(arg0 : Collection<?>) : boolean
    addAll(arg0 : Collection<?>) : boolean
    addAll(arg0 : int, arg1 : Collection<?>) : boolean
    removeAll(arg0 : Collection<?>) : boolean
    retainAll(arg0 : Collection<?>) : boolean
    replaceAll(arg0 : UnaryOperator<E>)
    sort(arg0 : Comparator<?>)
    clear()
    equals(arg0 : Object) : boolean
    hashCode() : int
    get(arg0 : int) : E
    set(arg0 : int, arg1 : E) : E
    add(arg0 : int, arg1 : E)
    remove(arg0 : int) : E
    indexOf(arg0 : Object) : int
    lastIndexOf(arg0 : Object) : int
    listIterator() : ListIterator<E>
    listIterator(arg0 : int) : ListIterator<E>
    subList(arg0 : int, arg1 : int) : List<E>
    spliterator() : Spliterator<E>
    >, URL="http://docs.oracle.com/javase/7/docs/api/java/util/List.html", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // java.util.ArrayList - c72 [label=<
    ArrayList<E>
    serialVersionUID : long
    DEFAULT_CAPACITY : int
    EMPTY_ELEMENTDATA : Object[]
    DEFAULTCAPACITY_EMPTY_ELEMENTDATA : Object[]
    elementData : Object[]
    size : int
    MAX_ARRAY_SIZE : int
    trimToSize()
    ensureCapacity(arg0 : int)
    ensureCapacityInternal(arg0 : int)
    ensureExplicitCapacity(arg0 : int)
    grow(arg0 : int)
    hugeCapacity(arg0 : int) : int
    size() : int
    isEmpty() : boolean
    contains(arg0 : Object) : boolean
    indexOf(arg0 : Object) : int
    lastIndexOf(arg0 : Object) : int
    clone() : Object
    toArray() : Object[]
    toArray(arg0 : T[]) : T[]
    elementData(arg0 : int) : E
    get(arg0 : int) : E
    set(arg0 : int, arg1 : E) : E
    add(arg0 : E) : boolean
    add(arg0 : int, arg1 : E)
    remove(arg0 : int) : E
    remove(arg0 : Object) : boolean
    fastRemove(arg0 : int)
    clear()
    addAll(arg0 : Collection<?>) : boolean
    addAll(arg0 : int, arg1 : Collection<?>) : boolean
    removeRange(arg0 : int, arg1 : int)
    rangeCheck(arg0 : int)
    rangeCheckForAdd(arg0 : int)
    outOfBoundsMsg(arg0 : int) : String
    removeAll(arg0 : Collection<?>) : boolean
    retainAll(arg0 : Collection<?>) : boolean
    batchRemove(arg0 : Collection<?>, arg1 : boolean) : boolean
    writeObject(arg0 : ObjectOutputStream)
    readObject(arg0 : ObjectInputStream)
    listIterator(arg0 : int) : ListIterator<E>
    listIterator() : ListIterator<E>
    iterator() : Iterator<E>
    subList(arg0 : int, arg1 : int) : List<E>
    subListRangeCheck(arg0 : int, arg1 : int, arg2 : int)
    forEach(arg0 : Consumer<?>)
    spliterator() : Spliterator<E>
    removeIf(arg0 : Predicate<?>) : boolean
    replaceAll(arg0 : UnaryOperator<E>)
    sort(arg0 : Comparator<?>)
    >, URL="http://docs.oracle.com/javase/7/docs/api/java/util/ArrayList.html", fontname="Helvetica", fontcolor="black", fontsize=10.0]; +graph [fontnames="svg"] +edge [fontname="Helvetica",fontsize=10,labelfontname="Helvetica",labelfontsize=10,color="black"]; +node [fontname="Helvetica",fontcolor="black",fontsize=10,shape=plaintext,margin=0,width=0,height=0]; +nodesep=0.25; +ranksep=0.5; +// A +c66 [label=<
    A
    first : B
    second : B
    third : C
    >]; +// B +c67 [label=<
    B
    doSomething(b : B, c : C) : A
    >]; +// C +c68 [label=<
    C
    collectionOfA : List<A>
    collectionOfB : ArrayList<B>
    mapOfD : Map<String, D>
    childs : C[]
    anOpaqueList : List<>
    >]; +// MyFunnyList +c69 [label=<
    MyFunnyList<T, V>
    myField : V
    >]; +// MyList +c70 [label=<
    MyList
    >]; +// D +c71 [label=<
    D
    anotherListOfA : MyList
    >]; +// MyFunnyList extends java.util.ArrayList +c72 -> c69 [arrowtail=empty,dir=back,weight=10]; +// MyList extends MyFunnyList +c69 -> c70 [arrowtail=empty,dir=back,weight=10]; +// A has B +c66 -> c67 [arrowhead=none,arrowtail=ediamond,dir=back,weight=4]; +// A has C +c66 -> c68 [arrowhead=none,arrowtail=ediamond,dir=back,weight=4]; +// C navassoc B +c68 -> c67 [arrowhead=open,weight=1,headlabel="*"]; +// C navassoc D +c68 -> c71 [arrowhead=open,weight=1,headlabel="*"]; +// C navassoc C +c68 -> c68 [arrowhead=open,weight=1,headlabel="*"]; +// C navassoc java.util.List +c68 -> c73 [arrowhead=open,weight=1]; +// D navassoc MyList +c71 -> c70 [arrowhead=open,weight=1]; +// B depend A +c67 -> c66 [arrowhead=open,style=dashed,weight=0]; +// java.util.List +c73 [label=<
    «interface»
    List<E>
    size() : int
    isEmpty() : boolean
    contains(arg0 : Object) : boolean
    iterator() : Iterator<E>
    toArray() : Object[]
    toArray(arg0 : T[]) : T[]
    add(arg0 : E) : boolean
    remove(arg0 : Object) : boolean
    containsAll(arg0 : Collection<?>) : boolean
    addAll(arg0 : Collection<?>) : boolean
    addAll(arg0 : int, arg1 : Collection<?>) : boolean
    removeAll(arg0 : Collection<?>) : boolean
    retainAll(arg0 : Collection<?>) : boolean
    replaceAll(arg0 : UnaryOperator<E>)
    sort(arg0 : Comparator<?>)
    clear()
    equals(arg0 : Object) : boolean
    hashCode() : int
    get(arg0 : int) : E
    set(arg0 : int, arg1 : E) : E
    add(arg0 : int, arg1 : E)
    remove(arg0 : int) : E
    indexOf(arg0 : Object) : int
    lastIndexOf(arg0 : Object) : int
    listIterator() : ListIterator<E>
    listIterator(arg0 : int) : ListIterator<E>
    subList(arg0 : int, arg1 : int) : List<E>
    spliterator() : Spliterator<E>
    >, URL="http://docs.oracle.com/javase/7/docs/api/java/util/List.html"]; +// java.util.ArrayList +c72 [label=<
    ArrayList<E>
    serialVersionUID : long
    DEFAULT_CAPACITY : int
    EMPTY_ELEMENTDATA : Object[]
    DEFAULTCAPACITY_EMPTY_ELEMENTDATA : Object[]
    elementData : Object[]
    size : int
    MAX_ARRAY_SIZE : int
    trimToSize()
    ensureCapacity(arg0 : int)
    ensureCapacityInternal(arg0 : int)
    ensureExplicitCapacity(arg0 : int)
    grow(arg0 : int)
    hugeCapacity(arg0 : int) : int
    size() : int
    isEmpty() : boolean
    contains(arg0 : Object) : boolean
    indexOf(arg0 : Object) : int
    lastIndexOf(arg0 : Object) : int
    clone() : Object
    toArray() : Object[]
    toArray(arg0 : T[]) : T[]
    elementData(arg0 : int) : E
    get(arg0 : int) : E
    set(arg0 : int, arg1 : E) : E
    add(arg0 : E) : boolean
    add(arg0 : int, arg1 : E)
    remove(arg0 : int) : E
    remove(arg0 : Object) : boolean
    fastRemove(arg0 : int)
    clear()
    addAll(arg0 : Collection<?>) : boolean
    addAll(arg0 : int, arg1 : Collection<?>) : boolean
    removeRange(arg0 : int, arg1 : int)
    rangeCheck(arg0 : int)
    rangeCheckForAdd(arg0 : int)
    outOfBoundsMsg(arg0 : int) : String
    removeAll(arg0 : Collection<?>) : boolean
    retainAll(arg0 : Collection<?>) : boolean
    batchRemove(arg0 : Collection<?>, arg1 : boolean) : boolean
    writeObject(arg0 : ObjectOutputStream)
    readObject(arg0 : ObjectInputStream)
    listIterator(arg0 : int) : ListIterator<E>
    listIterator() : ListIterator<E>
    iterator() : Iterator<E>
    subList(arg0 : int, arg1 : int) : List<E>
    subListRangeCheck(arg0 : int, arg1 : int, arg2 : int)
    forEach(arg0 : Consumer<?>)
    spliterator() : Spliterator<E>
    removeIf(arg0 : Predicate<?>) : boolean
    replaceAll(arg0 : UnaryOperator<E>)
    sort(arg0 : Comparator<?>)
    >, URL="http://docs.oracle.com/javase/7/docs/api/java/util/ArrayList.html"]; } diff --git a/testdata/dot-ref/Irp.dot b/testdata/dot-ref/Irp.dot index fe3da57..58bd3d1 100644 --- a/testdata/dot-ref/Irp.dot +++ b/testdata/dot-ref/Irp.dot @@ -5,19 +5,20 @@ # digraph G { - edge [fontname="Helvetica",fontsize=10,labelfontname="Helvetica",labelfontsize=10]; - node [fontname="Helvetica",fontsize=10,shape=plaintext]; - nodesep=0.25; - ranksep=0.5; - // Application - c74 [label=<
    Application
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // IrpApplication - c75 [label=<
    IrpApplication
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // Main - c76 [label=<
    Main
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - //IrpApplication extends Application - c74:p -> c75:p [dir=back,arrowtail=empty]; - // Main DEPEND IrpApplication - c76:p -> c75:p [taillabel="", label="«friend»", headlabel="", fontname="Helvetica", fontcolor="black", fontsize=10.0, color="black", arrowhead=open, style=dashed]; +graph [fontnames="svg"] +edge [fontname="Helvetica",fontsize=10,labelfontname="Helvetica",labelfontsize=10,color="black"]; +node [fontname="Helvetica",fontcolor="black",fontsize=10,shape=plaintext,margin=0,width=0,height=0]; +nodesep=0.25; +ranksep=0.5; +// Application +c74 [label=<
    Application
    >]; +// IrpApplication +c75 [label=<
    IrpApplication
    >]; +// Main +c76 [label=<
    Main
    >]; +// IrpApplication extends Application +c74 -> c75 [arrowtail=empty,dir=back,weight=10]; +// Main depend IrpApplication +c76 -> c75 [arrowhead=open,style=dashed,weight=0,label="«friend»"]; } diff --git a/testdata/dot-ref/MultiAssoc.dot b/testdata/dot-ref/MultiAssoc.dot index 63a42fa..a2841c0 100644 --- a/testdata/dot-ref/MultiAssoc.dot +++ b/testdata/dot-ref/MultiAssoc.dot @@ -5,15 +5,16 @@ # digraph G { - edge [fontname="Helvetica",fontsize=10,labelfontname="Helvetica",labelfontsize=10]; - node [fontname="Helvetica",fontsize=10,shape=plaintext]; - nodesep=0.25; - ranksep=0.5; - // A - c81 [label=<
    A
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // C - c83 [label=<
    C
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // A DEPEND C - c81:p -> c83:p [taillabel="", label="", headlabel="", fontname="Helvetica", fontcolor="black", fontsize=10.0, color="black", arrowhead=open, style=dashed]; +graph [fontnames="svg"] +edge [fontname="Helvetica",fontsize=10,labelfontname="Helvetica",labelfontsize=10,color="black"]; +node [fontname="Helvetica",fontcolor="black",fontsize=10,shape=plaintext,margin=0,width=0,height=0]; +nodesep=0.25; +ranksep=0.5; +// A +c81 [label=<
    A
    >]; +// C +c83 [label=<
    C
    >]; +// A depend C +c81 -> c83 [arrowhead=open,style=dashed,weight=0]; } diff --git a/testdata/dot-ref/MyVector.dot b/testdata/dot-ref/MyVector.dot index ce2b411..47aaf55 100644 --- a/testdata/dot-ref/MyVector.dot +++ b/testdata/dot-ref/MyVector.dot @@ -5,27 +5,28 @@ # digraph G { - edge [fontname="Helvetica",fontsize=10,labelfontname="Helvetica",labelfontsize=10]; - node [fontname="Helvetica",fontsize=10,shape=plaintext]; - nodesep=0.25; - ranksep=0.5; - // MyVector - c85 [label=<
    MyVector<E, P>
    ~ addAll(index : int, c : Collection<E>) : boolean
    ~ foo(x : MyVector<P, MyVector<E, E>>) : MyVector<E, P>
    ~ removeAll(c : Collection<?>) : boolean
    ~ set(index : int, element : E) : E
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - //MyVector extends java.util.Vector - c86:p -> c85:p [dir=back,arrowtail=empty]; - //MyVector implements java.util.List - c87:p -> c85:p [dir=back,arrowtail=empty,style=dashed]; - //MyVector implements java.util.RandomAccess - c88:p -> c85:p [dir=back,arrowtail=empty,style=dashed]; - //MyVector implements java.lang.Cloneable - c89:p -> c85:p [dir=back,arrowtail=empty,style=dashed]; - // java.util.RandomAccess - c88 [label=<
    «interface»
    RandomAccess
    >, URL="http://docs.oracle.com/javase/7/docs/api/java/util/RandomAccess.html", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // java.util.List - c87 [label=<
    «interface»
    List<E>
    + size() : int
    + isEmpty() : boolean
    + contains(arg0 : Object) : boolean
    + iterator() : Iterator<E>
    + toArray() : Object[]
    + toArray(arg0 : T[]) : T[]
    + add(arg0 : E) : boolean
    + remove(arg0 : Object) : boolean
    + containsAll(arg0 : Collection<?>) : boolean
    + addAll(arg0 : Collection<?>) : boolean
    + addAll(arg0 : int, arg1 : Collection<?>) : boolean
    + removeAll(arg0 : Collection<?>) : boolean
    + retainAll(arg0 : Collection<?>) : boolean
    + replaceAll(arg0 : UnaryOperator<E>)
    + sort(arg0 : Comparator<?>)
    + clear()
    + equals(arg0 : Object) : boolean
    + hashCode() : int
    + get(arg0 : int) : E
    + set(arg0 : int, arg1 : E) : E
    + add(arg0 : int, arg1 : E)
    + remove(arg0 : int) : E
    + indexOf(arg0 : Object) : int
    + lastIndexOf(arg0 : Object) : int
    + listIterator() : ListIterator<E>
    + listIterator(arg0 : int) : ListIterator<E>
    + subList(arg0 : int, arg1 : int) : List<E>
    + spliterator() : Spliterator<E>
    >, URL="http://docs.oracle.com/javase/7/docs/api/java/util/List.html", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // java.lang.Cloneable - c89 [label=<
    «interface»
    Cloneable
    >, URL="http://docs.oracle.com/javase/7/docs/api/java/lang/Cloneable.html", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // java.util.Vector - c86 [label=<
    Vector<E>
    # elementData : Object[]
    # elementCount : int
    # capacityIncrement : int
    - serialVersionUID : long
    - MAX_ARRAY_SIZE : int
    + copyInto(arg0 : Object[])
    + trimToSize()
    + ensureCapacity(arg0 : int)
    - ensureCapacityHelper(arg0 : int)
    - grow(arg0 : int)
    - hugeCapacity(arg0 : int) : int
    + setSize(arg0 : int)
    + capacity() : int
    + size() : int
    + isEmpty() : boolean
    + elements() : Enumeration<E>
    + contains(arg0 : Object) : boolean
    + indexOf(arg0 : Object) : int
    + indexOf(arg0 : Object, arg1 : int) : int
    + lastIndexOf(arg0 : Object) : int
    + lastIndexOf(arg0 : Object, arg1 : int) : int
    + elementAt(arg0 : int) : E
    + firstElement() : E
    + lastElement() : E
    + setElementAt(arg0 : E, arg1 : int)
    + removeElementAt(arg0 : int)
    + insertElementAt(arg0 : E, arg1 : int)
    + addElement(arg0 : E)
    + removeElement(arg0 : Object) : boolean
    + removeAllElements()
    + clone() : Object
    + toArray() : Object[]
    + toArray(arg0 : T[]) : T[]
    ~ elementData(arg0 : int) : E
    + get(arg0 : int) : E
    + set(arg0 : int, arg1 : E) : E
    + add(arg0 : E) : boolean
    + remove(arg0 : Object) : boolean
    + add(arg0 : int, arg1 : E)
    + remove(arg0 : int) : E
    + clear()
    + containsAll(arg0 : Collection<?>) : boolean
    + addAll(arg0 : Collection<?>) : boolean
    + removeAll(arg0 : Collection<?>) : boolean
    + retainAll(arg0 : Collection<?>) : boolean
    + addAll(arg0 : int, arg1 : Collection<?>) : boolean
    + equals(arg0 : Object) : boolean
    + hashCode() : int
    + toString() : String
    + subList(arg0 : int, arg1 : int) : List<E>
    # removeRange(arg0 : int, arg1 : int)
    - writeObject(arg0 : ObjectOutputStream)
    + listIterator(arg0 : int) : ListIterator<E>
    + listIterator() : ListIterator<E>
    + iterator() : Iterator<E>
    + forEach(arg0 : Consumer<?>)
    + removeIf(arg0 : Predicate<?>) : boolean
    + replaceAll(arg0 : UnaryOperator<E>)
    + sort(arg0 : Comparator<?>)
    + spliterator() : Spliterator<E>
    >, URL="http://docs.oracle.com/javase/7/docs/api/java/util/Vector.html", fontname="Helvetica", fontcolor="black", fontsize=10.0]; +graph [fontnames="svg"] +edge [fontname="Helvetica",fontsize=10,labelfontname="Helvetica",labelfontsize=10,color="black"]; +node [fontname="Helvetica",fontcolor="black",fontsize=10,shape=plaintext,margin=0,width=0,height=0]; +nodesep=0.25; +ranksep=0.5; +// MyVector +c85 [label=<
    MyVector<E, P>
    ~ addAll(index : int, c : Collection<E>) : boolean
    ~ foo(x : MyVector<P, MyVector<E, E>>) : MyVector<E, P>
    ~ removeAll(c : Collection<?>) : boolean
    ~ set(index : int, element : E) : E
    >]; +// MyVector extends java.util.Vector +c86 -> c85 [arrowtail=empty,dir=back,weight=10]; +// MyVector implements java.util.List +c87 -> c85 [arrowtail=empty,style=dashed,dir=back,weight=9]; +// MyVector implements java.util.RandomAccess +c88 -> c85 [arrowtail=empty,style=dashed,dir=back,weight=9]; +// MyVector implements java.lang.Cloneable +c89 -> c85 [arrowtail=empty,style=dashed,dir=back,weight=9]; +// java.util.RandomAccess +c88 [label=<
    «interface»
    RandomAccess
    >, URL="http://docs.oracle.com/javase/7/docs/api/java/util/RandomAccess.html"]; +// java.util.List +c87 [label=<
    «interface»
    List<E>
    + size() : int
    + isEmpty() : boolean
    + contains(arg0 : Object) : boolean
    + iterator() : Iterator<E>
    + toArray() : Object[]
    + toArray(arg0 : T[]) : T[]
    + add(arg0 : E) : boolean
    + remove(arg0 : Object) : boolean
    + containsAll(arg0 : Collection<?>) : boolean
    + addAll(arg0 : Collection<?>) : boolean
    + addAll(arg0 : int, arg1 : Collection<?>) : boolean
    + removeAll(arg0 : Collection<?>) : boolean
    + retainAll(arg0 : Collection<?>) : boolean
    + replaceAll(arg0 : UnaryOperator<E>)
    + sort(arg0 : Comparator<?>)
    + clear()
    + equals(arg0 : Object) : boolean
    + hashCode() : int
    + get(arg0 : int) : E
    + set(arg0 : int, arg1 : E) : E
    + add(arg0 : int, arg1 : E)
    + remove(arg0 : int) : E
    + indexOf(arg0 : Object) : int
    + lastIndexOf(arg0 : Object) : int
    + listIterator() : ListIterator<E>
    + listIterator(arg0 : int) : ListIterator<E>
    + subList(arg0 : int, arg1 : int) : List<E>
    + spliterator() : Spliterator<E>
    >, URL="http://docs.oracle.com/javase/7/docs/api/java/util/List.html"]; +// java.lang.Cloneable +c89 [label=<
    «interface»
    Cloneable
    >, URL="http://docs.oracle.com/javase/7/docs/api/java/lang/Cloneable.html"]; +// java.util.Vector +c86 [label=<
    Vector<E>
    # elementData : Object[]
    # elementCount : int
    # capacityIncrement : int
    - serialVersionUID : long
    - MAX_ARRAY_SIZE : int
    + copyInto(arg0 : Object[])
    + trimToSize()
    + ensureCapacity(arg0 : int)
    - ensureCapacityHelper(arg0 : int)
    - grow(arg0 : int)
    - hugeCapacity(arg0 : int) : int
    + setSize(arg0 : int)
    + capacity() : int
    + size() : int
    + isEmpty() : boolean
    + elements() : Enumeration<E>
    + contains(arg0 : Object) : boolean
    + indexOf(arg0 : Object) : int
    + indexOf(arg0 : Object, arg1 : int) : int
    + lastIndexOf(arg0 : Object) : int
    + lastIndexOf(arg0 : Object, arg1 : int) : int
    + elementAt(arg0 : int) : E
    + firstElement() : E
    + lastElement() : E
    + setElementAt(arg0 : E, arg1 : int)
    + removeElementAt(arg0 : int)
    + insertElementAt(arg0 : E, arg1 : int)
    + addElement(arg0 : E)
    + removeElement(arg0 : Object) : boolean
    + removeAllElements()
    + clone() : Object
    + toArray() : Object[]
    + toArray(arg0 : T[]) : T[]
    ~ elementData(arg0 : int) : E
    + get(arg0 : int) : E
    + set(arg0 : int, arg1 : E) : E
    + add(arg0 : E) : boolean
    + remove(arg0 : Object) : boolean
    + add(arg0 : int, arg1 : E)
    + remove(arg0 : int) : E
    + clear()
    + containsAll(arg0 : Collection<?>) : boolean
    + addAll(arg0 : Collection<?>) : boolean
    + removeAll(arg0 : Collection<?>) : boolean
    + retainAll(arg0 : Collection<?>) : boolean
    + addAll(arg0 : int, arg1 : Collection<?>) : boolean
    + equals(arg0 : Object) : boolean
    + hashCode() : int
    + toString() : String
    + subList(arg0 : int, arg1 : int) : List<E>
    # removeRange(arg0 : int, arg1 : int)
    - writeObject(arg0 : ObjectOutputStream)
    + listIterator(arg0 : int) : ListIterator<E>
    + listIterator() : ListIterator<E>
    + iterator() : Iterator<E>
    + forEach(arg0 : Consumer<?>)
    + removeIf(arg0 : Predicate<?>) : boolean
    + replaceAll(arg0 : UnaryOperator<E>)
    + sort(arg0 : Comparator<?>)
    + spliterator() : Spliterator<E>
    >, URL="http://docs.oracle.com/javase/7/docs/api/java/util/Vector.html"]; } diff --git a/testdata/dot-ref/Root.dot b/testdata/dot-ref/Root.dot index 4f92d1c..8379501 100644 --- a/testdata/dot-ref/Root.dot +++ b/testdata/dot-ref/Root.dot @@ -5,43 +5,44 @@ # digraph G { - edge [fontname="Helvetica",fontsize=10,labelfontname="Helvetica",labelfontsize=10]; - node [fontname="Helvetica",fontsize=10,shape=plaintext]; - nodesep=0.25; - ranksep=0.5; - // Root - c90 [label=<
    Root
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // Adapter - c91 [label=<
    Adapter
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // Element - c92 [label=<
    Element
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // ObjectType - c93 [label=<
    ObjectType
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // ObjectMap - c94 [label=<
    ObjectMap
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // Table - c95 [label=<
    Table
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // DataOperation - c96 [label=<
    DataOperation
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // Root ASSOC Adapter - c90:p -> c91:p [taillabel="1..1", label="", headlabel="0..n", fontname="Helvetica", fontcolor="black", fontsize=10.0, color="black", arrowhead=none]; - // Root ASSOC ObjectType - c90:p -> c93:p [taillabel="", label="", headlabel="0..n", fontname="Helvetica", fontcolor="black", fontsize=10.0, color="black", arrowhead=none]; - // Root ASSOC ObjectMap - c90:p -> c94:p [taillabel="", label="", headlabel="0..n", fontname="Helvetica", fontcolor="black", fontsize=10.0, color="black", arrowhead=none]; - // Root ASSOC Table - c90:p -> c95:p [taillabel="", label="", headlabel="0..n", fontname="Helvetica", fontcolor="black", fontsize=10.0, color="black", arrowhead=none]; - // Root ASSOC DataOperation - c90:p -> c96:p [taillabel="", label="", headlabel="0..n", fontname="Helvetica", fontcolor="black", fontsize=10.0, color="black", arrowhead=none]; - //ObjectType extends Element - c92:p -> c93:p [dir=back,arrowtail=empty]; - //ObjectMap extends Element - c92:p -> c94:p [dir=back,arrowtail=empty]; - // ObjectMap HAS ObjectType - c94:p -> c93:p [taillabel="1..1", label="", headlabel="1..1", fontname="Helvetica", fontcolor="black", fontsize=10.0, color="black", arrowhead=none, arrowtail=ediamond, dir=both]; - //Table extends Element - c92:p -> c95:p [dir=back,arrowtail=empty]; - //DataOperation extends Element - c92:p -> c96:p [dir=back,arrowtail=empty]; +graph [fontnames="svg"] +edge [fontname="Helvetica",fontsize=10,labelfontname="Helvetica",labelfontsize=10,color="black"]; +node [fontname="Helvetica",fontcolor="black",fontsize=10,shape=plaintext,margin=0,width=0,height=0]; +nodesep=0.25; +ranksep=0.5; +// Root +c90 [label=<
    Root
    >]; +// Adapter +c91 [label=<
    Adapter
    >]; +// Element +c92 [label=<
    Element
    >]; +// ObjectType +c93 [label=<
    ObjectType
    >]; +// ObjectMap +c94 [label=<
    ObjectMap
    >]; +// Table +c95 [label=<
    Table
    >]; +// DataOperation +c96 [label=<
    DataOperation
    >]; +// Root assoc Adapter +c90 -> c91 [arrowhead=none,weight=2,taillabel="1..1", headlabel="0..n"]; +// Root assoc ObjectType +c90 -> c93 [arrowhead=none,weight=2,headlabel="0..n"]; +// Root assoc ObjectMap +c90 -> c94 [arrowhead=none,weight=2,headlabel="0..n"]; +// Root assoc Table +c90 -> c95 [arrowhead=none,weight=2,headlabel="0..n"]; +// Root assoc DataOperation +c90 -> c96 [arrowhead=none,weight=2,headlabel="0..n"]; +// ObjectType extends Element +c92 -> c93 [arrowtail=empty,dir=back,weight=10]; +// ObjectMap extends Element +c92 -> c94 [arrowtail=empty,dir=back,weight=10]; +// ObjectMap has ObjectType +c94 -> c93 [arrowhead=none,arrowtail=ediamond,dir=back,weight=4,taillabel="1..1", headlabel="1..1"]; +// Table extends Element +c92 -> c95 [arrowtail=empty,dir=back,weight=10]; +// DataOperation extends Element +c92 -> c96 [arrowtail=empty,dir=back,weight=10]; } diff --git a/testdata/dot-ref/RunnableRef.dot b/testdata/dot-ref/RunnableRef.dot index 27b145d..f347d8f 100644 --- a/testdata/dot-ref/RunnableRef.dot +++ b/testdata/dot-ref/RunnableRef.dot @@ -5,15 +5,16 @@ # digraph G { - edge [fontname="Helvetica",fontsize=10,labelfontname="Helvetica",labelfontsize=10]; - node [fontname="Helvetica",fontsize=10,shape=plaintext]; - nodesep=0.25; - ranksep=0.5; - // test.RunnableRef - c98 [label=<
    RunnableRef
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // test.RunnableRef DEPEND java.lang.Runnable - c98:p -> c99:p [taillabel="", label="", headlabel="", fontname="Helvetica", fontcolor="black", fontsize=10.0, color="black", arrowhead=open, style=dashed]; - // java.lang.Runnable - c99 [label=<
    «interface»
    Runnable
    >, URL="http://docs.oracle.com/javase/7/docs/api/java/lang/Runnable.html", fontname="Helvetica", fontcolor="black", fontsize=10.0]; +graph [fontnames="svg"] +edge [fontname="Helvetica",fontsize=10,labelfontname="Helvetica",labelfontsize=10,color="black"]; +node [fontname="Helvetica",fontcolor="black",fontsize=10,shape=plaintext,margin=0,width=0,height=0]; +nodesep=0.25; +ranksep=0.5; +// test.RunnableRef +c98 [label=<
    RunnableRef
    >]; +// test.RunnableRef depend java.lang.Runnable +c98 -> c99 [arrowhead=open,style=dashed,weight=0]; +// java.lang.Runnable +c99 [label=<
    «interface»
    Runnable
    >, URL="http://docs.oracle.com/javase/7/docs/api/java/lang/Runnable.html"]; } diff --git a/testdata/dot-ref/Style.dot b/testdata/dot-ref/Style.dot index 320d5cc..09ab5f4 100644 --- a/testdata/dot-ref/Style.dot +++ b/testdata/dot-ref/Style.dot @@ -5,23 +5,24 @@ # digraph G { - edge [fontname="arial",fontsize=10,labelfontname="arial",labelfontsize=10]; - node [fontname="arial",fontsize=10,shape=plaintext]; - nodesep=0.25; - ranksep=0.5; - // net.sf.whatever.test.AbstractBase - c112 [label=<
    «base»
    AbstractBase
    net.sf.whatever.test
    {since = 1.0}
    field : int
    {since = 1.5}
    abstractMethod()
    concreteMethod() : int
    >, URL="null", fontname="arial", fontcolor="black", fontsize=9.0]; - // net.sf.whatever.test.Composite - c113 [label=<
    Composite
    net.sf.whatever.test
    >, URL="null", fontname="arial", fontcolor="black", fontsize=9.0]; - // net.sf.whatever.test.Style - c114 [label=<
    Style
    net.sf.whatever.test
    >, URL="null", fontname="arial", fontcolor="black", fontsize=9.0]; - //net.sf.whatever.test.Composite extends net.sf.whatever.test.AbstractBase - c112:p -> c113:p [dir=back,arrowtail=empty]; - // net.sf.whatever.test.Composite COMPOSED from.Outer.Space.AlienClass - c113:p -> c115:p [taillabel="1", label="has", headlabel="*", fontname="arial", fontcolor="black", fontsize=10.0, color="black", arrowhead=none, arrowtail=diamond, dir=both]; - //net.sf.whatever.test.Style extends net.sf.whatever.test.AbstractBase - c112:p -> c114:p [dir=back,arrowtail=empty]; - // from.Outer.Space.AlienClass - c115[label=<
    AlienClass
    from.Outer.Space
    >, fontname="arial", fontcolor="black", fontsize=9.0]; +graph [fontnames="svg"] +edge [fontname="arial",fontsize=10,labelfontname="arial",labelfontsize=10,color="black"]; +node [fontname="arial",fontcolor="black",fontsize=9,shape=plaintext,margin=0,width=0,height=0]; +nodesep=0.25; +ranksep=0.5; +// net.sf.whatever.test.AbstractBase +c112 [label=<
    «base»
    AbstractBase
    net.sf.whatever.test
    {since = 1.0}
    field : int
    {since = 1.5}
    abstractMethod()
    concreteMethod() : int
    >]; +// net.sf.whatever.test.Composite +c113 [label=<
    Composite
    net.sf.whatever.test
    >]; +// net.sf.whatever.test.Style +c114 [label=<
    Style
    net.sf.whatever.test
    >]; +// net.sf.whatever.test.Composite extends net.sf.whatever.test.AbstractBase +c112 -> c113 [arrowtail=empty,dir=back,weight=10]; +// net.sf.whatever.test.Composite composed from.Outer.Space.AlienClass +c113 -> c115 [arrowhead=none,arrowtail=diamond,dir=back,weight=6,taillabel="1",label="has",headlabel="*"]; +// net.sf.whatever.test.Style extends net.sf.whatever.test.AbstractBase +c112 -> c114 [arrowtail=empty,dir=back,weight=10]; +// from.Outer.Space.AlienClass +c115[label=<
    AlienClass
    from.Outer.Space
    >]; } - + diff --git a/testdata/dot-ref/TestHideOp.dot b/testdata/dot-ref/TestHideOp.dot index 661db51..793bf78 100644 --- a/testdata/dot-ref/TestHideOp.dot +++ b/testdata/dot-ref/TestHideOp.dot @@ -5,11 +5,12 @@ # digraph G { - edge [fontname="Helvetica",fontsize=10,labelfontname="Helvetica",labelfontsize=10]; - node [fontname="Helvetica",fontsize=10,shape=plaintext]; - nodesep=0.25; - ranksep=0.5; - // test.TestHideOp - c117 [label=<
    TestHideOp
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; +graph [fontnames="svg"] +edge [fontname="Helvetica",fontsize=10,labelfontname="Helvetica",labelfontsize=10,color="black"]; +node [fontname="Helvetica",fontcolor="black",fontsize=10,shape=plaintext,margin=0,width=0,height=0]; +nodesep=0.25; +ranksep=0.5; +// test.TestHideOp +c117 [label=<
    TestHideOp
    >]; } diff --git a/testdata/dot-ref/ViewAll.dot b/testdata/dot-ref/ViewAll.dot index bb8a66d..84cf660 100644 --- a/testdata/dot-ref/ViewAll.dot +++ b/testdata/dot-ref/ViewAll.dot @@ -5,27 +5,28 @@ # digraph G { - edge [fontname="Helvetica",fontsize=10,labelfontname="Helvetica",labelfontsize=10]; - node [fontname="Helvetica",fontsize=10,shape=plaintext]; - nodesep=0.25; - ranksep=0.5; - // gr.spinellis.basic.invoice.InvoiceItem - c355 [label=<
    InvoiceItem
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // gr.spinellis.basic.invoice.Invoice - c356 [label=<
    Invoice
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // gr.spinellis.basic.invoice.Customer - c357 [label=<
    Customer
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // gr.spinellis.basic.product.Product - c358 [label=<
    Product
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // gr.spinellis.basic.product.Category - c359 [label=<
    Category
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // gr.spinellis.basic.invoice.InvoiceItem ASSOC gr.spinellis.basic.product.Product - c355:p -> c358:p [taillabel="*", label="", headlabel="1", fontname="Helvetica", fontcolor="black", fontsize=10.0, color="black", arrowhead=none]; - // gr.spinellis.basic.invoice.Invoice ASSOC gr.spinellis.basic.invoice.Customer - c356:p -> c357:p [taillabel="*", label="", headlabel="1", fontname="Helvetica", fontcolor="black", fontsize=10.0, color="black", arrowhead=none]; - // gr.spinellis.basic.invoice.Invoice COMPOSED gr.spinellis.basic.invoice.InvoiceItem - c356:p -> c355:p [taillabel="1", label="", headlabel="*", fontname="Helvetica", fontcolor="black", fontsize=10.0, color="black", arrowhead=none, arrowtail=diamond, dir=both]; - // gr.spinellis.basic.product.Product ASSOC gr.spinellis.basic.product.Category - c358:p -> c359:p [taillabel="*", label="", headlabel="1", fontname="Helvetica", fontcolor="black", fontsize=10.0, color="black", arrowhead=none]; +graph [fontnames="svg"] +edge [fontname="Helvetica",fontsize=10,labelfontname="Helvetica",labelfontsize=10,color="black"]; +node [fontname="Helvetica",fontcolor="black",fontsize=10,shape=plaintext,margin=0,width=0,height=0]; +nodesep=0.25; +ranksep=0.5; +// gr.spinellis.basic.invoice.InvoiceItem +c355 [label=<
    InvoiceItem
    >]; +// gr.spinellis.basic.invoice.Invoice +c356 [label=<
    Invoice
    >]; +// gr.spinellis.basic.invoice.Customer +c357 [label=<
    Customer
    >]; +// gr.spinellis.basic.product.Product +c358 [label=<
    Product
    >]; +// gr.spinellis.basic.product.Category +c359 [label=<
    Category
    >]; +// gr.spinellis.basic.invoice.InvoiceItem assoc gr.spinellis.basic.product.Product +c355 -> c358 [arrowhead=none,weight=2,taillabel="*", headlabel="1"]; +// gr.spinellis.basic.invoice.Invoice assoc gr.spinellis.basic.invoice.Customer +c356 -> c357 [arrowhead=none,weight=2,taillabel="*", headlabel="1"]; +// gr.spinellis.basic.invoice.Invoice composed gr.spinellis.basic.invoice.InvoiceItem +c356 -> c355 [arrowhead=none,arrowtail=diamond,dir=back,weight=6,taillabel="1", headlabel="*"]; +// gr.spinellis.basic.product.Product assoc gr.spinellis.basic.product.Category +c358 -> c359 [arrowhead=none,weight=2,taillabel="*", headlabel="1"]; } diff --git a/testdata/dot-ref/ViewAllDetailed.dot b/testdata/dot-ref/ViewAllDetailed.dot index 079b0f7..7833953 100644 --- a/testdata/dot-ref/ViewAllDetailed.dot +++ b/testdata/dot-ref/ViewAllDetailed.dot @@ -5,27 +5,28 @@ # digraph G { - edge [fontname="Helvetica",fontsize=10,labelfontname="Helvetica",labelfontsize=10]; - node [fontname="Helvetica",fontsize=10,shape=plaintext]; - nodesep=0.25; - ranksep=0.5; - // gr.spinellis.basic.invoice.InvoiceItem - c317 [label=<
    InvoiceItem
    product : Product
    quantity : int
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // gr.spinellis.basic.invoice.Invoice - c318 [label=<
    Invoice
    total : double
    items : InvoiceItem[]
    customer : Customer
    addItem(p : Product, quantity : int)
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // gr.spinellis.basic.invoice.Customer - c319 [label=<
    Customer
    name : String
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // gr.spinellis.basic.product.Product - c320 [label=<
    Product
    name : String
    stock : int
    price : double
    category : Category
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // gr.spinellis.basic.product.Category - c321 [label=<
    Category
    name : String
    products : List<>
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // gr.spinellis.basic.invoice.InvoiceItem ASSOC gr.spinellis.basic.product.Product - c317:p -> c320:p [taillabel="*", label="", headlabel="1", fontname="Helvetica", fontcolor="black", fontsize=10.0, color="black", arrowhead=none]; - // gr.spinellis.basic.invoice.Invoice ASSOC gr.spinellis.basic.invoice.Customer - c318:p -> c319:p [taillabel="*", label="", headlabel="1", fontname="Helvetica", fontcolor="black", fontsize=10.0, color="black", arrowhead=none]; - // gr.spinellis.basic.invoice.Invoice COMPOSED gr.spinellis.basic.invoice.InvoiceItem - c318:p -> c317:p [taillabel="1", label="", headlabel="*", fontname="Helvetica", fontcolor="black", fontsize=10.0, color="black", arrowhead=none, arrowtail=diamond, dir=both]; - // gr.spinellis.basic.product.Product ASSOC gr.spinellis.basic.product.Category - c320:p -> c321:p [taillabel="*", label="", headlabel="1", fontname="Helvetica", fontcolor="black", fontsize=10.0, color="black", arrowhead=none]; +graph [fontnames="svg"] +edge [fontname="Helvetica",fontsize=10,labelfontname="Helvetica",labelfontsize=10,color="black"]; +node [fontname="Helvetica",fontcolor="black",fontsize=10,shape=plaintext,margin=0,width=0,height=0]; +nodesep=0.25; +ranksep=0.5; +// gr.spinellis.basic.invoice.InvoiceItem +c317 [label=<
    InvoiceItem
    product : Product
    quantity : int
    >]; +// gr.spinellis.basic.invoice.Invoice +c318 [label=<
    Invoice
    total : double
    items : InvoiceItem[]
    customer : Customer
    addItem(p : Product, quantity : int)
    >]; +// gr.spinellis.basic.invoice.Customer +c319 [label=<
    Customer
    name : String
    >]; +// gr.spinellis.basic.product.Product +c320 [label=<
    Product
    name : String
    stock : int
    price : double
    category : Category
    >]; +// gr.spinellis.basic.product.Category +c321 [label=<
    Category
    name : String
    products : List<>
    >]; +// gr.spinellis.basic.invoice.InvoiceItem assoc gr.spinellis.basic.product.Product +c317 -> c320 [arrowhead=none,weight=2,taillabel="*", headlabel="1"]; +// gr.spinellis.basic.invoice.Invoice assoc gr.spinellis.basic.invoice.Customer +c318 -> c319 [arrowhead=none,weight=2,taillabel="*", headlabel="1"]; +// gr.spinellis.basic.invoice.Invoice composed gr.spinellis.basic.invoice.InvoiceItem +c318 -> c317 [arrowhead=none,arrowtail=diamond,dir=back,weight=6,taillabel="1", headlabel="*"]; +// gr.spinellis.basic.product.Product assoc gr.spinellis.basic.product.Category +c320 -> c321 [arrowhead=none,weight=2,taillabel="*", headlabel="1"]; } diff --git a/testdata/dot-ref/ViewAtt.dot b/testdata/dot-ref/ViewAtt.dot index 07f93ca..f7ea886 100644 --- a/testdata/dot-ref/ViewAtt.dot +++ b/testdata/dot-ref/ViewAtt.dot @@ -5,27 +5,28 @@ # digraph G { - edge [fontname="Helvetica",fontsize=10,labelfontname="Helvetica",labelfontsize=10]; - node [fontname="Helvetica",fontsize=10,shape=plaintext]; - nodesep=0.25; - ranksep=0.5; - // gr.spinellis.basic.invoice.InvoiceItem - c279 [label=<
    InvoiceItem
    product
    quantity
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=16.0]; - // gr.spinellis.basic.invoice.Invoice - c280 [label=<
    Invoice
    total
    items
    customer
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=16.0]; - // gr.spinellis.basic.invoice.Customer - c281 [label=<
    Customer
    name
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=16.0]; - // gr.spinellis.basic.product.Product - c282 [label=<
    Product
    name
    stock
    price
    category
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=16.0]; - // gr.spinellis.basic.product.Category - c283 [label=<
    Category
    name
    products
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=16.0]; - // gr.spinellis.basic.invoice.InvoiceItem ASSOC gr.spinellis.basic.product.Product - c279:p -> c282:p [taillabel="*", label="", headlabel="1", fontname="Helvetica", fontcolor="black", fontsize=10.0, color="black", arrowhead=none]; - // gr.spinellis.basic.invoice.Invoice ASSOC gr.spinellis.basic.invoice.Customer - c280:p -> c281:p [taillabel="*", label="", headlabel="1", fontname="Helvetica", fontcolor="black", fontsize=10.0, color="black", arrowhead=none]; - // gr.spinellis.basic.invoice.Invoice COMPOSED gr.spinellis.basic.invoice.InvoiceItem - c280:p -> c279:p [taillabel="1", label="", headlabel="*", fontname="Helvetica", fontcolor="black", fontsize=10.0, color="black", arrowhead=none, arrowtail=diamond, dir=both]; - // gr.spinellis.basic.product.Product ASSOC gr.spinellis.basic.product.Category - c282:p -> c283:p [taillabel="*", label="", headlabel="1", fontname="Helvetica", fontcolor="black", fontsize=10.0, color="black", arrowhead=none]; +graph [fontnames="svg"] +edge [fontname="Helvetica",fontsize=10,labelfontname="Helvetica",labelfontsize=10,color="black"]; +node [fontname="Helvetica",fontcolor="black",fontsize=10,shape=plaintext,margin=0,width=0,height=0]; +nodesep=0.25; +ranksep=0.5; +// gr.spinellis.basic.invoice.InvoiceItem +c279 [label=<
    InvoiceItem
    product
    quantity
    >, fontname="Helvetica", fontcolor="black", fontsize=16.0]; +// gr.spinellis.basic.invoice.Invoice +c280 [label=<
    Invoice
    total
    items
    customer
    >, fontname="Helvetica", fontcolor="black", fontsize=16.0]; +// gr.spinellis.basic.invoice.Customer +c281 [label=<
    Customer
    name
    >, fontname="Helvetica", fontcolor="black", fontsize=16.0]; +// gr.spinellis.basic.product.Product +c282 [label=<
    Product
    name
    stock
    price
    category
    >, fontname="Helvetica", fontcolor="black", fontsize=16.0]; +// gr.spinellis.basic.product.Category +c283 [label=<
    Category
    name
    products
    >, fontname="Helvetica", fontcolor="black", fontsize=16.0]; +// gr.spinellis.basic.invoice.InvoiceItem assoc gr.spinellis.basic.product.Product +c279 -> c282 [arrowhead=none,weight=2,taillabel="*", headlabel="1"]; +// gr.spinellis.basic.invoice.Invoice assoc gr.spinellis.basic.invoice.Customer +c280 -> c281 [arrowhead=none,weight=2,taillabel="*", headlabel="1"]; +// gr.spinellis.basic.invoice.Invoice composed gr.spinellis.basic.invoice.InvoiceItem +c280 -> c279 [arrowhead=none,arrowtail=diamond,dir=back,weight=6,taillabel="1", headlabel="*"]; +// gr.spinellis.basic.product.Product assoc gr.spinellis.basic.product.Category +c282 -> c283 [arrowhead=none,weight=2,taillabel="*", headlabel="1"]; } diff --git a/testdata/dot-ref/ViewChildEmpty.dot b/testdata/dot-ref/ViewChildEmpty.dot index d525e6e..ab25f23 100644 --- a/testdata/dot-ref/ViewChildEmpty.dot +++ b/testdata/dot-ref/ViewChildEmpty.dot @@ -5,15 +5,16 @@ # digraph G { - edge [fontname="Helvetica",fontsize=10,labelfontname="Helvetica",labelfontsize=10]; - node [fontname="Helvetica",fontsize=10,shape=plaintext]; - nodesep=0.25; - ranksep=0.5; - // gr.spinellis.basic.product.Product - c244 [label=<
    Product
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // gr.spinellis.basic.product.Category - c245 [label=<
    Category
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // gr.spinellis.basic.product.Product ASSOC gr.spinellis.basic.product.Category - c244:p -> c245:p [taillabel="*", label="", headlabel="1", fontname="Helvetica", fontcolor="black", fontsize=10.0, color="black", arrowhead=none]; +graph [fontnames="svg"] +edge [fontname="Helvetica",fontsize=10,labelfontname="Helvetica",labelfontsize=10,color="black"]; +node [fontname="Helvetica",fontcolor="black",fontsize=10,shape=plaintext,margin=0,width=0,height=0]; +nodesep=0.25; +ranksep=0.5; +// gr.spinellis.basic.product.Product +c244 [label=<
    Product
    >]; +// gr.spinellis.basic.product.Category +c245 [label=<
    Category
    >]; +// gr.spinellis.basic.product.Product assoc gr.spinellis.basic.product.Category +c244 -> c245 [arrowhead=none,weight=2,taillabel="*", headlabel="1"]; } diff --git a/testdata/dot-ref/ViewChildOverride.dot b/testdata/dot-ref/ViewChildOverride.dot index 1ab5aab..4297729 100644 --- a/testdata/dot-ref/ViewChildOverride.dot +++ b/testdata/dot-ref/ViewChildOverride.dot @@ -5,15 +5,16 @@ # digraph G { - edge [fontname="Helvetica",fontsize=10,labelfontname="Helvetica",labelfontsize=10]; - node [fontname="Helvetica",fontsize=10,shape=plaintext]; - nodesep=0.25; - ranksep=0.5; - // gr.spinellis.basic.product.Product - c206 [label=<
    Product
    name
    stock
    price
    category
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // gr.spinellis.basic.product.Category - c207 [label=<
    Category
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // gr.spinellis.basic.product.Product ASSOC gr.spinellis.basic.product.Category - c206:p -> c207:p [taillabel="*", label="", headlabel="1", fontname="Helvetica", fontcolor="black", fontsize=10.0, color="black", arrowhead=none]; +graph [fontnames="svg"] +edge [fontname="Helvetica",fontsize=10,labelfontname="Helvetica",labelfontsize=10,color="black"]; +node [fontname="Helvetica",fontcolor="black",fontsize=10,shape=plaintext,margin=0,width=0,height=0]; +nodesep=0.25; +ranksep=0.5; +// gr.spinellis.basic.product.Product +c206 [label=<
    Product
    name
    stock
    price
    category
    >]; +// gr.spinellis.basic.product.Category +c207 [label=<
    Category
    >]; +// gr.spinellis.basic.product.Product assoc gr.spinellis.basic.product.Category +c206 -> c207 [arrowhead=none,weight=2,taillabel="*", headlabel="1"]; } diff --git a/testdata/dot-ref/ViewColors.dot b/testdata/dot-ref/ViewColors.dot index 2cb9a5a..59e9cec 100644 --- a/testdata/dot-ref/ViewColors.dot +++ b/testdata/dot-ref/ViewColors.dot @@ -5,31 +5,32 @@ # digraph G { - edge [fontname="Helvetica",fontsize=10,labelfontname="Helvetica",labelfontsize=10]; - node [fontname="Helvetica",fontsize=10,shape=plaintext]; - nodesep=0.25; - ranksep=0.5; - // gr.spinellis.basic.invoice.InvoiceItem - c164 [label=<
    InvoiceItem
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // gr.spinellis.basic.invoice.Invoice - c165 [label=<
    Invoice
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // gr.spinellis.basic.invoice.Customer - c166 [label=<
    Customer
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // gr.spinellis.basic.product.Product - c167 [label=<
    Product
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // gr.spinellis.basic.product.Category - c168 [label=<
    Category
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // gr.spinellis.basic.invoice.InvoiceItem ASSOC gr.spinellis.basic.product.Product - c164:p -> c167:p [taillabel="*", label="", headlabel="1", fontname="Helvetica", fontcolor="black", fontsize=10.0, color="black", arrowhead=none]; - // gr.spinellis.basic.invoice.Invoice ASSOC gr.spinellis.basic.invoice.Customer - c165:p -> c166:p [taillabel="*", label="", headlabel="1", fontname="Helvetica", fontcolor="black", fontsize=10.0, color="black", arrowhead=none]; - // gr.spinellis.basic.invoice.Invoice COMPOSED gr.spinellis.basic.invoice.InvoiceItem - c165:p -> c164:p [taillabel="1", label="", headlabel="*", fontname="Helvetica", fontcolor="black", fontsize=10.0, color="black", arrowhead=none, arrowtail=diamond, dir=both]; - // gr.spinellis.basic.product.Product ASSOC gr.spinellis.basic.product.Category - c167:p -> c168:p [taillabel="*", label="", headlabel="1", fontname="Helvetica", fontcolor="black", fontsize=10.0, color="black", arrowhead=none]; - // gr.spinellis.basic.product.Category DEPEND java.util.List - c168:p -> c202:p [taillabel="", label="", headlabel="", fontname="Helvetica", fontcolor="black", fontsize=10.0, color="black", arrowhead=open, style=dashed]; - // java.util.List - c202 [label=<
    «interface»
    List<E>
    >, URL="http://docs.oracle.com/javase/7/docs/api/java/util/List.html", fontname="Helvetica", fontcolor="black", fontsize=10.0]; +graph [fontnames="svg"] +edge [fontname="Helvetica",fontsize=10,labelfontname="Helvetica",labelfontsize=10,color="black"]; +node [fontname="Helvetica",fontcolor="black",fontsize=10,shape=plaintext,margin=0,width=0,height=0]; +nodesep=0.25; +ranksep=0.5; +// gr.spinellis.basic.invoice.InvoiceItem +c164 [label=<
    InvoiceItem
    >]; +// gr.spinellis.basic.invoice.Invoice +c165 [label=<
    Invoice
    >]; +// gr.spinellis.basic.invoice.Customer +c166 [label=<
    Customer
    >]; +// gr.spinellis.basic.product.Product +c167 [label=<
    Product
    >]; +// gr.spinellis.basic.product.Category +c168 [label=<
    Category
    >]; +// gr.spinellis.basic.invoice.InvoiceItem assoc gr.spinellis.basic.product.Product +c164 -> c167 [arrowhead=none,weight=2,taillabel="*", headlabel="1"]; +// gr.spinellis.basic.invoice.Invoice assoc gr.spinellis.basic.invoice.Customer +c165 -> c166 [arrowhead=none,weight=2,taillabel="*", headlabel="1"]; +// gr.spinellis.basic.invoice.Invoice composed gr.spinellis.basic.invoice.InvoiceItem +c165 -> c164 [arrowhead=none,arrowtail=diamond,dir=back,weight=6,taillabel="1", headlabel="*"]; +// gr.spinellis.basic.product.Product assoc gr.spinellis.basic.product.Category +c167 -> c168 [arrowhead=none,weight=2,taillabel="*", headlabel="1"]; +// gr.spinellis.basic.product.Category depend java.util.List +c168 -> c202 [arrowhead=open,style=dashed,weight=0]; +// java.util.List +c202 [label=<
    «interface»
    List<E>
    >, URL="http://docs.oracle.com/javase/7/docs/api/java/util/List.html"]; } diff --git a/testdata/dot-ref/ViewContext.dot b/testdata/dot-ref/ViewContext.dot index 45ee6f6..a20006b 100644 --- a/testdata/dot-ref/ViewContext.dot +++ b/testdata/dot-ref/ViewContext.dot @@ -5,39 +5,40 @@ # digraph G { - edge [fontname="Helvetica",fontsize=10,labelfontname="Helvetica",labelfontsize=10]; - node [fontname="Helvetica",fontsize=10,shape=plaintext]; - nodesep=0.25; - ranksep=0.5; - // gr.spinellis.context.classes.AClient - c424 [label=<
    AClient
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // gr.spinellis.context.classes.ASubclass - c426 [label=<
    ASubclass
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // gr.spinellis.context.classes.E - c427 [label=<
    E
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // gr.spinellis.context.classes.D - c429 [label=<
    D
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // gr.spinellis.context.classes.B - c432 [label=<
    B
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // gr.spinellis.context.classes.ABaseClass - c433 [label=<
    ABaseClass
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // gr.spinellis.context.classes.A - c434 [label=<
    A
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - //gr.spinellis.context.classes.ASubclass extends gr.spinellis.context.classes.A - c434:p -> c426:p [dir=back,arrowtail=empty]; - //gr.spinellis.context.classes.A extends gr.spinellis.context.classes.ABaseClass - c433:p -> c434:p [dir=back,arrowtail=empty]; - // gr.spinellis.context.classes.D NAVASSOC gr.spinellis.context.classes.A - c429:p -> c434:p [taillabel="", label="", headlabel="", fontname="Helvetica", fontcolor="black", fontsize=10.0, color="black", arrowhead=open]; - // gr.spinellis.context.classes.A NAVASSOC gr.spinellis.context.classes.B - c434:p -> c432:p [taillabel="", label="", headlabel="", fontname="Helvetica", fontcolor="black", fontsize=10.0, color="black", arrowhead=open]; - // gr.spinellis.context.classes.A NAVASSOC javax.swing.JComponent - c434:p -> c509:p [taillabel="", label="", headlabel="", fontname="Helvetica", fontcolor="black", fontsize=10.0, color="black", arrowhead=open]; - // gr.spinellis.context.classes.AClient DEPEND gr.spinellis.context.classes.A - c424:p -> c434:p [taillabel="", label="", headlabel="", fontname="Helvetica", fontcolor="black", fontsize=10.0, color="black", arrowhead=open, style=dashed]; - // gr.spinellis.context.classes.A DEPEND gr.spinellis.context.classes.E - c434:p -> c427:p [taillabel="", label="", headlabel="", fontname="Helvetica", fontcolor="black", fontsize=10.0, color="black", arrowhead=open, style=dashed]; - // javax.swing.JComponent - c509 [label=<
    JComponent
    >, URL="http://docs.oracle.com/javase/7/docs/api/javax/swing/JComponent.html", fontname="Helvetica", fontcolor="black", fontsize=10.0]; +graph [fontnames="svg"] +edge [fontname="Helvetica",fontsize=10,labelfontname="Helvetica",labelfontsize=10,color="black"]; +node [fontname="Helvetica",fontcolor="black",fontsize=10,shape=plaintext,margin=0,width=0,height=0]; +nodesep=0.25; +ranksep=0.5; +// gr.spinellis.context.classes.AClient +c424 [label=<
    AClient
    >]; +// gr.spinellis.context.classes.ASubclass +c426 [label=<
    ASubclass
    >]; +// gr.spinellis.context.classes.E +c427 [label=<
    E
    >]; +// gr.spinellis.context.classes.D +c429 [label=<
    D
    >]; +// gr.spinellis.context.classes.B +c432 [label=<
    B
    >]; +// gr.spinellis.context.classes.ABaseClass +c433 [label=<
    ABaseClass
    >]; +// gr.spinellis.context.classes.A +c434 [label=<
    A
    >]; +// gr.spinellis.context.classes.ASubclass extends gr.spinellis.context.classes.A +c434 -> c426 [arrowtail=empty,dir=back,weight=10]; +// gr.spinellis.context.classes.A extends gr.spinellis.context.classes.ABaseClass +c433 -> c434 [arrowtail=empty,dir=back,weight=10]; +// gr.spinellis.context.classes.D navassoc gr.spinellis.context.classes.A +c429 -> c434 [arrowhead=open,weight=1]; +// gr.spinellis.context.classes.A navassoc gr.spinellis.context.classes.B +c434 -> c432 [arrowhead=open,weight=1]; +// gr.spinellis.context.classes.A navassoc javax.swing.JComponent +c434 -> c509 [arrowhead=open,weight=1]; +// gr.spinellis.context.classes.AClient depend gr.spinellis.context.classes.A +c424 -> c434 [arrowhead=open,style=dashed,weight=0]; +// gr.spinellis.context.classes.A depend gr.spinellis.context.classes.E +c434 -> c427 [arrowhead=open,style=dashed,weight=0]; +// javax.swing.JComponent +c509 [label=<
    JComponent
    >, URL="http://docs.oracle.com/javase/7/docs/api/javax/swing/JComponent.html"]; } - + diff --git a/testdata/dot-ref/ViewInterfaces.dot b/testdata/dot-ref/ViewInterfaces.dot index f7d2b69..7e1938e 100644 --- a/testdata/dot-ref/ViewInterfaces.dot +++ b/testdata/dot-ref/ViewInterfaces.dot @@ -5,27 +5,28 @@ # digraph G { - edge [fontname="Helvetica",fontsize=10,labelfontname="Helvetica",labelfontsize=10]; - node [fontname="Helvetica",fontsize=10,shape=plaintext]; - nodesep=0.25; - ranksep=0.5; - // gr.spinellis.iface.classes.FarImplementor - c534 [label=<
    FarImplementor
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // gr.spinellis.iface.classes.DirectImplementor - c535 [label=<
    DirectImplementor
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // gr.spinellis.iface.classes.SubSubFace - c537 [label=<
    «interface»
    SubSubFace
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // gr.spinellis.iface.classes.SubFace - c538 [label=<
    «interface»
    SubFace
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // gr.spinellis.iface.classes.Face - c539 [label=<
    «interface»
    Face
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - //gr.spinellis.iface.classes.FarImplementor implements gr.spinellis.iface.classes.SubSubFace - c537:p -> c534:p [dir=back,arrowtail=empty,style=dashed]; - //gr.spinellis.iface.classes.DirectImplementor implements gr.spinellis.iface.classes.Face - c539:p -> c535:p [dir=back,arrowtail=empty,style=dashed]; - //gr.spinellis.iface.classes.SubSubFace implements gr.spinellis.iface.classes.SubFace - c538:p -> c537:p [dir=back,arrowtail=empty,style=dashed]; - //gr.spinellis.iface.classes.SubFace implements gr.spinellis.iface.classes.Face - c539:p -> c538:p [dir=back,arrowtail=empty,style=dashed]; +graph [fontnames="svg"] +edge [fontname="Helvetica",fontsize=10,labelfontname="Helvetica",labelfontsize=10,color="black"]; +node [fontname="Helvetica",fontcolor="black",fontsize=10,shape=plaintext,margin=0,width=0,height=0]; +nodesep=0.25; +ranksep=0.5; +// gr.spinellis.iface.classes.FarImplementor +c534 [label=<
    FarImplementor
    >]; +// gr.spinellis.iface.classes.DirectImplementor +c535 [label=<
    DirectImplementor
    >]; +// gr.spinellis.iface.classes.SubSubFace +c537 [label=<
    «interface»
    SubSubFace
    >]; +// gr.spinellis.iface.classes.SubFace +c538 [label=<
    «interface»
    SubFace
    >]; +// gr.spinellis.iface.classes.Face +c539 [label=<
    «interface»
    Face
    >]; +// gr.spinellis.iface.classes.FarImplementor implements gr.spinellis.iface.classes.SubSubFace +c537 -> c534 [arrowtail=empty,style=dashed,dir=back,weight=9]; +// gr.spinellis.iface.classes.DirectImplementor implements gr.spinellis.iface.classes.Face +c539 -> c535 [arrowtail=empty,style=dashed,dir=back,weight=9]; +// gr.spinellis.iface.classes.SubSubFace implements gr.spinellis.iface.classes.SubFace +c538 -> c537 [arrowtail=empty,style=dashed,dir=back,weight=9]; +// gr.spinellis.iface.classes.SubFace implements gr.spinellis.iface.classes.Face +c539 -> c538 [arrowtail=empty,style=dashed,dir=back,weight=9]; } diff --git a/testdata/dot-ref/ViewProduct.dot b/testdata/dot-ref/ViewProduct.dot index 1c3c1ca..8f2192a 100644 --- a/testdata/dot-ref/ViewProduct.dot +++ b/testdata/dot-ref/ViewProduct.dot @@ -5,15 +5,16 @@ # digraph G { - edge [fontname="Helvetica",fontsize=10,labelfontname="Helvetica",labelfontsize=10]; - node [fontname="Helvetica",fontsize=10,shape=plaintext]; - nodesep=0.25; - ranksep=0.5; - // gr.spinellis.basic.product.Product - c129 [label=<
    Product
    name
    stock
    price
    category
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // gr.spinellis.basic.product.Category - c130 [label=<
    Category
    name
    products
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // gr.spinellis.basic.product.Product ASSOC gr.spinellis.basic.product.Category - c129:p -> c130:p [taillabel="*", label="", headlabel="1", fontname="Helvetica", fontcolor="black", fontsize=10.0, color="black", arrowhead=none]; +graph [fontnames="svg"] +edge [fontname="Helvetica",fontsize=10,labelfontname="Helvetica",labelfontsize=10,color="black"]; +node [fontname="Helvetica",fontcolor="black",fontsize=10,shape=plaintext,margin=0,width=0,height=0]; +nodesep=0.25; +ranksep=0.5; +// gr.spinellis.basic.product.Product +c129 [label=<
    Product
    name
    stock
    price
    category
    >]; +// gr.spinellis.basic.product.Category +c130 [label=<
    Category
    name
    products
    >]; +// gr.spinellis.basic.product.Product assoc gr.spinellis.basic.product.Category +c129 -> c130 [arrowhead=none,weight=2,taillabel="*", headlabel="1"]; } diff --git a/testdata/dot-ref/ViewSubclasses.dot b/testdata/dot-ref/ViewSubclasses.dot index a4034a4..0dc6c7f 100644 --- a/testdata/dot-ref/ViewSubclasses.dot +++ b/testdata/dot-ref/ViewSubclasses.dot @@ -5,27 +5,28 @@ # digraph G { - edge [fontname="Helvetica",fontsize=10,labelfontname="Helvetica",labelfontsize=10]; - node [fontname="Helvetica",fontsize=10,shape=plaintext]; - nodesep=0.25; - ranksep=0.5; - // gr.spinellis.subclass.classes.SubOneTwo - c580 [label=<
    SubOneTwo
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // gr.spinellis.subclass.classes.SubOneOne - c581 [label=<
    SubOneOne
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // gr.spinellis.subclass.classes.SubTwo - c582 [label=<
    SubTwo
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // gr.spinellis.subclass.classes.SubOne - c583 [label=<
    SubOne
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // gr.spinellis.subclass.classes.Super - c584 [label=<
    Super
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - //gr.spinellis.subclass.classes.SubOneTwo extends gr.spinellis.subclass.classes.SubOne - c583:p -> c580:p [dir=back,arrowtail=empty]; - //gr.spinellis.subclass.classes.SubOneOne extends gr.spinellis.subclass.classes.SubOne - c583:p -> c581:p [dir=back,arrowtail=empty]; - //gr.spinellis.subclass.classes.SubTwo extends gr.spinellis.subclass.classes.Super - c584:p -> c582:p [dir=back,arrowtail=empty]; - //gr.spinellis.subclass.classes.SubOne extends gr.spinellis.subclass.classes.Super - c584:p -> c583:p [dir=back,arrowtail=empty]; +graph [fontnames="svg"] +edge [fontname="Helvetica",fontsize=10,labelfontname="Helvetica",labelfontsize=10,color="black"]; +node [fontname="Helvetica",fontcolor="black",fontsize=10,shape=plaintext,margin=0,width=0,height=0]; +nodesep=0.25; +ranksep=0.5; +// gr.spinellis.subclass.classes.SubOneTwo +c580 [label=<
    SubOneTwo
    >]; +// gr.spinellis.subclass.classes.SubOneOne +c581 [label=<
    SubOneOne
    >]; +// gr.spinellis.subclass.classes.SubTwo +c582 [label=<
    SubTwo
    >]; +// gr.spinellis.subclass.classes.SubOne +c583 [label=<
    SubOne
    >]; +// gr.spinellis.subclass.classes.Super +c584 [label=<
    Super
    >]; +// gr.spinellis.subclass.classes.SubOneTwo extends gr.spinellis.subclass.classes.SubOne +c583 -> c580 [arrowtail=empty,dir=back,weight=10]; +// gr.spinellis.subclass.classes.SubOneOne extends gr.spinellis.subclass.classes.SubOne +c583 -> c581 [arrowtail=empty,dir=back,weight=10]; +// gr.spinellis.subclass.classes.SubTwo extends gr.spinellis.subclass.classes.Super +c584 -> c582 [arrowtail=empty,dir=back,weight=10]; +// gr.spinellis.subclass.classes.SubOne extends gr.spinellis.subclass.classes.Super +c584 -> c583 [arrowtail=empty,dir=back,weight=10]; } - + diff --git a/testdata/dot-ref/active.dot b/testdata/dot-ref/active.dot new file mode 100644 index 0000000..02c5a4e --- /dev/null +++ b/testdata/dot-ref/active.dot @@ -0,0 +1,16 @@ +#!/usr/local/bin/dot +# +# Class diagram +# Generated by UMLGraph version R5_7_2-54-gbca0ce (http://www.spinellis.gr/umlgraph/) +# + +digraph G { +graph [fontnames="svg"] +edge [fontname="Helvetica",fontsize=10,labelfontname="Helvetica",labelfontsize=10,color="black"]; +node [fontname="Helvetica",fontcolor="black",fontsize=10,shape=plaintext,margin=0,width=0,height=0]; +nodesep=0.25; +ranksep=0.5; +// Active +c32 [label=<
    Active
    run()
    >]; +} + diff --git a/testdata/dot-ref/advrel.dot b/testdata/dot-ref/advrel.dot index 92e9a8e..2b21798 100644 --- a/testdata/dot-ref/advrel.dot +++ b/testdata/dot-ref/advrel.dot @@ -5,31 +5,32 @@ # digraph G { - edge [fontname="Helvetica",fontsize=10,labelfontname="Helvetica",labelfontsize=10]; - node [fontname="Helvetica",fontsize=10,shape=plaintext]; - nodesep=0.25; - ranksep=0.5; - // Controller - c5 [label=<
    Controller
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // EmbeddedAgent - c6 [label=<
    EmbeddedAgent
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // PowerManager - c7 [label=<
    PowerManager
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // SetTopController - c8 [label=<
    SetTopController
    authorizationLevel
    startUp()
    shutDown()
    connect()
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // ChannelIterator - c9 [label=<
    ChannelIterator
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // URLStreamHandler - c10 [label=<
    «interface»
    URLStreamHandler
    OpenConnection()
    parseURL()
    setURL()
    toExternalForm()
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - //SetTopController extends Controller - c5:p -> c8:p [dir=back,arrowtail=empty]; - //SetTopController extends EmbeddedAgent - c6:p -> c8:p [dir=back,arrowtail=empty]; - //SetTopController implements URLStreamHandler - c10:p -> c8:p [dir=back,arrowtail=empty,style=dashed]; - // SetTopController NAVASSOC PowerManager - c8:p -> c7:p [taillabel="", label="", headlabel="", fontname="Helvetica", fontcolor="black", fontsize=10.0, color="black", arrowhead=open]; - // ChannelIterator DEPEND SetTopController - c9:p -> c8:p [taillabel="", label="«friend»", headlabel="", fontname="Helvetica", fontcolor="black", fontsize=10.0, color="black", arrowhead=open, style=dashed]; +graph [fontnames="svg"] +edge [fontname="Helvetica",fontsize=10,labelfontname="Helvetica",labelfontsize=10,color="black"]; +node [fontname="Helvetica",fontcolor="black",fontsize=10,shape=plaintext,margin=0,width=0,height=0]; +nodesep=0.25; +ranksep=0.5; +// Controller +c5 [label=<
    Controller
    >]; +// EmbeddedAgent +c6 [label=<
    EmbeddedAgent
    >]; +// PowerManager +c7 [label=<
    PowerManager
    >]; +// SetTopController +c8 [label=<
    SetTopController
    authorizationLevel
    startUp()
    shutDown()
    connect()
    >]; +// ChannelIterator +c9 [label=<
    ChannelIterator
    >]; +// URLStreamHandler +c10 [label=<
    «interface»
    URLStreamHandler
    OpenConnection()
    parseURL()
    setURL()
    toExternalForm()
    >]; +// SetTopController extends Controller +c5 -> c8 [arrowtail=empty,dir=back,weight=10]; +// SetTopController extends EmbeddedAgent +c6 -> c8 [arrowtail=empty,dir=back,weight=10]; +// SetTopController implements URLStreamHandler +c10 -> c8 [arrowtail=empty,style=dashed,dir=back,weight=9]; +// SetTopController navassoc PowerManager +c8 -> c7 [arrowhead=open,weight=1]; +// ChannelIterator depend SetTopController +c9 -> c8 [arrowhead=open,style=dashed,weight=0,label="«friend»"]; } diff --git a/testdata/dot-ref/assoc.dot b/testdata/dot-ref/assoc.dot index df9b3a1..29715e0 100644 --- a/testdata/dot-ref/assoc.dot +++ b/testdata/dot-ref/assoc.dot @@ -5,20 +5,21 @@ # digraph G { - edge [fontname="Helvetica",fontsize=10,labelfontname="Helvetica",labelfontsize=10]; - node [fontname="Helvetica",fontsize=10,shape=plaintext]; - nodesep=0.25; - ranksep=0.5; - rankdir=LR; - // UserGroup - c12 [label=<
    UserGroup
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // User - c13 [label=<
    User
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // Password - c14 [label=<
    Password
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // UserGroup ASSOC User - c12:p -> c13:p [taillabel="*", label="", headlabel="*\n\n+user ", fontname="Helvetica", fontcolor="black", fontsize=10.0, color="black", arrowhead=none]; - // User NAVASSOC Password - c13:p -> c14:p [taillabel="1\n\n+owner\r", label="", headlabel="*\n\n+key", fontname="Helvetica", fontcolor="black", fontsize=10.0, color="black", arrowhead=open]; +graph [fontnames="svg"] +edge [fontname="Helvetica",fontsize=10,labelfontname="Helvetica",labelfontsize=10,color="black"]; +node [fontname="Helvetica",fontcolor="black",fontsize=10,shape=plaintext,margin=0,width=0,height=0]; +nodesep=0.25; +ranksep=0.5; +rankdir=LR; +// UserGroup +c12 [label=<
    UserGroup
    >]; +// User +c13 [label=<
    User
    >]; +// Password +c14 [label=<
    Password
    >]; +// UserGroup assoc User +c12 -> c13 [arrowhead=none,weight=2,taillabel="*", headlabel="*\n\n+user "]; +// User navassoc Password +c13 -> c14 [arrowhead=open,weight=1,taillabel="1\n\n+owner\r", headlabel="*\n\n+key"]; } diff --git a/testdata/dot-ref/car.dot b/testdata/dot-ref/car.dot index 8429912..1b3b572 100644 --- a/testdata/dot-ref/car.dot +++ b/testdata/dot-ref/car.dot @@ -5,23 +5,24 @@ # digraph G { - edge [fontname="Helvetica",fontsize=10,labelfontname="Helvetica",labelfontsize=10]; - node [fontname="Helvetica",fontsize=10,shape=plaintext]; - nodesep=0.25; - ranksep=0.5; - // Tyre - c15 [label=<
    Tyre
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // Engine - c16 [label=<
    Engine
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // Body - c17 [label=<
    Body
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // Car - c18 [label=<
    Car
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // Car COMPOSED Tyre - c18:p -> c15:p [taillabel="1", label="", headlabel="4", fontname="Helvetica", fontcolor="black", fontsize=10.0, color="black", arrowhead=none, arrowtail=diamond, dir=both]; - // Car COMPOSED Engine - c18:p -> c16:p [taillabel="1", label="", headlabel="1", fontname="Helvetica", fontcolor="black", fontsize=10.0, color="black", arrowhead=none, arrowtail=diamond, dir=both]; - // Car COMPOSED Body - c18:p -> c17:p [taillabel="1", label="", headlabel="1", fontname="Helvetica", fontcolor="black", fontsize=10.0, color="black", arrowhead=none, arrowtail=diamond, dir=both]; +graph [fontnames="svg"] +edge [fontname="Helvetica",fontsize=10,labelfontname="Helvetica",labelfontsize=10,color="black"]; +node [fontname="Helvetica",fontcolor="black",fontsize=10,shape=plaintext,margin=0,width=0,height=0]; +nodesep=0.25; +ranksep=0.5; +// Tyre +c15 [label=<
    Tyre
    >]; +// Engine +c16 [label=<
    Engine
    >]; +// Body +c17 [label=<
    Body
    >]; +// Car +c18 [label=<
    Car
    >]; +// Car composed Tyre +c18 -> c15 [arrowhead=none,arrowtail=diamond,dir=back,weight=6,taillabel="1", headlabel="4"]; +// Car composed Engine +c18 -> c16 [arrowhead=none,arrowtail=diamond,dir=back,weight=6,taillabel="1", headlabel="1"]; +// Car composed Body +c18 -> c17 [arrowhead=none,arrowtail=diamond,dir=back,weight=6,taillabel="1", headlabel="1"]; } diff --git a/testdata/dot-ref/catalina.dot b/testdata/dot-ref/catalina.dot index 8fea9a5..b0b624a 100644 --- a/testdata/dot-ref/catalina.dot +++ b/testdata/dot-ref/catalina.dot @@ -5,53 +5,54 @@ # digraph G { - edge [fontname="Helvetica",fontsize=10,labelfontname="Helvetica",labelfontsize=10]; - node [fontname="Helvetica",fontsize=10,shape=plaintext]; - nodesep=0.25; - ranksep=0.5; - // HttpResponseBase - c19 [label=<
    HttpResponseBase
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // HttpResponseWrapper - c20 [label=<
    HttpResponseWrapper
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // HttpResponseFacade - c21 [label=<
    HttpResponseFacade
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // ResponseWrapper - c22 [label=<
    ResponseWrapper
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // HttpResponse - c23 [label=<
    «interface»
    HttpResponse
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // ResponseBase - c24 [label=<
    ResponseBase
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // HttpServletResponse - c25 [label=<
    «interface»
    HttpServletResponse
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // ResponseFacade - c26 [label=<
    ResponseFacade
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // ServletResponse - c27 [label=<
    «interface»
    ServletResponse
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // Response - c28 [label=<
    «interface»
    Response
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - //HttpResponseBase extends ResponseBase - c24:p -> c19:p [dir=back,arrowtail=empty]; - //HttpResponseBase implements HttpResponse - c23:p -> c19:p [dir=back,arrowtail=empty,style=dashed]; - //HttpResponseBase implements HttpServletResponse - c25:p -> c19:p [dir=back,arrowtail=empty,style=dashed]; - //HttpResponseWrapper extends ResponseWrapper - c22:p -> c20:p [dir=back,arrowtail=empty]; - //HttpResponseWrapper implements HttpResponse - c23:p -> c20:p [dir=back,arrowtail=empty,style=dashed]; - //HttpResponseFacade extends ResponseFacade - c26:p -> c21:p [dir=back,arrowtail=empty]; - //HttpResponseFacade implements HttpServletResponse - c25:p -> c21:p [dir=back,arrowtail=empty,style=dashed]; - //ResponseWrapper implements Response - c28:p -> c22:p [dir=back,arrowtail=empty,style=dashed]; - //HttpResponse implements Response - c28:p -> c23:p [dir=back,arrowtail=empty,style=dashed]; - //ResponseBase implements Response - c28:p -> c24:p [dir=back,arrowtail=empty,style=dashed]; - //ResponseBase implements ServletResponse - c27:p -> c24:p [dir=back,arrowtail=empty,style=dashed]; - //ResponseFacade implements ServletResponse - c27:p -> c26:p [dir=back,arrowtail=empty,style=dashed]; +graph [fontnames="svg"] +edge [fontname="Helvetica",fontsize=10,labelfontname="Helvetica",labelfontsize=10,color="black"]; +node [fontname="Helvetica",fontcolor="black",fontsize=10,shape=plaintext,margin=0,width=0,height=0]; +nodesep=0.25; +ranksep=0.5; +// HttpResponseBase +c19 [label=<
    HttpResponseBase
    >]; +// HttpResponseWrapper +c20 [label=<
    HttpResponseWrapper
    >]; +// HttpResponseFacade +c21 [label=<
    HttpResponseFacade
    >]; +// ResponseWrapper +c22 [label=<
    ResponseWrapper
    >]; +// HttpResponse +c23 [label=<
    «interface»
    HttpResponse
    >]; +// ResponseBase +c24 [label=<
    ResponseBase
    >]; +// HttpServletResponse +c25 [label=<
    «interface»
    HttpServletResponse
    >]; +// ResponseFacade +c26 [label=<
    ResponseFacade
    >]; +// ServletResponse +c27 [label=<
    «interface»
    ServletResponse
    >]; +// Response +c28 [label=<
    «interface»
    Response
    >]; +// HttpResponseBase extends ResponseBase +c24 -> c19 [arrowtail=empty,dir=back,weight=10]; +// HttpResponseBase implements HttpResponse +c23 -> c19 [arrowtail=empty,style=dashed,dir=back,weight=9]; +// HttpResponseBase implements HttpServletResponse +c25 -> c19 [arrowtail=empty,style=dashed,dir=back,weight=9]; +// HttpResponseWrapper extends ResponseWrapper +c22 -> c20 [arrowtail=empty,dir=back,weight=10]; +// HttpResponseWrapper implements HttpResponse +c23 -> c20 [arrowtail=empty,style=dashed,dir=back,weight=9]; +// HttpResponseFacade extends ResponseFacade +c26 -> c21 [arrowtail=empty,dir=back,weight=10]; +// HttpResponseFacade implements HttpServletResponse +c25 -> c21 [arrowtail=empty,style=dashed,dir=back,weight=9]; +// ResponseWrapper implements Response +c28 -> c22 [arrowtail=empty,style=dashed,dir=back,weight=9]; +// HttpResponse implements Response +c28 -> c23 [arrowtail=empty,style=dashed,dir=back,weight=9]; +// ResponseBase implements Response +c28 -> c24 [arrowtail=empty,style=dashed,dir=back,weight=9]; +// ResponseBase implements ServletResponse +c27 -> c24 [arrowtail=empty,style=dashed,dir=back,weight=9]; +// ResponseFacade implements ServletResponse +c27 -> c26 [arrowtail=empty,style=dashed,dir=back,weight=9]; } diff --git a/testdata/dot-ref/class-eg.dot b/testdata/dot-ref/class-eg.dot index 28f9188..3ac8d11 100644 --- a/testdata/dot-ref/class-eg.dot +++ b/testdata/dot-ref/class-eg.dot @@ -5,19 +5,20 @@ # digraph G { - edge [fontname="Helvetica",fontsize=10,labelfontname="Helvetica",labelfontsize=10]; - node [fontname="Helvetica",fontsize=10,shape=plaintext]; - nodesep=0.25; - ranksep=0.5; - // Person - c30 [label=<
    Person
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // Employee - c31 [label=<
    Employee
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // Client - c32 [label=<
    Client
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - //Employee extends Person - c30:p -> c31:p [dir=back,arrowtail=empty]; - //Client extends Person - c30:p -> c32:p [dir=back,arrowtail=empty]; +graph [fontnames="svg"] +edge [fontname="Helvetica",fontsize=10,labelfontname="Helvetica",labelfontsize=10,color="black"]; +node [fontname="Helvetica",fontcolor="black",fontsize=10,shape=plaintext,margin=0,width=0,height=0]; +nodesep=0.25; +ranksep=0.5; +// Person +c30 [label=<
    Person
    >]; +// Employee +c31 [label=<
    Employee
    >]; +// Client +c32 [label=<
    Client
    >]; +// Employee extends Person +c30 -> c31 [arrowtail=empty,dir=back,weight=10]; +// Client extends Person +c30 -> c32 [arrowtail=empty,dir=back,weight=10]; } diff --git a/testdata/dot-ref/classadd.dot b/testdata/dot-ref/classadd.dot index 966a36c..acc4817 100644 --- a/testdata/dot-ref/classadd.dot +++ b/testdata/dot-ref/classadd.dot @@ -5,11 +5,12 @@ # digraph G { - edge [fontname="Helvetica",fontsize=10,labelfontname="Helvetica",labelfontsize=10]; - node [fontname="Helvetica",fontsize=10,shape=plaintext]; - nodesep=0.25; - ranksep=0.5; - // ActionQueue - c35 [label=<
    «container»
    ActionQueue
    {version = 3.2}
    add(a : Action)
    add(a : Action, n : int)
    {version = 1.0}
    remove(n : int)
    «query»
    length() : int
    «helper functions»
    reorder()
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; +graph [fontnames="svg"] +edge [fontname="Helvetica",fontsize=10,labelfontname="Helvetica",labelfontsize=10,color="black"]; +node [fontname="Helvetica",fontcolor="black",fontsize=10,shape=plaintext,margin=0,width=0,height=0]; +nodesep=0.25; +ranksep=0.5; +// ActionQueue +c35 [label=<
    «container»
    ActionQueue
    {version = 3.2}
    add(a : Action)
    add(a : Action, n : int)
    {version = 1.0}
    remove(n : int)
    «query»
    length() : int
    «helper functions»
    reorder()
    >]; } diff --git a/testdata/dot-ref/color.dot b/testdata/dot-ref/color.dot index 77937b2..32ccad6 100644 --- a/testdata/dot-ref/color.dot +++ b/testdata/dot-ref/color.dot @@ -5,25 +5,26 @@ # digraph G { - edge [fontname="Helvetica",fontsize=10,labelfontname="Helvetica",labelfontsize=10]; - node [fontname="Serif",fontsize=10,shape=plaintext]; - nodesep=0.25; - ranksep=0.5; - bgcolor=".7 .9 1"; - - // Pixel - c37 [label=<
    Pixel
    - x : int
    - y : int
    >, URL="null", fontname="arial", fontcolor="white", fontsize=14.0]; - // Red - c38 [label=<
    Red
    >, URL="null", fontname="Serif", fontcolor="black", fontsize=14.0]; - // Green - c39 [label=<
    Green
    >, URL="null", fontname="Serif", fontcolor="black", fontsize=14.0]; - // Blue - c40 [label=<
    Blue
    >, URL="null", fontname="Serif", fontcolor="black", fontsize=14.0]; - // Pixel COMPOSED Red - c37:p -> c38:p [taillabel="", label="", headlabel="", fontname="Helvetica", fontcolor="black", fontsize=10.0, color="yellow", arrowhead=none, arrowtail=diamond, dir=both]; - // Pixel COMPOSED Green - c37:p -> c39:p [taillabel="", label="", headlabel="", fontname="Helvetica", fontcolor="black", fontsize=10.0, color="yellow", arrowhead=none, arrowtail=diamond, dir=both]; - // Pixel COMPOSED Blue - c37:p -> c40:p [taillabel="", label="", headlabel="", fontname="Helvetica", fontcolor="black", fontsize=10.0, color="yellow", arrowhead=none, arrowtail=diamond, dir=both]; +graph [fontnames="svg"] +edge [fontname="Helvetica",fontsize=10,labelfontname="Helvetica",labelfontsize=10,color="yellow"]; +node [fontname="Serif",fontcolor="black",fontsize=14,shape=plaintext,margin=0,width=0,height=0]; +nodesep=0.25; +ranksep=0.5; +bgcolor=".7 .9 1"; + +// Pixel +c37 [label=<
    Pixel
    - x : int
    - y : int
    >]; +// Red +c38 [label=<
    Red
    >]; +// Green +c39 [label=<
    Green
    >]; +// Blue +c40 [label=<
    Blue
    >]; +// Pixel composed Red +c37 -> c38 [arrowhead=none,arrowtail=diamond,dir=back,weight=6]; +// Pixel composed Green +c37 -> c39 [arrowhead=none,arrowtail=diamond,dir=back,weight=6]; +// Pixel composed Blue +c37 -> c40 [arrowhead=none,arrowtail=diamond,dir=back,weight=6]; } - + diff --git a/testdata/dot-ref/ctor.dot b/testdata/dot-ref/ctor.dot index 0826c73..b35fe05 100644 --- a/testdata/dot-ref/ctor.dot +++ b/testdata/dot-ref/ctor.dot @@ -5,11 +5,12 @@ # digraph G { - edge [fontname="Helvetica",fontsize=10,labelfontname="Helvetica",labelfontsize=10]; - node [fontname="Helvetica",fontsize=10,shape=plaintext]; - nodesep=0.25; - ranksep=0.5; - // Junk - c43 [label=<
    Junk
    - value : int
    + Junk(val : int)
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; +graph [fontnames="svg"] +edge [fontname="Helvetica",fontsize=10,labelfontname="Helvetica",labelfontsize=10,color="black"]; +node [fontname="Helvetica",fontcolor="black",fontsize=10,shape=plaintext,margin=0,width=0,height=0]; +nodesep=0.25; +ranksep=0.5; +// Junk +c43 [label=<
    Junk
    - value : int
    + Junk(val : int)
    >]; } diff --git a/testdata/dot-ref/disable.dot b/testdata/dot-ref/disable.dot index 3759817..7388fd1 100644 --- a/testdata/dot-ref/disable.dot +++ b/testdata/dot-ref/disable.dot @@ -5,15 +5,16 @@ # digraph G { - edge [fontname="Helvetica",fontsize=10,labelfontname="Helvetica",labelfontsize=10]; - node [fontname="Helvetica",fontsize=10,shape=plaintext]; - nodesep=0.25; - ranksep=0.5; - // Person1 - c45 [label=<
    Person1
    ~ address : String
    ~ name : String
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // Person2 - c46 [label=<
    Person2
    ~ displayName() : String
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // Person3 - c47 [label=<
    Person3
    address : Address
    name : String
    displayName() : String
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; +graph [fontnames="svg"] +edge [fontname="Helvetica",fontsize=10,labelfontname="Helvetica",labelfontsize=10,color="black"]; +node [fontname="Helvetica",fontcolor="black",fontsize=10,shape=plaintext,margin=0,width=0,height=0]; +nodesep=0.25; +ranksep=0.5; +// Person1 +c45 [label=<
    Person1
    ~ address : String
    ~ name : String
    >]; +// Person2 +c46 [label=<
    Person2
    ~ displayName() : String
    >]; +// Person3 +c47 [label=<
    Person3
    address : Address
    name : String
    displayName() : String
    >]; } diff --git a/testdata/dot-ref/extends.dot b/testdata/dot-ref/extends.dot index 2829ebb..6328183 100644 --- a/testdata/dot-ref/extends.dot +++ b/testdata/dot-ref/extends.dot @@ -5,13 +5,14 @@ # digraph G { - edge [fontname="Helvetica",fontsize=10,labelfontname="Helvetica",labelfontsize=10]; - node [fontname="Helvetica",fontsize=10,shape=plaintext]; - nodesep=0.25; - ranksep=0.5; - // Base - c48 [label=<
    Base
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // Test2 - c49 [label=<
    Test2<B extends Base>
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; +graph [fontnames="svg"] +edge [fontname="Helvetica",fontsize=10,labelfontname="Helvetica",labelfontsize=10,color="black"]; +node [fontname="Helvetica",fontcolor="black",fontsize=10,shape=plaintext,margin=0,width=0,height=0]; +nodesep=0.25; +ranksep=0.5; +// Base +c48 [label=<
    Base
    >]; +// Test2 +c49 [label=<
    Test2<B extends Base>
    >]; } diff --git a/testdata/dot-ref/foo.dot b/testdata/dot-ref/foo.dot index 7c4e2a2..21a8513 100644 --- a/testdata/dot-ref/foo.dot +++ b/testdata/dot-ref/foo.dot @@ -5,21 +5,22 @@ # digraph G { - edge [fontname="Helvetica",fontsize=10,labelfontname="Helvetica",labelfontsize=10]; - node [fontname="Helvetica",fontsize=10,shape=plaintext]; - nodesep=0.25; - ranksep=0.5; - // a.b.c.UMLOptions - c50 [label=<
    UMLOptions
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // a.b.c.UserGroup - c51 [label=<
    UserGroup
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // a.b.c.User - c52 [label=<
    User
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // a.b.c.Password - c53 [label=<
    Password
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // a.b.c.UserGroup ASSOC a.b.c.User - c51:p -> c52:p [taillabel="*", label="", headlabel="*\n\n+user ", fontname="Helvetica", fontcolor="black", fontsize=10.0, color="black", arrowhead=none]; - // a.b.c.User NAVASSOC a.b.c.Password - c52:p -> c53:p [taillabel="1\n\n+owner\r", label="", headlabel="*\n\n+key", fontname="Helvetica", fontcolor="black", fontsize=10.0, color="black", arrowhead=open]; +graph [fontnames="svg"] +edge [fontname="Helvetica",fontsize=10,labelfontname="Helvetica",labelfontsize=10,color="black"]; +node [fontname="Helvetica",fontcolor="black",fontsize=10,shape=plaintext,margin=0,width=0,height=0]; +nodesep=0.25; +ranksep=0.5; +// a.b.c.UMLOptions +c50 [label=<
    UMLOptions
    >]; +// a.b.c.UserGroup +c51 [label=<
    UserGroup
    >]; +// a.b.c.User +c52 [label=<
    User
    >]; +// a.b.c.Password +c53 [label=<
    Password
    >]; +// a.b.c.UserGroup assoc a.b.c.User +c51 -> c52 [arrowhead=none,weight=2,taillabel="*", headlabel="*\n\n+user "]; +// a.b.c.User navassoc a.b.c.Password +c52 -> c53 [arrowhead=open,weight=1,taillabel="1\n\n+owner\r", headlabel="*\n\n+key"]; } diff --git a/testdata/dot-ref/general.dot b/testdata/dot-ref/general.dot index 75cdc3f..85e9787 100644 --- a/testdata/dot-ref/general.dot +++ b/testdata/dot-ref/general.dot @@ -5,49 +5,50 @@ # digraph G { - edge [fontname="Helvetica",fontsize=10,labelfontname="Helvetica",labelfontsize=10]; - node [fontname="Helvetica",fontsize=10,shape=plaintext]; - nodesep=0.25; - ranksep=0.5; - // Asset - c55 [label=<
    Asset
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // InterestBearingItem - c56 [label=<
    InterestBearingItem
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // InsurableItem - c57 [label=<
    InsurableItem
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // BankAccount - c58 [label=<
    BankAccount
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // RealEstate - c59 [label=<
    RealEstate
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // Security - c60 [label=<
    Security
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // Stock - c61 [label=<
    Stock
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // Bond - c62 [label=<
    Bond
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // CheckingAccount - c63 [label=<
    CheckingAccount
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // SavingsAccount - c64 [label=<
    SavingsAccount
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - //BankAccount extends Asset - c55:p -> c58:p [dir=back,arrowtail=empty]; - //BankAccount extends InsurableItem - c57:p -> c58:p [dir=back,arrowtail=empty]; - //BankAccount extends InterestBearingItem - c56:p -> c58:p [dir=back,arrowtail=empty]; - //RealEstate extends Asset - c55:p -> c59:p [dir=back,arrowtail=empty]; - //RealEstate extends InsurableItem - c57:p -> c59:p [dir=back,arrowtail=empty]; - //Security extends Asset - c55:p -> c60:p [dir=back,arrowtail=empty]; - //Stock extends Security - c60:p -> c61:p [dir=back,arrowtail=empty]; - //Bond extends Security - c60:p -> c62:p [dir=back,arrowtail=empty]; - //CheckingAccount extends BankAccount - c58:p -> c63:p [dir=back,arrowtail=empty]; - //SavingsAccount extends BankAccount - c58:p -> c64:p [dir=back,arrowtail=empty]; +graph [fontnames="svg"] +edge [fontname="Helvetica",fontsize=10,labelfontname="Helvetica",labelfontsize=10,color="black"]; +node [fontname="Helvetica",fontcolor="black",fontsize=10,shape=plaintext,margin=0,width=0,height=0]; +nodesep=0.25; +ranksep=0.5; +// Asset +c55 [label=<
    Asset
    >]; +// InterestBearingItem +c56 [label=<
    InterestBearingItem
    >]; +// InsurableItem +c57 [label=<
    InsurableItem
    >]; +// BankAccount +c58 [label=<
    BankAccount
    >]; +// RealEstate +c59 [label=<
    RealEstate
    >]; +// Security +c60 [label=<
    Security
    >]; +// Stock +c61 [label=<
    Stock
    >]; +// Bond +c62 [label=<
    Bond
    >]; +// CheckingAccount +c63 [label=<
    CheckingAccount
    >]; +// SavingsAccount +c64 [label=<
    SavingsAccount
    >]; +// BankAccount extends Asset +c55 -> c58 [arrowtail=empty,dir=back,weight=10]; +// BankAccount extends InsurableItem +c57 -> c58 [arrowtail=empty,dir=back,weight=10]; +// BankAccount extends InterestBearingItem +c56 -> c58 [arrowtail=empty,dir=back,weight=10]; +// RealEstate extends Asset +c55 -> c59 [arrowtail=empty,dir=back,weight=10]; +// RealEstate extends InsurableItem +c57 -> c59 [arrowtail=empty,dir=back,weight=10]; +// Security extends Asset +c55 -> c60 [arrowtail=empty,dir=back,weight=10]; +// Stock extends Security +c60 -> c61 [arrowtail=empty,dir=back,weight=10]; +// Bond extends Security +c60 -> c62 [arrowtail=empty,dir=back,weight=10]; +// CheckingAccount extends BankAccount +c58 -> c63 [arrowtail=empty,dir=back,weight=10]; +// SavingsAccount extends BankAccount +c58 -> c64 [arrowtail=empty,dir=back,weight=10]; } diff --git a/testdata/dot-ref/java5.dot b/testdata/dot-ref/java5.dot index 3364bc4..18c40e7 100644 --- a/testdata/dot-ref/java5.dot +++ b/testdata/dot-ref/java5.dot @@ -5,13 +5,14 @@ # digraph G { - edge [fontname="Helvetica",fontsize=10,labelfontname="Helvetica",labelfontsize=10]; - node [fontname="Helvetica",fontsize=10,shape=plaintext]; - nodesep=0.25; - ranksep=0.5; - // Java5 - c78 [label=<
    Java5
    ~ state : Java5.States
    - specifiedPackages : Set<String>
    + printAll(args : String[])
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // Java5.States - c79 [label=<
    «enumeration»
    States
    start
    dash
    colon
    space
    open
    w
    close
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; +graph [fontnames="svg"] +edge [fontname="Helvetica",fontsize=10,labelfontname="Helvetica",labelfontsize=10,color="black"]; +node [fontname="Helvetica",fontcolor="black",fontsize=10,shape=plaintext,margin=0,width=0,height=0]; +nodesep=0.25; +ranksep=0.5; +// Java5 +c78 [label=<
    Java5
    ~ state : Java5.States
    - specifiedPackages : Set<String>
    + printAll(args : String[])
    >]; +// Java5.States +c79 [label=<
    «enumeration»
    States
    start
    dash
    colon
    space
    open
    w
    close
    >]; } diff --git a/testdata/dot-ref/schema.dot b/testdata/dot-ref/schema.dot index a723eab..6d97162 100644 --- a/testdata/dot-ref/schema.dot +++ b/testdata/dot-ref/schema.dot @@ -5,33 +5,34 @@ # digraph G { - edge [fontname="Helvetica",fontsize=10,labelfontname="Helvetica",labelfontsize=10]; - node [fontname="Helvetica",fontsize=10,shape=plaintext]; - nodesep=0.25; - ranksep=0.5; - // School - c103 [label=<
    School
    name : Name
    address : String
    phone : Number
    addStudent()
    removeStudent()
    getStudent()
    getAllStudents()
    addDepartment()
    removeDepartment()
    getDepartment()
    getAllDepartments()
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // Department - c104 [label=<
    Department
    name : Name
    addInstructor()
    removeInstructor()
    getInstructor()
    getAllInstructors()
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // Student - c105 [label=<
    Student
    name : Name
    studentID : Number
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // Course - c106 [label=<
    Course
    name : Name
    courseID : Number
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // Instructor - c107 [label=<
    Instructor
    name : Name
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // School HAS Student - c103:p -> c105:p [taillabel="1..*", label="Member", headlabel="*", fontname="Helvetica", fontcolor="black", fontsize=10.0, color="black", arrowhead=none, arrowtail=ediamond, dir=both]; - // School COMPOSED Department - c103:p -> c104:p [taillabel="1..*", label="Has", headlabel="1..*", fontname="Helvetica", fontcolor="black", fontsize=10.0, color="black", arrowhead=none, arrowtail=diamond, dir=both]; - // Department ASSOC Course - c104:p -> c106:p [taillabel="1..*", label="", headlabel="1..*", fontname="Helvetica", fontcolor="black", fontsize=10.0, color="black", arrowhead=none]; - // Department ASSOC Instructor - c104:p -> c107:p [taillabel="0..*", label="", headlabel="0..1 chairperson", fontname="Helvetica", fontcolor="black", fontsize=10.0, color="black", arrowhead=none]; - // Department HAS Instructor - c104:p -> c107:p [taillabel="1..*", label="AssignedTo", headlabel="1..*", fontname="Helvetica", fontcolor="black", fontsize=10.0, color="black", arrowhead=none, arrowtail=ediamond, dir=both]; - // Student ASSOC Course - c105:p -> c106:p [taillabel="*", label="Attends", headlabel="*", fontname="Helvetica", fontcolor="black", fontsize=10.0, color="black", arrowhead=none]; - // Instructor ASSOC Course - c107:p -> c106:p [taillabel="1..*", label="Teaches", headlabel="*", fontname="Helvetica", fontcolor="black", fontsize=10.0, color="black", arrowhead=none]; +graph [fontnames="svg"] +edge [fontname="Helvetica",fontsize=10,labelfontname="Helvetica",labelfontsize=10,color="black"]; +node [fontname="Helvetica",fontcolor="black",fontsize=10,shape=plaintext,margin=0,width=0,height=0]; +nodesep=0.25; +ranksep=0.5; +// School +c103 [label=<
    School
    name : Name
    address : String
    phone : Number
    addStudent()
    removeStudent()
    getStudent()
    getAllStudents()
    addDepartment()
    removeDepartment()
    getDepartment()
    getAllDepartments()
    >]; +// Department +c104 [label=<
    Department
    name : Name
    addInstructor()
    removeInstructor()
    getInstructor()
    getAllInstructors()
    >]; +// Student +c105 [label=<
    Student
    name : Name
    studentID : Number
    >]; +// Course +c106 [label=<
    Course
    name : Name
    courseID : Number
    >]; +// Instructor +c107 [label=<
    Instructor
    name : Name
    >]; +// School has Student +c103 -> c105 [arrowhead=none,arrowtail=ediamond,dir=back,weight=4,taillabel="1..*", label="Member", headlabel="*"]; +// School composed Department +c103 -> c104 [arrowhead=none,arrowtail=diamond,dir=back,weight=6,taillabel="1..*", label="Has", headlabel="1..*"]; +// Department assoc Course +c104 -> c106 [arrowhead=none,weight=2,taillabel="1..*", headlabel="1..*"]; +// Department assoc Instructor +c104 -> c107 [arrowhead=none,weight=2,taillabel="0..*", headlabel="0..1 chairperson"]; +// Department has Instructor +c104 -> c107 [arrowhead=none,arrowtail=ediamond,dir=back,weight=4,taillabel="1..*", label="AssignedTo", headlabel="1..*"]; +// Student assoc Course +c105 -> c106 [arrowhead=none,weight=2,taillabel="*", label="Attends", headlabel="*"]; +// Instructor assoc Course +c107 -> c106 [arrowhead=none,weight=2,taillabel="1..*", label="Teaches", headlabel="*"]; } diff --git a/testdata/dot-ref/strip.dot b/testdata/dot-ref/strip.dot index 6c7ca58..a40df9c 100644 --- a/testdata/dot-ref/strip.dot +++ b/testdata/dot-ref/strip.dot @@ -5,13 +5,14 @@ # digraph G { - edge [fontname="Helvetica",fontsize=10,labelfontname="Helvetica",labelfontsize=10]; - node [fontname="Helvetica",fontsize=10,shape=plaintext]; - nodesep=0.25; - ranksep=0.5; - // Java5 - c109 [label=<
    Java5
    ~ state : Java5.States
    + specifiedPackages : Set<String>
    + printAll(args : String[])
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; - // Java5.States - c110 [label=<
    «enumeration»
    States
    start
    dash
    colon
    space
    open
    w
    close
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; +graph [fontnames="svg"] +edge [fontname="Helvetica",fontsize=10,labelfontname="Helvetica",labelfontsize=10,color="black"]; +node [fontname="Helvetica",fontcolor="black",fontsize=10,shape=plaintext,margin=0,width=0,height=0]; +nodesep=0.25; +ranksep=0.5; +// Java5 +c109 [label=<
    Java5
    ~ state : Java5.States
    + specifiedPackages : Set<String>
    + printAll(args : String[])
    >]; +// Java5.States +c110 [label=<
    «enumeration»
    States
    start
    dash
    colon
    space
    open
    w
    close
    >]; } diff --git a/testdata/dot-ref/vis.dot b/testdata/dot-ref/vis.dot index b44fd58..db7ad2b 100644 --- a/testdata/dot-ref/vis.dot +++ b/testdata/dot-ref/vis.dot @@ -5,11 +5,12 @@ # digraph G { - edge [fontname="Helvetica",fontsize=10,labelfontname="Helvetica",labelfontsize=10]; - node [fontname="Helvetica",fontsize=10,shape=plaintext]; - nodesep=0.25; - ranksep=0.5; - // Toolbar - c120 [label=<
    Toolbar
    # currentSelection : Tool
    # toolCount : Integer
    + pickItem(i : Integer)
    + addTool(t : Tool)
    + removeTool(i : Integer)
    + getTool() : Tool
    # checkOrphans()
    - compact()
    >, URL="null", fontname="Helvetica", fontcolor="black", fontsize=10.0]; +graph [fontnames="svg"] +edge [fontname="Helvetica",fontsize=10,labelfontname="Helvetica",labelfontsize=10,color="black"]; +node [fontname="Helvetica",fontcolor="black",fontsize=10,shape=plaintext,margin=0,width=0,height=0]; +nodesep=0.25; +ranksep=0.5; +// Toolbar +c120 [label=<
    Toolbar
    # currentSelection : Tool
    # toolCount : Integer
    + pickItem(i : Integer)
    + addTool(t : Tool)
    + removeTool(i : Integer)
    + getTool() : Tool
    # checkOrphans()
    - compact()
    >]; } diff --git a/testdata/java/active.java b/testdata/java/active.java new file mode 100644 index 0000000..5b63708 --- /dev/null +++ b/testdata/java/active.java @@ -0,0 +1,13 @@ +/** + * Active classes + * + * @opt operations + * @opt shape activeclass + * @hidden + */ +class UMLOptions {} + +class Active { + protected int hidden; + public void run() {}; +} diff --git a/testdata/java/extends.java b/testdata/java/extends.java index 6cd4188..d9bd341 100644 --- a/testdata/java/extends.java +++ b/testdata/java/extends.java @@ -1,3 +1,2 @@ - class Base {} -class Test2 {} +class Test2 {}