mirror of https://github.com/dspinellis/UMLGraph
reformat classes
This commit is contained in:
parent
d80597d547
commit
c8f805bdef
File diff suppressed because it is too large
Load Diff
|
|
@ -23,8 +23,9 @@ import java.util.HashMap;
|
|||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Class's dot-compatible alias name (for fully qualified class names)
|
||||
* and printed information
|
||||
* Class's dot-compatible alias name (for fully qualified class names) and
|
||||
* printed information
|
||||
*
|
||||
* @version $Revision$
|
||||
* @author <a href="http://www.spinellis.gr">Diomidis Spinellis</a>
|
||||
*/
|
||||
|
|
@ -37,36 +38,34 @@ class ClassInfo {
|
|||
/** True if the class class node is hidden */
|
||||
boolean hidden;
|
||||
/**
|
||||
* The list of classes that share a relation with this one. Contains
|
||||
* all the classes linked with a bi-directional relation , and the ones
|
||||
* referred by a directed relation
|
||||
* The list of classes that share a relation with this one. Contains all the
|
||||
* classes linked with a bi-directional relation , and the ones referred by a
|
||||
* directed relation
|
||||
*/
|
||||
Map<String, RelationPattern> relatedClasses = new HashMap<String, RelationPattern>();
|
||||
|
||||
ClassInfo(boolean h) {
|
||||
hidden = h;
|
||||
name = "c" + classNumber;
|
||||
classNumber++;
|
||||
hidden = h;
|
||||
name = "c" + classNumber;
|
||||
classNumber++;
|
||||
}
|
||||
|
||||
public void addRelation(String dest, RelationType rt, RelationDirection d) {
|
||||
RelationPattern ri = relatedClasses.get(dest);
|
||||
if(ri == null) {
|
||||
ri = new RelationPattern(RelationDirection.NONE);
|
||||
relatedClasses.put(dest, ri);
|
||||
}
|
||||
ri.addRelation(rt, d);
|
||||
RelationPattern ri = relatedClasses.get(dest);
|
||||
if (ri == null) {
|
||||
ri = new RelationPattern(RelationDirection.NONE);
|
||||
relatedClasses.put(dest, ri);
|
||||
}
|
||||
ri.addRelation(rt, d);
|
||||
}
|
||||
|
||||
public RelationPattern getRelation(String dest) {
|
||||
return relatedClasses.get(dest);
|
||||
return relatedClasses.get(dest);
|
||||
}
|
||||
|
||||
/** Start numbering from zero. */
|
||||
public static void reset() {
|
||||
classNumber = 0;
|
||||
classNumber = 0;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -20,9 +20,9 @@ package org.umlgraph.doclet;
|
|||
import com.sun.javadoc.ClassDoc;
|
||||
|
||||
/**
|
||||
* A ClassMatcher is used to check if a class definition matches a
|
||||
* specific condition. The nature of the condition is dependent on
|
||||
* the kind of matcher
|
||||
* A ClassMatcher is used to check if a class definition matches a specific
|
||||
* condition. The nature of the condition is dependent on the kind of matcher
|
||||
*
|
||||
* @author wolf
|
||||
*/
|
||||
public interface ClassMatcher {
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ import com.sun.javadoc.RootDoc;
|
|||
* This class needs to perform quite a bit of computations in order to gather
|
||||
* the network of class releationships, so you are allowed to reuse it should
|
||||
* you
|
||||
*
|
||||
* @author wolf
|
||||
*
|
||||
* @depend - - - DevNullWriter
|
||||
|
|
@ -54,25 +55,26 @@ public class ContextMatcher implements ClassMatcher {
|
|||
|
||||
/**
|
||||
* Builds the context matcher
|
||||
* @param root The root doc returned by JavaDoc
|
||||
* @param pattern The pattern that will match the "center" of this
|
||||
* context
|
||||
* @param keepParentHide If true, parent option hide patterns will be
|
||||
* preserved, so that classes hidden by the options won't
|
||||
* be shown in the context
|
||||
*
|
||||
* @param root The root doc returned by JavaDoc
|
||||
* @param pattern The pattern that will match the "center" of this
|
||||
* context
|
||||
* @param keepParentHide If true, parent option hide patterns will be preserved,
|
||||
* so that classes hidden by the options won't be shown in
|
||||
* the context
|
||||
* @throws IOException
|
||||
*/
|
||||
public ContextMatcher(RootDoc root, Pattern pattern, Options options, boolean keepParentHide) throws IOException {
|
||||
this.pattern = pattern;
|
||||
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" });
|
||||
this.cg = new ClassGraphHack(root, opt);
|
||||
this.pattern = pattern;
|
||||
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" });
|
||||
this.cg = new ClassGraphHack(root, opt);
|
||||
|
||||
setContextCenter(pattern);
|
||||
setContextCenter(pattern);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -80,116 +82,119 @@ public class ContextMatcher implements ClassMatcher {
|
|||
* <p>
|
||||
* This can be used to speed up subsequent matching with the same global
|
||||
* options, since the class network informations will be reused.
|
||||
*
|
||||
* @param pattern
|
||||
*/
|
||||
public void setContextCenter(Pattern pattern) {
|
||||
// build up the classgraph printing the relations for all of the
|
||||
// classes that make up the "center" of this context
|
||||
this.pattern = pattern;
|
||||
matched = new ArrayList<ClassDoc>();
|
||||
for (ClassDoc cd : root.classes()) {
|
||||
if (pattern.matcher(cd.toString()).matches()) {
|
||||
matched.add(cd);
|
||||
addToGraph(cd);
|
||||
}
|
||||
}
|
||||
// build up the classgraph printing the relations for all of the
|
||||
// classes that make up the "center" of this context
|
||||
this.pattern = pattern;
|
||||
matched = new ArrayList<ClassDoc>();
|
||||
for (ClassDoc cd : root.classes()) {
|
||||
if (pattern.matcher(cd.toString()).matches()) {
|
||||
matched.add(cd);
|
||||
addToGraph(cd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the specified class to the internal class graph along with its
|
||||
* relations and dependencies, eventually inferring them, according to the
|
||||
* Options specified for this matcher
|
||||
* Adds the specified class to the internal class graph along with its 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
|
||||
if (visited.contains(cd.toString()))
|
||||
return;
|
||||
// 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
|
||||
if (visited.contains(cd.toString()))
|
||||
return;
|
||||
|
||||
visited.add(cd.toString());
|
||||
cg.printClass(cd, false);
|
||||
cg.printRelations(cd);
|
||||
if (opt.inferRelationships)
|
||||
cg.printInferredRelations(cd);
|
||||
if (opt.inferDependencies)
|
||||
cg.printInferredDependencies(cd);
|
||||
visited.add(cd.toString());
|
||||
cg.printClass(cd, false);
|
||||
cg.printRelations(cd);
|
||||
if (opt.inferRelationships)
|
||||
cg.printInferredRelations(cd);
|
||||
if (opt.inferDependencies)
|
||||
cg.printInferredDependencies(cd);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.umlgraph.doclet.ClassMatcher#matches(com.sun.javadoc.ClassDoc)
|
||||
*/
|
||||
public boolean matches(ClassDoc cd) {
|
||||
if (keepParentHide && opt.matchesHideExpression(cd.toString()))
|
||||
return false;
|
||||
if (keepParentHide && opt.matchesHideExpression(cd.toString()))
|
||||
return false;
|
||||
|
||||
// if the class is matched, it's in by default.
|
||||
if (matched.contains(cd))
|
||||
return true;
|
||||
// if the class is matched, it's in by default.
|
||||
if (matched.contains(cd))
|
||||
return true;
|
||||
|
||||
// otherwise, add the class to the graph and see if it's associated
|
||||
// with any of the matched classes using the classgraph hack
|
||||
addToGraph(cd);
|
||||
return matches(cd.toString());
|
||||
// otherwise, add the class to the graph and see if it's associated
|
||||
// with any of the matched classes using the classgraph hack
|
||||
addToGraph(cd);
|
||||
return matches(cd.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.umlgraph.doclet.ClassMatcher#matches(java.lang.String)
|
||||
*/
|
||||
public boolean matches(String name) {
|
||||
if (pattern.matcher(name).matches())
|
||||
return true;
|
||||
if (pattern.matcher(name).matches())
|
||||
return true;
|
||||
|
||||
for (ClassDoc mcd : matched) {
|
||||
RelationPattern rp = cg.getClassInfo(mcd, true).getRelation(name);
|
||||
if (rp != null && opt.contextRelationPattern.matchesOne(rp))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
for (ClassDoc mcd : matched) {
|
||||
RelationPattern rp = cg.getClassInfo(mcd, true).getRelation(name);
|
||||
if (rp != null && opt.contextRelationPattern.matchesOne(rp))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* A quick hack to compute class dependencies reusing ClassGraph but
|
||||
* without generating output. Will be removed once the ClassGraph class
|
||||
* will be split into two classes for graph computation and output
|
||||
* generation.
|
||||
* A quick hack to compute class dependencies reusing ClassGraph but without
|
||||
* generating output. Will be removed once the ClassGraph class will be split
|
||||
* into two classes for graph computation and output generation.
|
||||
*
|
||||
* @author wolf
|
||||
*
|
||||
*/
|
||||
private static class ClassGraphHack extends ClassGraph {
|
||||
|
||||
public ClassGraphHack(RootDoc root, OptionProvider optionProvider) throws IOException {
|
||||
super(root, optionProvider, null);
|
||||
prologue();
|
||||
}
|
||||
public ClassGraphHack(RootDoc root, OptionProvider optionProvider) throws IOException {
|
||||
super(root, optionProvider, null);
|
||||
prologue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void prologue() throws IOException {
|
||||
w = new PrintWriter(new DevNullWriter());
|
||||
}
|
||||
@Override
|
||||
public void prologue() throws IOException {
|
||||
w = new PrintWriter(new DevNullWriter());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple dev/null imitation
|
||||
*
|
||||
* @author wolf
|
||||
*/
|
||||
private static class DevNullWriter extends Writer {
|
||||
|
||||
@Override
|
||||
public void write(char[] cbuf, int off, int len) throws IOException {
|
||||
// nothing to do
|
||||
}
|
||||
@Override
|
||||
public void write(char[] cbuf, int off, int len) throws IOException {
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush() throws IOException {
|
||||
// nothing to do
|
||||
}
|
||||
@Override
|
||||
public void flush() throws IOException {
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
// nothing to do
|
||||
}
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import com.sun.javadoc.RootDoc;
|
|||
* single {@linkplain ContextMatcher}, but provides some extra configuration
|
||||
* such as context highlighting and output path configuration (and it is
|
||||
* specified in code rather than in javadoc comments).
|
||||
*
|
||||
* @author wolf
|
||||
*
|
||||
*/
|
||||
|
|
@ -28,93 +29,89 @@ public class ContextView implements OptionProvider {
|
|||
private Options packageOptions;
|
||||
private static final String[] HIDE_OPTIONS = new String[] { "hide" };
|
||||
|
||||
public ContextView(String outputFolder, ClassDoc cd, RootDoc root, Options parent)
|
||||
throws IOException {
|
||||
this.cd = cd;
|
||||
String outputPath = cd.containingPackage().name().replace('.', '/') + "/" + cd.name()
|
||||
+ ".dot";
|
||||
public ContextView(String outputFolder, ClassDoc cd, RootDoc root, Options parent) throws IOException {
|
||||
this.cd = cd;
|
||||
String outputPath = cd.containingPackage().name().replace('.', '/') + "/" + cd.name() + ".dot";
|
||||
|
||||
// setup options statically, so that we won't need to change them so
|
||||
// often
|
||||
this.globalOptions = parent.getGlobalOptions();
|
||||
// setup options statically, so that we won't need to change them so
|
||||
// often
|
||||
this.globalOptions = parent.getGlobalOptions();
|
||||
|
||||
this.packageOptions = parent.getGlobalOptions();
|
||||
this.packageOptions.showQualified = false;
|
||||
this.packageOptions = parent.getGlobalOptions();
|
||||
this.packageOptions.showQualified = false;
|
||||
|
||||
this.myGlobalOptions = parent.getGlobalOptions();
|
||||
this.myGlobalOptions.setOption(new String[] { "output", outputPath });
|
||||
this.myGlobalOptions.setOption(HIDE_OPTIONS);
|
||||
this.myGlobalOptions = parent.getGlobalOptions();
|
||||
this.myGlobalOptions.setOption(new String[] { "output", outputPath });
|
||||
this.myGlobalOptions.setOption(HIDE_OPTIONS);
|
||||
|
||||
this.hideOptions = parent.getGlobalOptions();
|
||||
this.hideOptions.setOption(HIDE_OPTIONS);
|
||||
this.hideOptions = parent.getGlobalOptions();
|
||||
this.hideOptions.setOption(HIDE_OPTIONS);
|
||||
|
||||
this.centerOptions = parent.getGlobalOptions();
|
||||
this.centerOptions.nodeFillColor = "lemonChiffon";
|
||||
this.centerOptions.showQualified = false;
|
||||
this.centerOptions = parent.getGlobalOptions();
|
||||
this.centerOptions.nodeFillColor = "lemonChiffon";
|
||||
this.centerOptions.showQualified = false;
|
||||
|
||||
this.matcher = new ContextMatcher(root, Pattern.compile(Pattern.quote(cd.toString())),
|
||||
myGlobalOptions, true);
|
||||
this.matcher = new ContextMatcher(root, Pattern.compile(Pattern.quote(cd.toString())), myGlobalOptions, true);
|
||||
|
||||
}
|
||||
|
||||
public void setContextCenter(ClassDoc contextCenter) {
|
||||
this.cd = contextCenter;
|
||||
String outputPath = cd.containingPackage().name().replace('.', '/') + "/" + cd.name()
|
||||
+ ".dot";
|
||||
this.myGlobalOptions.setOption(new String[] { "output", outputPath });
|
||||
matcher.setContextCenter(Pattern.compile(Pattern.quote(cd.toString())));
|
||||
this.cd = contextCenter;
|
||||
String outputPath = cd.containingPackage().name().replace('.', '/') + "/" + cd.name() + ".dot";
|
||||
this.myGlobalOptions.setOption(new String[] { "output", outputPath });
|
||||
matcher.setContextCenter(Pattern.compile(Pattern.quote(cd.toString())));
|
||||
}
|
||||
|
||||
public String getDisplayName() {
|
||||
return "Context view for class " + cd;
|
||||
return "Context view for class " + cd;
|
||||
}
|
||||
|
||||
public Options getGlobalOptions() {
|
||||
return myGlobalOptions;
|
||||
return myGlobalOptions;
|
||||
}
|
||||
|
||||
public Options getOptionsFor(ClassDoc cd) {
|
||||
Options opt;
|
||||
if (globalOptions.matchesHideExpression(cd.qualifiedName())
|
||||
|| !(matcher.matches(cd) || globalOptions.matchesIncludeExpression(cd.qualifiedName()))) {
|
||||
opt = hideOptions;
|
||||
} else if (cd.equals(this.cd)) {
|
||||
opt = centerOptions;
|
||||
} else if(cd.containingPackage().equals(this.cd.containingPackage())){
|
||||
opt = packageOptions;
|
||||
} else {
|
||||
opt = globalOptions;
|
||||
}
|
||||
Options optionClone = (Options) opt.clone();
|
||||
overrideForClass(optionClone, cd);
|
||||
return optionClone;
|
||||
Options opt;
|
||||
if (globalOptions.matchesHideExpression(cd.qualifiedName())
|
||||
|| !(matcher.matches(cd) || globalOptions.matchesIncludeExpression(cd.qualifiedName()))) {
|
||||
opt = hideOptions;
|
||||
} else if (cd.equals(this.cd)) {
|
||||
opt = centerOptions;
|
||||
} else if (cd.containingPackage().equals(this.cd.containingPackage())) {
|
||||
opt = packageOptions;
|
||||
} else {
|
||||
opt = globalOptions;
|
||||
}
|
||||
Options optionClone = (Options) opt.clone();
|
||||
overrideForClass(optionClone, cd);
|
||||
return optionClone;
|
||||
}
|
||||
|
||||
public Options getOptionsFor(String name) {
|
||||
Options opt;
|
||||
if (!matcher.matches(name))
|
||||
opt = hideOptions;
|
||||
else if (name.equals(cd.name()))
|
||||
opt = centerOptions;
|
||||
else
|
||||
opt = globalOptions;
|
||||
Options optionClone = (Options) opt.clone();
|
||||
overrideForClass(optionClone, name);
|
||||
return optionClone;
|
||||
Options opt;
|
||||
if (!matcher.matches(name))
|
||||
opt = hideOptions;
|
||||
else if (name.equals(cd.name()))
|
||||
opt = centerOptions;
|
||||
else
|
||||
opt = globalOptions;
|
||||
Options optionClone = (Options) opt.clone();
|
||||
overrideForClass(optionClone, name);
|
||||
return optionClone;
|
||||
}
|
||||
|
||||
public void overrideForClass(Options opt, ClassDoc cd) {
|
||||
opt.setOptions(cd);
|
||||
if (opt.matchesHideExpression(cd.qualifiedName())
|
||||
|| !(matcher.matches(cd) || opt.matchesIncludeExpression(cd.qualifiedName())))
|
||||
opt.setOption(HIDE_OPTIONS);
|
||||
if (cd.equals(this.cd))
|
||||
opt.nodeFillColor = "lemonChiffon";
|
||||
opt.setOptions(cd);
|
||||
if (opt.matchesHideExpression(cd.qualifiedName())
|
||||
|| !(matcher.matches(cd) || opt.matchesIncludeExpression(cd.qualifiedName())))
|
||||
opt.setOption(HIDE_OPTIONS);
|
||||
if (cd.equals(this.cd))
|
||||
opt.nodeFillColor = "lemonChiffon";
|
||||
}
|
||||
|
||||
public void overrideForClass(Options opt, String className) {
|
||||
if (!(matcher.matches(className) || opt.matchesIncludeExpression(className)))
|
||||
opt.setOption(HIDE_OPTIONS);
|
||||
if (!(matcher.matches(className) || opt.matchesIncludeExpression(className)))
|
||||
opt.setOption(HIDE_OPTIONS);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,12 +33,12 @@ public enum 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"?
|
||||
}
|
||||
// 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"?
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -49,53 +49,53 @@ public enum Font {
|
|||
* @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("<font");
|
||||
if (face != null)
|
||||
buf.append(" face=\"").append(face).append('"');
|
||||
if (size > 0)
|
||||
buf.append(" point-size=\"").append(size).append('"');
|
||||
buf.append('>');
|
||||
}
|
||||
if (italic)
|
||||
buf.append("<i>");
|
||||
buf.append(text);
|
||||
if (italic)
|
||||
buf.append("</i>");
|
||||
if (face != null || size > 0)
|
||||
buf.append("</font>");
|
||||
return buf.toString();
|
||||
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("<font");
|
||||
if (face != null)
|
||||
buf.append(" face=\"").append(face).append('"');
|
||||
if (size > 0)
|
||||
buf.append(" point-size=\"").append(size).append('"');
|
||||
buf.append('>');
|
||||
}
|
||||
if (italic)
|
||||
buf.append("<i>");
|
||||
buf.append(text);
|
||||
if (italic)
|
||||
buf.append("</i>");
|
||||
if (face != null || size > 0)
|
||||
buf.append("</font>");
|
||||
return buf.toString();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@ import com.sun.javadoc.ClassDoc;
|
|||
import com.sun.javadoc.RootDoc;
|
||||
|
||||
/**
|
||||
* Matches every class that implements (directly or indirectly) an
|
||||
* interfaces matched by regular expression provided.
|
||||
* Matches every class that implements (directly or indirectly) an interfaces
|
||||
* matched by regular expression provided.
|
||||
*/
|
||||
public class InterfaceMatcher implements ClassMatcher {
|
||||
|
||||
|
|
@ -15,28 +15,28 @@ public class InterfaceMatcher implements ClassMatcher {
|
|||
protected Pattern pattern;
|
||||
|
||||
public InterfaceMatcher(RootDoc root, Pattern pattern) {
|
||||
this.root = root;
|
||||
this.pattern = pattern;
|
||||
this.root = root;
|
||||
this.pattern = pattern;
|
||||
}
|
||||
|
||||
public boolean matches(ClassDoc cd) {
|
||||
// if it's the interface we're looking for, match
|
||||
if(cd.isInterface() && pattern.matcher(cd.toString()).matches())
|
||||
return true;
|
||||
// if it's the interface we're looking for, match
|
||||
if (cd.isInterface() && pattern.matcher(cd.toString()).matches())
|
||||
return true;
|
||||
|
||||
// for each interface, recurse, since classes and interfaces
|
||||
// are treated the same in the doclet API
|
||||
for (ClassDoc iface : cd.interfaces())
|
||||
if(matches(iface))
|
||||
return true;
|
||||
// for each interface, recurse, since classes and interfaces
|
||||
// are treated the same in the doclet API
|
||||
for (ClassDoc iface : cd.interfaces())
|
||||
if (matches(iface))
|
||||
return true;
|
||||
|
||||
// recurse on supeclass, if available
|
||||
return cd.superclass() == null ? false : matches(cd.superclass());
|
||||
// recurse on supeclass, if available
|
||||
return cd.superclass() == null ? false : matches(cd.superclass());
|
||||
}
|
||||
|
||||
public boolean matches(String name) {
|
||||
ClassDoc cd = root.classNamed(name);
|
||||
return cd == null ? false : matches(cd);
|
||||
ClassDoc cd = root.classNamed(name);
|
||||
return cd == null ? false : matches(cd);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,8 +20,8 @@ package org.umlgraph.doclet;
|
|||
import com.sun.javadoc.ClassDoc;
|
||||
|
||||
/**
|
||||
* A factory class that builds Options object for general use or for a
|
||||
* specific class
|
||||
* A factory class that builds Options object for general use or for a specific
|
||||
* class
|
||||
*/
|
||||
public interface OptionProvider {
|
||||
/**
|
||||
|
|
@ -51,7 +51,8 @@ public interface OptionProvider {
|
|||
|
||||
/**
|
||||
* Returns user displayable name for this option provider.
|
||||
* <p>Will be used to provide progress feedback on the console
|
||||
* <p>
|
||||
* Will be used to provide progress feedback on the console
|
||||
*/
|
||||
public String getDisplayName();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ import com.sun.javadoc.Tag;
|
|||
|
||||
/**
|
||||
* Represent the program options
|
||||
*
|
||||
* @version $Revision$
|
||||
* @author <a href="http://www.spinellis.gr">Diomidis Spinellis</a>
|
||||
*/
|
||||
|
|
@ -97,14 +98,13 @@ public class Options implements Cloneable, OptionProvider {
|
|||
double rankSep = 0.5;
|
||||
public String outputDirectory = null;
|
||||
/*
|
||||
* Numeric values are preferable to symbolic here.
|
||||
* Symbolic reportedly fail on MacOSX, and also are
|
||||
* more difficult to verify with XML tools.
|
||||
* Numeric values are preferable to symbolic here. Symbolic reportedly fail on
|
||||
* MacOSX, and also are more difficult to verify with XML tools.
|
||||
*/
|
||||
/** Guillemot left (open) */
|
||||
String guilOpen = "«"; // « \u00ab
|
||||
String guilOpen = "«"; // « \u00ab
|
||||
/** Guillemot right (close) */
|
||||
String guilClose = "»"; // » \u00bb
|
||||
String guilClose = "»"; // » \u00bb
|
||||
boolean inferRelationships = false;
|
||||
boolean inferDependencies = false;
|
||||
boolean collapsibleDiagrams = false;
|
||||
|
|
@ -119,8 +119,10 @@ public class Options implements Cloneable, OptionProvider {
|
|||
// internal option, used by UMLDoc to generate relative links between classes
|
||||
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<T extends java.io.Serializable>
|
||||
// and avoid problems with packages in the template declaration making UmlGraph
|
||||
// hide
|
||||
// classes outside of them (for example, class gr.spinellis.Foo<T extends
|
||||
// java.io.Serializable>
|
||||
// would have been hidden by the hide pattern "java.*"
|
||||
// TODO: consider making this standard behaviour
|
||||
boolean strictMatching = false;
|
||||
|
|
@ -130,127 +132,98 @@ public class Options implements Cloneable, OptionProvider {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Object clone() {
|
||||
Options clone = null;
|
||||
try {
|
||||
clone = (Options) super.clone();
|
||||
} catch (CloneNotSupportedException e) {
|
||||
throw new RuntimeException("Cannot clone?!?", e); // Should not happen
|
||||
}
|
||||
// deep clone the hide and collection patterns
|
||||
clone.hidePatterns = new ArrayList<Pattern>(hidePatterns);
|
||||
clone.includePatterns = new ArrayList<Pattern>(includePatterns);
|
||||
clone.collPackages= new ArrayList<Pattern>(collPackages);
|
||||
clone.apiDocMap = new HashMap<Pattern, String>(apiDocMap);
|
||||
return clone;
|
||||
public Object clone() {
|
||||
Options clone = null;
|
||||
try {
|
||||
clone = (Options) super.clone();
|
||||
} catch (CloneNotSupportedException e) {
|
||||
throw new RuntimeException("Cannot clone?!?", e); // Should not happen
|
||||
}
|
||||
// deep clone the hide and collection patterns
|
||||
clone.hidePatterns = new ArrayList<Pattern>(hidePatterns);
|
||||
clone.includePatterns = new ArrayList<Pattern>(includePatterns);
|
||||
clone.collPackages = new ArrayList<Pattern>(collPackages);
|
||||
clone.apiDocMap = new HashMap<Pattern, String>(apiDocMap);
|
||||
return clone;
|
||||
}
|
||||
|
||||
/** Most complete output */
|
||||
public void setAll() {
|
||||
showAttributes = true;
|
||||
showEnumerations = true;
|
||||
showEnumConstants = true;
|
||||
showOperations = true;
|
||||
showConstructors = true;
|
||||
showVisibility = true;
|
||||
showType = true;
|
||||
showAttributes = true;
|
||||
showEnumerations = true;
|
||||
showEnumConstants = true;
|
||||
showOperations = true;
|
||||
showConstructors = true;
|
||||
showVisibility = true;
|
||||
showType = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Match strings, ignoring leading <tt>-</tt>, <tt>-!</tt>, and <tt>!</tt>.
|
||||
*
|
||||
* @param given Given string
|
||||
* @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);
|
||||
return matchOption(given, expect, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Match strings, ignoring leading <tt>-</tt>, <tt>-!</tt>, and <tt>!</tt>.
|
||||
*
|
||||
* @param given Given string
|
||||
* @param expect Expected string
|
||||
* @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);
|
||||
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.
|
||||
* The return value includes the actual option.
|
||||
* Will return 0 if the option is not supported.
|
||||
* Return the number of arguments associated with the specified option. The
|
||||
* return value includes the actual option. Will return 0 if the option is not
|
||||
* supported.
|
||||
*/
|
||||
public static int optionLength(String option) {
|
||||
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))
|
||||
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(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(matchOption(option, "contextPattern") ||
|
||||
matchOption(option, "linkoffline"))
|
||||
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 (matchOption(option, "contextPattern") || matchOption(option, "linkoffline"))
|
||||
return 3;
|
||||
else
|
||||
return 0;
|
||||
|
|
@ -258,382 +231,390 @@ public class Options implements Cloneable, OptionProvider {
|
|||
|
||||
/** Set the options based on a single option and its arguments */
|
||||
void setOption(String[] opt) {
|
||||
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 (!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(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(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();
|
||||
} else if(matchOption(opt[0], "include", true)) {
|
||||
if (positive) {
|
||||
try {
|
||||
includePatterns.add(Pattern.compile(opt[1]));
|
||||
} catch (PatternSyntaxException e) {
|
||||
System.err.println("Skipping invalid pattern " + opt[1]);
|
||||
}
|
||||
} 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
|
||||
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 (matchOption(opt[0], "linkoffline")) {
|
||||
addApiDocRootsOffline(opt[1], opt[2]);
|
||||
} else if(matchOption(opt[0], "contextPattern")) {
|
||||
RelationDirection d; RelationType rt;
|
||||
try {
|
||||
d = RelationDirection.valueOf(opt[2].toUpperCase());
|
||||
if(opt[1].equalsIgnoreCase("all")) {
|
||||
contextRelationPattern = new RelationPattern(d);
|
||||
} else {
|
||||
rt = RelationType.valueOf(opt[1].toUpperCase());
|
||||
contextRelationPattern.addRelation(rt, d);
|
||||
}
|
||||
} catch(IllegalArgumentException e) {
|
||||
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 (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();
|
||||
} else if (matchOption(opt[0], "include", true)) {
|
||||
if (positive) {
|
||||
try {
|
||||
includePatterns.add(Pattern.compile(opt[1]));
|
||||
} catch (PatternSyntaxException e) {
|
||||
System.err.println("Skipping invalid pattern " + opt[1]);
|
||||
}
|
||||
} 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
|
||||
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 (matchOption(opt[0], "linkoffline")) {
|
||||
addApiDocRootsOffline(opt[1], opt[2]);
|
||||
} else if (matchOption(opt[0], "contextPattern")) {
|
||||
RelationDirection d;
|
||||
RelationType rt;
|
||||
try {
|
||||
d = RelationDirection.valueOf(opt[2].toUpperCase());
|
||||
if (opt[1].equalsIgnoreCase("all")) {
|
||||
contextRelationPattern = new RelationPattern(d);
|
||||
} else {
|
||||
rt = RelationType.valueOf(opt[1].toUpperCase());
|
||||
contextRelationPattern.addRelation(rt, d);
|
||||
}
|
||||
} catch (IllegalArgumentException e) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
} else if (matchOption(opt[0], "nodesep", true)) {
|
||||
try {
|
||||
nodeSep = positive ? Double.parseDouble(opt[1]) : 0.25;
|
||||
} catch (NumberFormatException e) {
|
||||
System.err.println("Skipping invalid nodesep " + opt[1]);
|
||||
}
|
||||
} else if (matchOption(opt[0], "ranksep", true)) {
|
||||
try {
|
||||
rankSep = positive ? Double.parseDouble(opt[1]) : 0.5;
|
||||
} catch (NumberFormatException e) {
|
||||
System.err.println("Skipping invalid ranksep " + opt[1]);
|
||||
}
|
||||
} else if (matchOption(opt[0], "dotexecutable")) {
|
||||
dotExecutable = opt[1];
|
||||
} else
|
||||
; // Do nothing, javadoc will handle the option or complain, if needed.
|
||||
} else if (matchOption(opt[0], "nodesep", true)) {
|
||||
try {
|
||||
nodeSep = positive ? Double.parseDouble(opt[1]) : 0.25;
|
||||
} catch (NumberFormatException e) {
|
||||
System.err.println("Skipping invalid nodesep " + opt[1]);
|
||||
}
|
||||
} else if (matchOption(opt[0], "ranksep", true)) {
|
||||
try {
|
||||
rankSep = positive ? Double.parseDouble(opt[1]) : 0.5;
|
||||
} catch (NumberFormatException e) {
|
||||
System.err.println("Skipping invalid ranksep " + opt[1]);
|
||||
}
|
||||
} else if (matchOption(opt[0], "dotexecutable")) {
|
||||
dotExecutable = opt[1];
|
||||
} else
|
||||
; // Do nothing, javadoc will handle the option or complain, if needed.
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds api doc roots from a link. The folder reffered by the link should contain a package-list
|
||||
* file that will be parsed in order to add api doc roots to this configuration
|
||||
* Adds api doc roots from a link. The folder reffered by the link should
|
||||
* contain a package-list file that will be parsed in order to add api doc roots
|
||||
* to this configuration
|
||||
*
|
||||
* @param packageListUrl
|
||||
*/
|
||||
private void addApiDocRoots(String packageListUrl) {
|
||||
BufferedReader br = null;
|
||||
packageListUrl = fixApiDocRoot(packageListUrl);
|
||||
try {
|
||||
URL url = new URL(packageListUrl + "/package-list");
|
||||
br = new BufferedReader(new InputStreamReader(url.openStream()));
|
||||
String line;
|
||||
while((line = br.readLine()) != null) {
|
||||
line = line + ".";
|
||||
Pattern pattern = Pattern.compile(line.replace(".", "\\.") + "[^\\.]*");
|
||||
apiDocMap.put(pattern, packageListUrl);
|
||||
}
|
||||
} catch(IOException e) {
|
||||
System.err.println("Errors happened while accessing the package-list file at "
|
||||
+ packageListUrl);
|
||||
} finally {
|
||||
if(br != null)
|
||||
try {
|
||||
br.close();
|
||||
} catch (IOException e) {}
|
||||
}
|
||||
BufferedReader br = null;
|
||||
packageListUrl = fixApiDocRoot(packageListUrl);
|
||||
try {
|
||||
URL url = new URL(packageListUrl + "/package-list");
|
||||
br = new BufferedReader(new InputStreamReader(url.openStream()));
|
||||
String line;
|
||||
while ((line = br.readLine()) != null) {
|
||||
line = line + ".";
|
||||
Pattern pattern = Pattern.compile(line.replace(".", "\\.") + "[^\\.]*");
|
||||
apiDocMap.put(pattern, packageListUrl);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
System.err.println("Errors happened while accessing the package-list file at " + packageListUrl);
|
||||
} finally {
|
||||
if (br != null)
|
||||
try {
|
||||
br.close();
|
||||
} catch (IOException e) {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds api doc roots from an offline link.
|
||||
* The folder specified by packageListUrl should contain the package-list associed with the docUrl folder.
|
||||
* @param docUrl folder containing the javadoc
|
||||
* Adds api doc roots from an offline link. The folder specified by
|
||||
* packageListUrl should contain the package-list associed with the docUrl
|
||||
* folder.
|
||||
*
|
||||
* @param docUrl folder containing the javadoc
|
||||
* @param packageListUrl folder containing the package-list
|
||||
*/
|
||||
private void addApiDocRootsOffline(String docUrl, String packageListUrl) {
|
||||
BufferedReader br = null;
|
||||
packageListUrl = fixApiDocRoot(packageListUrl);
|
||||
try {
|
||||
URL url = new URL(packageListUrl + "/package-list");
|
||||
br = new BufferedReader(new InputStreamReader(url.openStream()));
|
||||
String line;
|
||||
while((line = br.readLine()) != null) {
|
||||
line = line + ".";
|
||||
Pattern pattern = Pattern.compile(line.replace(".", "\\.") + "[^\\.]*");
|
||||
apiDocMap.put(pattern, fixApiDocRoot(docUrl));
|
||||
}
|
||||
} catch(IOException e) {
|
||||
System.err.println("Unable to access the package-list file at " + packageListUrl);
|
||||
} finally {
|
||||
if (br != null)
|
||||
try {
|
||||
br.close();
|
||||
} catch (IOException e) {}
|
||||
}
|
||||
BufferedReader br = null;
|
||||
packageListUrl = fixApiDocRoot(packageListUrl);
|
||||
try {
|
||||
URL url = new URL(packageListUrl + "/package-list");
|
||||
br = new BufferedReader(new InputStreamReader(url.openStream()));
|
||||
String line;
|
||||
while ((line = br.readLine()) != null) {
|
||||
line = line + ".";
|
||||
Pattern pattern = Pattern.compile(line.replace(".", "\\.") + "[^\\.]*");
|
||||
apiDocMap.put(pattern, fixApiDocRoot(docUrl));
|
||||
}
|
||||
} catch (IOException e) {
|
||||
System.err.println("Unable to access the package-list file at " + packageListUrl);
|
||||
} finally {
|
||||
if (br != null)
|
||||
try {
|
||||
br.close();
|
||||
} catch (IOException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the property file referred by <code>apiDocMapFileName</code> and fills the apiDocMap
|
||||
* accordingly
|
||||
* Loads the property file referred by <code>apiDocMapFileName</code> and fills
|
||||
* the apiDocMap accordingly
|
||||
*
|
||||
* @param apiDocMapFileName
|
||||
*/
|
||||
void setApiDocMapFile(String apiDocMapFileName) {
|
||||
try {
|
||||
InputStream is = new FileInputStream(apiDocMapFileName);
|
||||
Properties userMap = new Properties();
|
||||
userMap.load(is);
|
||||
for (Map.Entry<?, ?> mapEntry : userMap.entrySet()) {
|
||||
try {
|
||||
String thisRoot = (String) mapEntry.getValue();
|
||||
if (thisRoot != null) {
|
||||
thisRoot = fixApiDocRoot(thisRoot);
|
||||
apiDocMap.put(Pattern.compile((String) mapEntry.getKey()), thisRoot);
|
||||
} else {
|
||||
System.err.println("No URL for pattern " + mapEntry.getKey());
|
||||
}
|
||||
} catch (PatternSyntaxException e) {
|
||||
System.err.println("Skipping bad pattern " + mapEntry.getKey());
|
||||
}
|
||||
}
|
||||
} catch (FileNotFoundException e) {
|
||||
System.err.println("File " + apiDocMapFileName + " was not found: " + e);
|
||||
} catch (IOException e) {
|
||||
System.err.println("Error reading the property api map file " + apiDocMapFileName
|
||||
+ ": " + e);
|
||||
}
|
||||
try {
|
||||
InputStream is = new FileInputStream(apiDocMapFileName);
|
||||
Properties userMap = new Properties();
|
||||
userMap.load(is);
|
||||
for (Map.Entry<?, ?> mapEntry : userMap.entrySet()) {
|
||||
try {
|
||||
String thisRoot = (String) mapEntry.getValue();
|
||||
if (thisRoot != null) {
|
||||
thisRoot = fixApiDocRoot(thisRoot);
|
||||
apiDocMap.put(Pattern.compile((String) mapEntry.getKey()), thisRoot);
|
||||
} else {
|
||||
System.err.println("No URL for pattern " + mapEntry.getKey());
|
||||
}
|
||||
} catch (PatternSyntaxException e) {
|
||||
System.err.println("Skipping bad pattern " + mapEntry.getKey());
|
||||
}
|
||||
}
|
||||
} catch (FileNotFoundException e) {
|
||||
System.err.println("File " + apiDocMapFileName + " was not found: " + e);
|
||||
} catch (IOException e) {
|
||||
System.err.println("Error reading the property api map file " + apiDocMapFileName + ": " + e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the appropriate URL "root" for an external class name. It will
|
||||
* match the class name against the regular expressions specified in the
|
||||
* <code>apiDocMap</code>; if a match is found, the associated URL
|
||||
* will be returned.
|
||||
* Returns the appropriate URL "root" for an external class name. It will match
|
||||
* the class name against the regular expressions specified in the
|
||||
* <code>apiDocMap</code>; if a match is found, the associated URL will be
|
||||
* returned.
|
||||
* <p>
|
||||
* <b>NOTE:</b> 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.
|
||||
* <b>NOTE:</b> 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.
|
||||
*/
|
||||
public String getApiDocRoot(String className) {
|
||||
if(apiDocMap.isEmpty())
|
||||
apiDocMap.put(Pattern.compile(".*"), DEFAULT_EXTERNAL_APIDOC);
|
||||
if (apiDocMap.isEmpty())
|
||||
apiDocMap.put(Pattern.compile(".*"), DEFAULT_EXTERNAL_APIDOC);
|
||||
|
||||
for (Map.Entry<Pattern, String> mapEntry : apiDocMap.entrySet()) {
|
||||
if (mapEntry.getKey().matcher(className).matches())
|
||||
return mapEntry.getValue();
|
||||
}
|
||||
return null;
|
||||
for (Map.Entry<Pattern, String> mapEntry : apiDocMap.entrySet()) {
|
||||
if (mapEntry.getKey().matcher(className).matches())
|
||||
return mapEntry.getValue();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/** Trim and append a file separator to the string */
|
||||
private String fixApiDocRoot(String str) {
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
/** Set the options based on the command line parameters */
|
||||
public void setOptions(String[][] options) {
|
||||
for (String s[] : options)
|
||||
setOption(s);
|
||||
for (String s[] : options)
|
||||
setOption(s);
|
||||
}
|
||||
|
||||
|
||||
/** Set the options based on the tag elements of the ClassDoc parameter */
|
||||
public void setOptions(Doc p) {
|
||||
if (p == null)
|
||||
return;
|
||||
if (p == null)
|
||||
return;
|
||||
|
||||
for (Tag tag : p.tags("opt"))
|
||||
setOption(StringUtil.tokenize(tag.text()));
|
||||
for (Tag tag : p.tags("opt"))
|
||||
setOption(StringUtil.tokenize(tag.text()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the supplied string matches an entity specified
|
||||
* with the -hide parameter.
|
||||
* Check if the supplied string matches an entity specified with the -hide
|
||||
* parameter.
|
||||
*
|
||||
* @return true if the string matches.
|
||||
*/
|
||||
public boolean matchesHideExpression(String s) {
|
||||
for (Pattern hidePattern : hidePatterns) {
|
||||
// micro-optimization because the "all pattern" is heavily used in UmlGraphDoc
|
||||
if(hidePattern == allPattern)
|
||||
return true;
|
||||
for (Pattern hidePattern : hidePatterns) {
|
||||
// micro-optimization because the "all pattern" is heavily used in UmlGraphDoc
|
||||
if (hidePattern == allPattern)
|
||||
return true;
|
||||
|
||||
Matcher m = hidePattern.matcher(s);
|
||||
if (strictMatching ? m.matches() : m.find())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
Matcher m = hidePattern.matcher(s);
|
||||
if (strictMatching ? m.matches() : m.find())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the supplied string matches an entity specified
|
||||
* with the -include parameter.
|
||||
* Check if the supplied string matches an entity specified with the -include
|
||||
* parameter.
|
||||
*
|
||||
* @return true if the string matches.
|
||||
*/
|
||||
public boolean matchesIncludeExpression(String s) {
|
||||
for (Pattern includePattern : includePatterns) {
|
||||
Matcher m = includePattern.matcher(s);
|
||||
if (strictMatching ? m.matches() : m.find())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
for (Pattern includePattern : includePatterns) {
|
||||
Matcher m = includePattern.matcher(s);
|
||||
if (strictMatching ? m.matches() : m.find())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the supplied string matches an entity specified
|
||||
* with the -collpackages parameter.
|
||||
* Check if the supplied string matches an entity specified with the
|
||||
* -collpackages parameter.
|
||||
*
|
||||
* @return true if the string matches.
|
||||
*/
|
||||
public boolean matchesCollPackageExpression(String s) {
|
||||
for (Pattern collPattern : collPackages) {
|
||||
Matcher m = collPattern.matcher(s);
|
||||
if (strictMatching ? m.matches() : m.find())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
for (Pattern collPattern : collPackages) {
|
||||
Matcher m = collPattern.matcher(s);
|
||||
if (strictMatching ? m.matches() : m.find())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
|
|
@ -641,44 +622,44 @@ public class Options implements Cloneable, OptionProvider {
|
|||
// ----------------------------------------------------------------
|
||||
|
||||
public Options getOptionsFor(ClassDoc cd) {
|
||||
Options localOpt = getGlobalOptions();
|
||||
localOpt.setOptions(cd);
|
||||
return localOpt;
|
||||
Options localOpt = getGlobalOptions();
|
||||
localOpt.setOptions(cd);
|
||||
return localOpt;
|
||||
}
|
||||
|
||||
public Options getOptionsFor(String name) {
|
||||
return getGlobalOptions();
|
||||
return getGlobalOptions();
|
||||
}
|
||||
|
||||
public Options getGlobalOptions() {
|
||||
return (Options) clone();
|
||||
return (Options) clone();
|
||||
}
|
||||
|
||||
public void overrideForClass(Options opt, ClassDoc cd) {
|
||||
// nothing to do
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
public void overrideForClass(Options opt, String className) {
|
||||
// nothing to do
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
public String getDisplayName() {
|
||||
return "general class diagram";
|
||||
return "general class diagram";
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("UMLGRAPH OPTIONS\n");
|
||||
for(Field f : this.getClass().getDeclaredFields()) {
|
||||
if(!Modifier.isStatic(f.getModifiers())) {
|
||||
f.setAccessible(true);
|
||||
try {
|
||||
sb.append(f.getName() + ":" + f.get(this) + "\n");
|
||||
} catch (Exception e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("UMLGRAPH OPTIONS\n");
|
||||
for (Field f : this.getClass().getDeclaredFields()) {
|
||||
if (!Modifier.isStatic(f.getModifiers())) {
|
||||
f.setAccessible(true);
|
||||
try {
|
||||
sb.append(f.getName() + ":" + f.get(this) + "\n");
|
||||
} catch (Exception e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,19 +7,19 @@ public class PackageMatcher implements ClassMatcher {
|
|||
protected PackageDoc packageDoc;
|
||||
|
||||
public PackageMatcher(PackageDoc packageDoc) {
|
||||
super();
|
||||
this.packageDoc = packageDoc;
|
||||
super();
|
||||
this.packageDoc = packageDoc;
|
||||
}
|
||||
|
||||
public boolean matches(ClassDoc cd) {
|
||||
return cd.containingPackage().equals(packageDoc);
|
||||
return cd.containingPackage().equals(packageDoc);
|
||||
}
|
||||
|
||||
public boolean matches(String name) {
|
||||
for (ClassDoc cd : packageDoc.allClasses())
|
||||
if (cd.qualifiedName().equals(name))
|
||||
return true;
|
||||
return false;
|
||||
for (ClassDoc cd : packageDoc.allClasses())
|
||||
if (cd.qualifiedName().equals(name))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import com.sun.javadoc.RootDoc;
|
|||
* single {@linkplain ClassMatcher}, and provides some extra configuration such
|
||||
* as output path configuration (and it is specified in code rather than in
|
||||
* javadoc comments).
|
||||
*
|
||||
* @author wolf
|
||||
*
|
||||
*/
|
||||
|
|
@ -25,57 +26,57 @@ public class PackageView implements OptionProvider {
|
|||
private Options opt;
|
||||
|
||||
public PackageView(String outputFolder, PackageDoc pd, RootDoc root, OptionProvider parent) {
|
||||
this.parent = parent;
|
||||
this.pd = pd;
|
||||
this.matcher = new PackageMatcher(pd);
|
||||
this.opt = parent.getGlobalOptions();
|
||||
this.opt.setOptions(pd);
|
||||
this.outputPath = pd.name().replace('.', '/') + "/" + pd.name() + ".dot";
|
||||
this.parent = parent;
|
||||
this.pd = pd;
|
||||
this.matcher = new PackageMatcher(pd);
|
||||
this.opt = parent.getGlobalOptions();
|
||||
this.opt.setOptions(pd);
|
||||
this.outputPath = pd.name().replace('.', '/') + "/" + pd.name() + ".dot";
|
||||
}
|
||||
|
||||
public String getDisplayName() {
|
||||
return "Package view for package " + pd;
|
||||
return "Package view for package " + pd;
|
||||
}
|
||||
|
||||
public Options getGlobalOptions() {
|
||||
Options go = parent.getGlobalOptions();
|
||||
Options go = parent.getGlobalOptions();
|
||||
|
||||
go.setOption(new String[] { "output", outputPath });
|
||||
go.setOption(HIDE);
|
||||
go.setOption(new String[] { "output", outputPath });
|
||||
go.setOption(HIDE);
|
||||
|
||||
return go;
|
||||
return go;
|
||||
}
|
||||
|
||||
public Options getOptionsFor(ClassDoc cd) {
|
||||
Options go = parent.getGlobalOptions();
|
||||
overrideForClass(go, cd);
|
||||
return go;
|
||||
Options go = parent.getGlobalOptions();
|
||||
overrideForClass(go, cd);
|
||||
return go;
|
||||
}
|
||||
|
||||
public Options getOptionsFor(String name) {
|
||||
Options go = parent.getGlobalOptions();
|
||||
overrideForClass(go, name);
|
||||
return go;
|
||||
Options go = parent.getGlobalOptions();
|
||||
overrideForClass(go, name);
|
||||
return go;
|
||||
}
|
||||
|
||||
public void overrideForClass(Options opt, ClassDoc cd) {
|
||||
opt.setOptions(cd);
|
||||
boolean inPackage = matcher.matches(cd);
|
||||
if (inPackage)
|
||||
opt.showQualified = false;
|
||||
boolean included = inPackage || this.opt.matchesIncludeExpression(cd.qualifiedName());
|
||||
if (!included || this.opt.matchesHideExpression(cd.qualifiedName()))
|
||||
opt.setOption(HIDE);
|
||||
opt.setOptions(cd);
|
||||
boolean inPackage = matcher.matches(cd);
|
||||
if (inPackage)
|
||||
opt.showQualified = false;
|
||||
boolean included = inPackage || this.opt.matchesIncludeExpression(cd.qualifiedName());
|
||||
if (!included || this.opt.matchesHideExpression(cd.qualifiedName()))
|
||||
opt.setOption(HIDE);
|
||||
}
|
||||
|
||||
public void overrideForClass(Options opt, String className) {
|
||||
opt.showQualified = false;
|
||||
boolean inPackage = matcher.matches(className);
|
||||
if (inPackage)
|
||||
opt.showQualified = false;
|
||||
boolean included = inPackage || this.opt.matchesIncludeExpression(className);
|
||||
if (!included || this.opt.matchesHideExpression(className))
|
||||
opt.setOption(HIDE);
|
||||
opt.showQualified = false;
|
||||
boolean inPackage = matcher.matches(className);
|
||||
if (inPackage)
|
||||
opt.showQualified = false;
|
||||
boolean included = inPackage || this.opt.matchesIncludeExpression(className);
|
||||
if (!included || this.opt.matchesHideExpression(className))
|
||||
opt.setOption(HIDE);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,21 +23,22 @@ import com.sun.javadoc.ClassDoc;
|
|||
/**
|
||||
* Matches classes performing a regular expression match on the qualified class
|
||||
* name
|
||||
*
|
||||
* @author wolf
|
||||
*/
|
||||
public class PatternMatcher implements ClassMatcher {
|
||||
Pattern pattern;
|
||||
|
||||
public PatternMatcher(Pattern pattern) {
|
||||
this.pattern = pattern;
|
||||
this.pattern = pattern;
|
||||
}
|
||||
|
||||
public boolean matches(ClassDoc cd) {
|
||||
return matches(cd.toString());
|
||||
return matches(cd.toString());
|
||||
}
|
||||
|
||||
public boolean matches(String name) {
|
||||
return pattern.matcher(name).matches();
|
||||
return pattern.matcher(name).matches();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,32 +9,35 @@ public enum RelationDirection {
|
|||
|
||||
/**
|
||||
* Adds the current direction
|
||||
*
|
||||
* @param d
|
||||
* @return
|
||||
*/
|
||||
public RelationDirection sum(RelationDirection d) {
|
||||
// Handle same and nones first:
|
||||
return (this == d || d == NONE) ? this : //
|
||||
this == NONE ? d : BOTH; // They are different and not none.
|
||||
// Handle same and nones first:
|
||||
return (this == d || d == NONE) ? this : //
|
||||
this == NONE ? d : BOTH; // They are different and not none.
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this direction "contains" the specified one, that is,
|
||||
* either it's equal to it, or this direction is {@link #BOTH}
|
||||
* Returns true if this direction "contains" the specified one, that is, either
|
||||
* it's equal to it, or this direction is {@link #BOTH}
|
||||
*
|
||||
* @param d
|
||||
* @return
|
||||
*/
|
||||
public boolean contains(RelationDirection d) {
|
||||
return this == BOTH ? true : (d == this);
|
||||
return this == BOTH ? true : (d == this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inverts the direction of the relation. Turns IN into OUT and vice-versa, NONE and BOTH
|
||||
* are not changed
|
||||
* Inverts the direction of the relation. Turns IN into OUT and vice-versa, NONE
|
||||
* and BOTH are not changed
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public RelationDirection inverse() {
|
||||
return this == IN ? OUT : this == OUT ? IN : this;
|
||||
return this == IN ? OUT : this == OUT ? IN : this;
|
||||
}
|
||||
|
||||
};
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package org.umlgraph.doclet;
|
|||
|
||||
/**
|
||||
* A map from relation types to directions
|
||||
*
|
||||
* @author wolf
|
||||
*
|
||||
*/
|
||||
|
|
@ -13,38 +14,41 @@ public class RelationPattern {
|
|||
|
||||
/**
|
||||
* Creates a new pattern using the same direction for every relation kind
|
||||
*
|
||||
* @param defaultDirection The direction used to initialize this pattern
|
||||
*/
|
||||
public RelationPattern(RelationDirection defaultDirection) {
|
||||
directions = new RelationDirection[RelationType.values().length];
|
||||
for (int i = 0; i < directions.length; i++) {
|
||||
directions[i] = defaultDirection;
|
||||
}
|
||||
directions = new RelationDirection[RelationType.values().length];
|
||||
for (int i = 0; i < directions.length; i++) {
|
||||
directions[i] = defaultDirection;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds, eventually merging, a direction for the specified relation type
|
||||
*
|
||||
* @param relationType
|
||||
* @param direction
|
||||
*/
|
||||
public void addRelation(RelationType relationType, RelationDirection direction) {
|
||||
int idx = relationType.ordinal();
|
||||
directions[idx] = directions[idx].sum(direction);
|
||||
int idx = relationType.ordinal();
|
||||
directions[idx] = directions[idx].sum(direction);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this patterns matches at least the direction of one
|
||||
* of the relations in the other relation patterns. Matching is defined
|
||||
* by {@linkplain RelationDirection#contains(RelationDirection)}
|
||||
* Returns true if this patterns matches at least the direction of one of the
|
||||
* relations in the other relation patterns. Matching is defined by
|
||||
* {@linkplain RelationDirection#contains(RelationDirection)}
|
||||
*
|
||||
* @param relationPattern
|
||||
* @return
|
||||
*/
|
||||
public boolean matchesOne(RelationPattern relationPattern) {
|
||||
for (int i = 0; i < directions.length; i++) {
|
||||
if (directions[i].contains(relationPattern.directions[i]))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
for (int i = 0; i < directions.length; i++) {
|
||||
if (directions[i].contains(relationPattern.directions[i]))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,8 +27,8 @@ public enum RelationType {
|
|||
|
||||
/** Enum constructors must be private */
|
||||
private RelationType(String style, boolean backorder) {
|
||||
this.lower = toString().toLowerCase();
|
||||
this.style = style;
|
||||
this.backorder = backorder;
|
||||
this.lower = toString().toLowerCase();
|
||||
this.style = style;
|
||||
this.backorder = backorder;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,10 +45,10 @@ public enum Shape {
|
|||
|
||||
/** Initialize the lookup index */
|
||||
static {
|
||||
for (Shape s : Shape.values()) {
|
||||
index.put(s.name(), s);
|
||||
index.put(s.name().toLowerCase(Locale.ROOT), s);
|
||||
}
|
||||
for (Shape s : Shape.values()) {
|
||||
index.put(s.name(), s);
|
||||
index.put(s.name().toLowerCase(Locale.ROOT), s);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -59,25 +59,25 @@ public enum Shape {
|
|||
* @return Shape
|
||||
*/
|
||||
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;
|
||||
Shape shp = index.get(s);
|
||||
if (shp != null)
|
||||
return shp;
|
||||
System.err.println("Ignoring invalid shape: " + s);
|
||||
return CLASS;
|
||||
}
|
||||
|
||||
/** Enum constructor, must be private! */
|
||||
private Shape(String style) {
|
||||
this.style = style;
|
||||
this.style = style;
|
||||
}
|
||||
|
||||
/** Return the table border required for the shape */
|
||||
public String extraColumn() {
|
||||
return this == Shape.ACTIVECLASS ? ("<td rowspan=\"10\"></td>") : "";
|
||||
return this == Shape.ACTIVECLASS ? ("<td rowspan=\"10\"></td>") : "";
|
||||
}
|
||||
|
||||
/** Return the cell border required for the shape */
|
||||
public String cellBorder() {
|
||||
return this == CLASS || this == ACTIVECLASS ? "1" : "0";
|
||||
return this == CLASS || this == ACTIVECLASS ? "1" : "0";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,37 +31,37 @@ import java.util.regex.Pattern;
|
|||
class StringUtil {
|
||||
/** Tokenize string s into an array */
|
||||
public static String[] tokenize(String s) {
|
||||
ArrayList<String> r = new ArrayList<String>();
|
||||
String remain = s;
|
||||
int n = 0, pos;
|
||||
ArrayList<String> r = new ArrayList<String>();
|
||||
String remain = s;
|
||||
int n = 0, pos;
|
||||
|
||||
remain = remain.trim();
|
||||
while (remain.length() > 0) {
|
||||
if (remain.startsWith("\"")) {
|
||||
// Field in quotes
|
||||
pos = remain.indexOf('"', 1);
|
||||
if (pos == -1)
|
||||
break;
|
||||
r.add(remain.substring(1, pos));
|
||||
if (pos + 1 < remain.length())
|
||||
pos++;
|
||||
} else {
|
||||
// Space-separated field
|
||||
pos = remain.indexOf(' ', 0);
|
||||
if (pos == -1) {
|
||||
r.add(remain);
|
||||
remain = "";
|
||||
} else
|
||||
r.add(remain.substring(0, pos));
|
||||
}
|
||||
remain = remain.substring(pos + 1);
|
||||
remain = remain.trim();
|
||||
// - is used as a placeholder for empy fields
|
||||
if (r.get(n).equals("-"))
|
||||
r.set(n, "");
|
||||
n++;
|
||||
}
|
||||
return r.toArray(new String[0]);
|
||||
remain = remain.trim();
|
||||
while (remain.length() > 0) {
|
||||
if (remain.startsWith("\"")) {
|
||||
// Field in quotes
|
||||
pos = remain.indexOf('"', 1);
|
||||
if (pos == -1)
|
||||
break;
|
||||
r.add(remain.substring(1, pos));
|
||||
if (pos + 1 < remain.length())
|
||||
pos++;
|
||||
} else {
|
||||
// Space-separated field
|
||||
pos = remain.indexOf(' ', 0);
|
||||
if (pos == -1) {
|
||||
r.add(remain);
|
||||
remain = "";
|
||||
} else
|
||||
r.add(remain.substring(0, pos));
|
||||
}
|
||||
remain = remain.substring(pos + 1);
|
||||
remain = remain.trim();
|
||||
// - is used as a placeholder for empy fields
|
||||
if (r.get(n).equals("-"))
|
||||
r.set(n, "");
|
||||
n++;
|
||||
}
|
||||
return r.toArray(new String[0]);
|
||||
}
|
||||
|
||||
private final static Pattern ESCAPE_BASIC_XML = Pattern.compile("[&<>]");
|
||||
|
|
@ -71,47 +71,47 @@ class StringUtil {
|
|||
* 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;
|
||||
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;
|
||||
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, "<br/>");
|
||||
i += "<br/>".length();
|
||||
} else
|
||||
i++;
|
||||
}
|
||||
return sb.toString();
|
||||
StringBuilder sb = new StringBuilder(s);
|
||||
for (int i = 0; i < sb.length();) {
|
||||
if (sb.charAt(i) == '\n') {
|
||||
sb.replace(i, i + 1, "<br/>");
|
||||
i += "<br/>".length();
|
||||
} else
|
||||
i++;
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -119,22 +119,22 @@ class StringUtil {
|
|||
* 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();
|
||||
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();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -144,45 +144,45 @@ class StringUtil {
|
|||
* @return the wrapped <code>String</code>.
|
||||
*/
|
||||
public static String guilWrap(Options opt, String str) {
|
||||
return opt.guilOpen + str + opt.guilClose;
|
||||
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();
|
||||
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("\\.");
|
||||
// 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();
|
||||
// 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();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -199,22 +199,22 @@ class StringUtil {
|
|||
* @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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -226,6 +226,6 @@ class StringUtil {
|
|||
* @return Formatted value
|
||||
*/
|
||||
public static String fmt(double val) {
|
||||
return val == Math.round(val) ? Long.toString((long) val) : Double.toString(val);
|
||||
return val == Math.round(val) ? Long.toString((long) val) : Double.toString(val);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@ import com.sun.javadoc.ClassDoc;
|
|||
import com.sun.javadoc.RootDoc;
|
||||
|
||||
/**
|
||||
* Matches every class that extends (directly or indirectly) a class
|
||||
* matched by the regular expression provided.
|
||||
* Matches every class that extends (directly or indirectly) a class matched by
|
||||
* the regular expression provided.
|
||||
*/
|
||||
public class SubclassMatcher implements ClassMatcher {
|
||||
|
||||
|
|
@ -15,22 +15,22 @@ public class SubclassMatcher implements ClassMatcher {
|
|||
protected Pattern pattern;
|
||||
|
||||
public SubclassMatcher(RootDoc root, Pattern pattern) {
|
||||
this.root = root;
|
||||
this.pattern = pattern;
|
||||
this.root = root;
|
||||
this.pattern = pattern;
|
||||
}
|
||||
|
||||
public boolean matches(ClassDoc cd) {
|
||||
// if it's the class we're looking for return
|
||||
if(pattern.matcher(cd.toString()).matches())
|
||||
return true;
|
||||
// if it's the class we're looking for return
|
||||
if (pattern.matcher(cd.toString()).matches())
|
||||
return true;
|
||||
|
||||
// recurse on supeclass, if available
|
||||
return cd.superclass() == null ? false : matches(cd.superclass());
|
||||
// recurse on supeclass, if available
|
||||
return cd.superclass() == null ? false : matches(cd.superclass());
|
||||
}
|
||||
|
||||
public boolean matches(String name) {
|
||||
ClassDoc cd = root.classNamed(name);
|
||||
return cd == null ? false : matches(cd);
|
||||
ClassDoc cd = root.classNamed(name);
|
||||
return cd == null ? false : matches(cd);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,8 +2,10 @@ package org.umlgraph.doclet;
|
|||
|
||||
/**
|
||||
* Options for UMLGraph class diagram generation
|
||||
*
|
||||
* @opt operations
|
||||
* @opt visibility
|
||||
* @hidden
|
||||
*/
|
||||
public class UMLOptions {}
|
||||
public class UMLOptions {
|
||||
}
|
||||
|
|
@ -31,6 +31,7 @@ import com.sun.javadoc.RootDoc;
|
|||
|
||||
/**
|
||||
* Doclet API implementation
|
||||
*
|
||||
* @depend - - - OptionProvider
|
||||
* @depend - - - Options
|
||||
* @depend - - - View
|
||||
|
|
@ -50,139 +51,138 @@ public class UmlGraph {
|
|||
|
||||
/** Entry point through javadoc */
|
||||
public static boolean start(RootDoc root) throws IOException {
|
||||
Options opt = buildOptions(root);
|
||||
root.printNotice("UMLGraph doclet version " + Version.VERSION + " started");
|
||||
Options opt = buildOptions(root);
|
||||
root.printNotice("UMLGraph doclet version " + Version.VERSION + " started");
|
||||
|
||||
View[] views = buildViews(opt, root, root);
|
||||
if(views == null)
|
||||
return false;
|
||||
if (views.length == 0)
|
||||
buildGraph(root, opt, null);
|
||||
else
|
||||
for (int i = 0; i < views.length; i++)
|
||||
buildGraph(root, views[i], null);
|
||||
return true;
|
||||
View[] views = buildViews(opt, root, root);
|
||||
if (views == null)
|
||||
return false;
|
||||
if (views.length == 0)
|
||||
buildGraph(root, opt, null);
|
||||
else
|
||||
for (int i = 0; i < views.length; i++)
|
||||
buildGraph(root, views[i], null);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void main(String args[]) {
|
||||
PrintWriter err = new PrintWriter(System.err);
|
||||
com.sun.tools.javadoc.Main.execute(programName,
|
||||
err, err, err, docletName, args);
|
||||
PrintWriter err = new PrintWriter(System.err);
|
||||
com.sun.tools.javadoc.Main.execute(programName, err, err, err, docletName, args);
|
||||
}
|
||||
|
||||
public static Options getCommentOptions() {
|
||||
return commentOptions;
|
||||
return commentOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the base Options object.
|
||||
* This contains both the options specified on the command
|
||||
* line and the ones specified in the UMLOptions class, if available.
|
||||
* Also create the globally accessible commentOptions object.
|
||||
* Creates the base Options object. This contains both the options specified on
|
||||
* the command line and the ones specified in the UMLOptions class, if
|
||||
* available. Also create the globally accessible commentOptions object.
|
||||
*/
|
||||
public static Options buildOptions(RootDoc root) {
|
||||
commentOptions = new Options();
|
||||
commentOptions.setOptions(root.options());
|
||||
commentOptions.setOptions(findClass(root, "UMLNoteOptions"));
|
||||
commentOptions.shape = Shape.NOTE;
|
||||
commentOptions = new Options();
|
||||
commentOptions.setOptions(root.options());
|
||||
commentOptions.setOptions(findClass(root, "UMLNoteOptions"));
|
||||
commentOptions.shape = Shape.NOTE;
|
||||
|
||||
Options opt = new Options();
|
||||
opt.setOptions(root.options());
|
||||
opt.setOptions(findClass(root, "UMLOptions"));
|
||||
return opt;
|
||||
Options opt = new Options();
|
||||
opt.setOptions(root.options());
|
||||
opt.setOptions(findClass(root, "UMLOptions"));
|
||||
return opt;
|
||||
}
|
||||
|
||||
/** Return the ClassDoc for the specified class; null if not found. */
|
||||
private static ClassDoc findClass(RootDoc root, String name) {
|
||||
ClassDoc[] classes = root.classes();
|
||||
for (ClassDoc cd : classes)
|
||||
if(cd.name().equals(name))
|
||||
return cd;
|
||||
return null;
|
||||
ClassDoc[] classes = root.classes();
|
||||
for (ClassDoc cd : classes)
|
||||
if (cd.name().equals(name))
|
||||
return cd;
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds and outputs a single graph according to the view overrides
|
||||
*/
|
||||
public static void buildGraph(RootDoc root, OptionProvider op, Doc contextDoc) throws IOException {
|
||||
if(getCommentOptions() == null)
|
||||
buildOptions(root);
|
||||
Options opt = op.getGlobalOptions();
|
||||
root.printNotice("Building " + op.getDisplayName());
|
||||
ClassDoc[] classes = root.classes();
|
||||
if (getCommentOptions() == null)
|
||||
buildOptions(root);
|
||||
Options opt = op.getGlobalOptions();
|
||||
root.printNotice("Building " + op.getDisplayName());
|
||||
ClassDoc[] classes = root.classes();
|
||||
|
||||
ClassGraph c = new ClassGraph(root, op, contextDoc);
|
||||
c.prologue();
|
||||
for (ClassDoc cd : classes)
|
||||
c.printClass(cd, true);
|
||||
for (ClassDoc cd : classes)
|
||||
c.printRelations(cd);
|
||||
if(opt.inferRelationships)
|
||||
for (ClassDoc cd : classes)
|
||||
c.printInferredRelations(cd);
|
||||
if(opt.inferDependencies)
|
||||
for (ClassDoc cd : classes)
|
||||
c.printInferredDependencies(cd);
|
||||
ClassGraph c = new ClassGraph(root, op, contextDoc);
|
||||
c.prologue();
|
||||
for (ClassDoc cd : classes)
|
||||
c.printClass(cd, true);
|
||||
for (ClassDoc cd : classes)
|
||||
c.printRelations(cd);
|
||||
if (opt.inferRelationships)
|
||||
for (ClassDoc cd : classes)
|
||||
c.printInferredRelations(cd);
|
||||
if (opt.inferDependencies)
|
||||
for (ClassDoc cd : classes)
|
||||
c.printInferredDependencies(cd);
|
||||
|
||||
c.printExtraClasses(root);
|
||||
c.epilogue();
|
||||
c.printExtraClasses(root);
|
||||
c.epilogue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the views according to the parameters on the command line
|
||||
* @param opt The options
|
||||
* @param srcRootDoc The RootDoc for the source classes
|
||||
* @param viewRootDoc The RootDoc for the view classes (may be
|
||||
* different, or may be the same as the srcRootDoc)
|
||||
*
|
||||
* @param opt The options
|
||||
* @param srcRootDoc The RootDoc for the source classes
|
||||
* @param viewRootDoc The RootDoc for the view classes (may be different, or may
|
||||
* be the same as the srcRootDoc)
|
||||
*/
|
||||
public static View[] buildViews(Options opt, RootDoc srcRootDoc, RootDoc viewRootDoc) {
|
||||
if (opt.viewName != null) {
|
||||
ClassDoc viewClass = viewRootDoc.classNamed(opt.viewName);
|
||||
if(viewClass == null) {
|
||||
System.out.println("View " + opt.viewName + " not found! Exiting without generating any output.");
|
||||
return null;
|
||||
}
|
||||
if(viewClass.tags("view").length == 0) {
|
||||
System.out.println(viewClass + " is not a view!");
|
||||
return null;
|
||||
}
|
||||
if(viewClass.isAbstract()) {
|
||||
System.out.println(viewClass + " is an abstract view, no output will be generated!");
|
||||
return null;
|
||||
}
|
||||
return new View[] { buildView(srcRootDoc, viewClass, opt) };
|
||||
} else if (opt.findViews) {
|
||||
List<View> views = new ArrayList<View>();
|
||||
ClassDoc[] classes = viewRootDoc.classes();
|
||||
if (opt.viewName != null) {
|
||||
ClassDoc viewClass = viewRootDoc.classNamed(opt.viewName);
|
||||
if (viewClass == null) {
|
||||
System.out.println("View " + opt.viewName + " not found! Exiting without generating any output.");
|
||||
return null;
|
||||
}
|
||||
if (viewClass.tags("view").length == 0) {
|
||||
System.out.println(viewClass + " is not a view!");
|
||||
return null;
|
||||
}
|
||||
if (viewClass.isAbstract()) {
|
||||
System.out.println(viewClass + " is an abstract view, no output will be generated!");
|
||||
return null;
|
||||
}
|
||||
return new View[] { buildView(srcRootDoc, viewClass, opt) };
|
||||
} else if (opt.findViews) {
|
||||
List<View> views = new ArrayList<View>();
|
||||
ClassDoc[] classes = viewRootDoc.classes();
|
||||
|
||||
// find view classes
|
||||
for (int i = 0; i < classes.length; i++)
|
||||
if (classes[i].tags("view").length > 0 && !classes[i].isAbstract())
|
||||
views.add(buildView(srcRootDoc, classes[i], opt));
|
||||
// find view classes
|
||||
for (int i = 0; i < classes.length; i++)
|
||||
if (classes[i].tags("view").length > 0 && !classes[i].isAbstract())
|
||||
views.add(buildView(srcRootDoc, classes[i], opt));
|
||||
|
||||
return views.toArray(new View[views.size()]);
|
||||
} else
|
||||
return new View[0];
|
||||
return views.toArray(new View[views.size()]);
|
||||
} else
|
||||
return new View[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a view along with its parent views, recursively
|
||||
*/
|
||||
private static View buildView(RootDoc root, ClassDoc viewClass, OptionProvider provider) {
|
||||
ClassDoc superClass = viewClass.superclass();
|
||||
if(superClass == null || superClass.tags("view").length == 0)
|
||||
return new View(root, viewClass, provider);
|
||||
ClassDoc superClass = viewClass.superclass();
|
||||
if (superClass == null || superClass.tags("view").length == 0)
|
||||
return new View(root, viewClass, provider);
|
||||
|
||||
return new View(root, viewClass, buildView(root, superClass, provider));
|
||||
return new View(root, viewClass, buildView(root, superClass, provider));
|
||||
}
|
||||
|
||||
/** Option checking */
|
||||
public static int optionLength(String option) {
|
||||
return Options.optionLength(option);
|
||||
return Options.optionLength(option);
|
||||
}
|
||||
|
||||
/** Indicate the language version we support */
|
||||
public static LanguageVersion languageVersion() {
|
||||
return LanguageVersion.JAVA_1_5;
|
||||
return LanguageVersion.JAVA_1_5;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import com.sun.tools.doclets.standard.Standard;
|
|||
/**
|
||||
* Chaining doclet that runs the standart Javadoc doclet first, and on success,
|
||||
* runs the generation of dot files by UMLGraph
|
||||
*
|
||||
* @author wolf
|
||||
*
|
||||
* @depend - - - WrappedClassDoc
|
||||
|
|
@ -30,81 +31,81 @@ import com.sun.tools.doclets.standard.Standard;
|
|||
*/
|
||||
public class UmlGraphDoc {
|
||||
/**
|
||||
* Option check, forwards options to the standard doclet, if that one refuses them,
|
||||
* they are sent to UmlGraph
|
||||
* Option check, forwards options to the standard doclet, if that one refuses
|
||||
* them, they are sent to UmlGraph
|
||||
*/
|
||||
public static int optionLength(String option) {
|
||||
int result = Standard.optionLength(option);
|
||||
if (result != 0)
|
||||
return result;
|
||||
else
|
||||
return UmlGraph.optionLength(option);
|
||||
int result = Standard.optionLength(option);
|
||||
if (result != 0)
|
||||
return result;
|
||||
else
|
||||
return UmlGraph.optionLength(option);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard doclet entry point
|
||||
*
|
||||
* @param root
|
||||
* @return
|
||||
*/
|
||||
public static boolean start(RootDoc root) {
|
||||
root.printNotice("UmlGraphDoc version " + Version.VERSION + ", running the standard doclet");
|
||||
Standard.start(root);
|
||||
root.printNotice("UmlGraphDoc version " + Version.VERSION + ", altering javadocs");
|
||||
try {
|
||||
String outputFolder = findOutputPath(root.options());
|
||||
root.printNotice("UmlGraphDoc version " + Version.VERSION + ", running the standard doclet");
|
||||
Standard.start(root);
|
||||
root.printNotice("UmlGraphDoc version " + Version.VERSION + ", altering javadocs");
|
||||
try {
|
||||
String outputFolder = findOutputPath(root.options());
|
||||
|
||||
Options opt = UmlGraph.buildOptions(root);
|
||||
opt.setOptions(root.options());
|
||||
// in javadoc enumerations are always printed
|
||||
opt.showEnumerations = true;
|
||||
opt.relativeLinksForSourcePackages = true;
|
||||
// enable strict matching for hide expressions
|
||||
opt.strictMatching = true;
|
||||
Options opt = UmlGraph.buildOptions(root);
|
||||
opt.setOptions(root.options());
|
||||
// in javadoc enumerations are always printed
|
||||
opt.showEnumerations = true;
|
||||
opt.relativeLinksForSourcePackages = true;
|
||||
// enable strict matching for hide expressions
|
||||
opt.strictMatching = true;
|
||||
// root.printNotice(opt.toString());
|
||||
|
||||
generatePackageDiagrams(root, opt, outputFolder);
|
||||
generateContextDiagrams(root, opt, outputFolder);
|
||||
} catch(Throwable t) {
|
||||
root.printWarning("Error: " + t.toString());
|
||||
t.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
generatePackageDiagrams(root, opt, outputFolder);
|
||||
generateContextDiagrams(root, opt, outputFolder);
|
||||
} catch (Throwable t) {
|
||||
root.printWarning("Error: " + t.toString());
|
||||
t.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Standand doclet entry
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static LanguageVersion languageVersion() {
|
||||
return Standard.languageVersion();
|
||||
return Standard.languageVersion();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the package diagrams for all of the packages that contain classes among those
|
||||
* returned by RootDoc.class()
|
||||
* Generates the package diagrams for all of the packages that contain classes
|
||||
* among those returned by RootDoc.class()
|
||||
*/
|
||||
private static void generatePackageDiagrams(RootDoc root, Options opt, String outputFolder)
|
||||
throws IOException {
|
||||
Set<String> packages = new HashSet<String>();
|
||||
for (ClassDoc classDoc : root.classes()) {
|
||||
PackageDoc packageDoc = classDoc.containingPackage();
|
||||
if(!packages.contains(packageDoc.name())) {
|
||||
packages.add(packageDoc.name());
|
||||
OptionProvider view = new PackageView(outputFolder, packageDoc, root, opt);
|
||||
UmlGraph.buildGraph(root, view, packageDoc);
|
||||
runGraphviz(opt.dotExecutable, outputFolder, packageDoc.name(), packageDoc.name(), root);
|
||||
alterHtmlDocs(opt, outputFolder, packageDoc.name(), packageDoc.name(),
|
||||
"package-summary.html", Pattern.compile("(</[Hh]2>)|(<h1 title=\"Package\").*"), root);
|
||||
}
|
||||
}
|
||||
private static void generatePackageDiagrams(RootDoc root, Options opt, String outputFolder) throws IOException {
|
||||
Set<String> packages = new HashSet<String>();
|
||||
for (ClassDoc classDoc : root.classes()) {
|
||||
PackageDoc packageDoc = classDoc.containingPackage();
|
||||
if (!packages.contains(packageDoc.name())) {
|
||||
packages.add(packageDoc.name());
|
||||
OptionProvider view = new PackageView(outputFolder, packageDoc, root, opt);
|
||||
UmlGraph.buildGraph(root, view, packageDoc);
|
||||
runGraphviz(opt.dotExecutable, outputFolder, packageDoc.name(), packageDoc.name(), root);
|
||||
alterHtmlDocs(opt, outputFolder, packageDoc.name(), packageDoc.name(), "package-summary.html",
|
||||
Pattern.compile("(</[Hh]2>)|(<h1 title=\"Package\").*"), root);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the context diagram for a single class
|
||||
*/
|
||||
private static void generateContextDiagrams(RootDoc root, Options opt, String outputFolder)
|
||||
throws IOException {
|
||||
private static void generateContextDiagrams(RootDoc root, Options opt, String outputFolder) throws IOException {
|
||||
Set<ClassDoc> classDocs = new TreeSet<ClassDoc>(new Comparator<ClassDoc>() {
|
||||
public int compare(ClassDoc cd1, ClassDoc cd2) {
|
||||
return cd1.name().compareTo(cd2.name());
|
||||
|
|
@ -113,158 +114,143 @@ public class UmlGraphDoc {
|
|||
for (ClassDoc classDoc : root.classes())
|
||||
classDocs.add(classDoc);
|
||||
|
||||
ContextView view = null;
|
||||
for (ClassDoc classDoc : classDocs) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
ContextView view = null;
|
||||
for (ClassDoc classDoc : classDocs) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs Graphviz dot building both a diagram (in png format) and a client side map for it.
|
||||
* Runs Graphviz dot building both a diagram (in png format) and a client side
|
||||
* map for it.
|
||||
*/
|
||||
private static void runGraphviz(String dotExecutable, String outputFolder, String packageName, String name, RootDoc root) {
|
||||
if (dotExecutable == null) {
|
||||
dotExecutable = "dot";
|
||||
}
|
||||
File dotFile = new File(outputFolder, packageName.replace(".", "/") + "/" + name + ".dot");
|
||||
File svgFile = new File(outputFolder, packageName.replace(".", "/") + "/" + name + ".svg");
|
||||
private static void runGraphviz(String dotExecutable, String outputFolder, String packageName, String name,
|
||||
RootDoc root) {
|
||||
if (dotExecutable == null) {
|
||||
dotExecutable = "dot";
|
||||
}
|
||||
File dotFile = new File(outputFolder, packageName.replace(".", "/") + "/" + name + ".dot");
|
||||
File svgFile = new File(outputFolder, packageName.replace(".", "/") + "/" + name + ".svg");
|
||||
|
||||
try {
|
||||
Process p = Runtime.getRuntime().exec(new String [] {
|
||||
dotExecutable,
|
||||
"-Tsvg",
|
||||
"-o",
|
||||
svgFile.getAbsolutePath(),
|
||||
dotFile.getAbsolutePath()
|
||||
});
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(p.getErrorStream()));
|
||||
String line;
|
||||
while((line = reader.readLine()) != null)
|
||||
root.printWarning(line);
|
||||
int result = p.waitFor();
|
||||
if (result != 0)
|
||||
root.printWarning("Errors running Graphviz on " + dotFile);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
System.err.println("Ensure that dot is in your path and that its path does not contain spaces");
|
||||
}
|
||||
try {
|
||||
Process p = Runtime.getRuntime().exec(new String[] { dotExecutable, "-Tsvg", "-o",
|
||||
svgFile.getAbsolutePath(), dotFile.getAbsolutePath() });
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(p.getErrorStream()));
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null)
|
||||
root.printWarning(line);
|
||||
int result = p.waitFor();
|
||||
if (result != 0)
|
||||
root.printWarning("Errors running Graphviz on " + dotFile);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
System.err.println("Ensure that dot is in your path and that its path does not contain spaces");
|
||||
}
|
||||
}
|
||||
|
||||
//Format string for the uml image div tag.
|
||||
private static final String UML_DIV_TAG =
|
||||
"<div align=\"center\">" +
|
||||
"<object width=\"100%%\" height=\"100%%\" type=\"image/svg+xml\" data=\"%1$s.svg\" alt=\"Package class diagram package %1$s\" border=0></object>" +
|
||||
"</div>";
|
||||
// Format string for the uml image div tag.
|
||||
private static final String UML_DIV_TAG = "<div align=\"center\">"
|
||||
+ "<object width=\"100%%\" height=\"100%%\" type=\"image/svg+xml\" data=\"%1$s.svg\" alt=\"Package class diagram package %1$s\" border=0></object>"
|
||||
+ "</div>";
|
||||
|
||||
private static final String UML_AUTO_SIZED_DIV_TAG =
|
||||
"<div align=\"center\">" +
|
||||
"<object type=\"image/svg+xml\" data=\"%1$s.svg\" alt=\"Package class diagram package %1$s\" border=0></object>" +
|
||||
"</div>";
|
||||
private static final String UML_AUTO_SIZED_DIV_TAG = "<div align=\"center\">"
|
||||
+ "<object type=\"image/svg+xml\" data=\"%1$s.svg\" alt=\"Package class diagram package %1$s\" border=0></object>"
|
||||
+ "</div>";
|
||||
|
||||
private static final String EXPANDABLE_UML_STYLE = "font-family: Arial,Helvetica,sans-serif;font-size: 1.5em; display: block; width: 250px; height: 20px; background: #009933; padding: 5px; text-align: center; border-radius: 8px; color: white; font-weight: bold;";
|
||||
|
||||
//Format string for the java script tag.
|
||||
private static final String EXPANDABLE_UML =
|
||||
"<script type=\"text/javascript\">\n" +
|
||||
"function show() {\n" +
|
||||
" document.getElementById(\"uml\").innerHTML = \n" +
|
||||
" \'<a style=\"" + EXPANDABLE_UML_STYLE + "\" href=\"javascript:hide()\">%3$s</a>\' +\n" +
|
||||
" \'%1$s\';\n" +
|
||||
"}\n" +
|
||||
"function hide() {\n" +
|
||||
" document.getElementById(\"uml\").innerHTML = \n" +
|
||||
" \'<a style=\"" + EXPANDABLE_UML_STYLE + "\" href=\"javascript:show()\">%2$s</a>\' ;\n" +
|
||||
"}\n" +
|
||||
"</script>\n" +
|
||||
"<div id=\"uml\" >\n" +
|
||||
" <a href=\"javascript:show()\">\n" +
|
||||
" <a style=\"" + EXPANDABLE_UML_STYLE + "\" href=\"javascript:show()\">%2$s</a> \n" +
|
||||
"</div>";
|
||||
// Format string for the java script tag.
|
||||
private static final String EXPANDABLE_UML = "<script type=\"text/javascript\">\n" + "function show() {\n"
|
||||
+ " document.getElementById(\"uml\").innerHTML = \n" + " \'<a style=\"" + EXPANDABLE_UML_STYLE
|
||||
+ "\" href=\"javascript:hide()\">%3$s</a>\' +\n" + " \'%1$s\';\n" + "}\n" + "function hide() {\n"
|
||||
+ " document.getElementById(\"uml\").innerHTML = \n" + " \'<a style=\"" + EXPANDABLE_UML_STYLE
|
||||
+ "\" href=\"javascript:show()\">%2$s</a>\' ;\n" + "}\n" + "</script>\n" + "<div id=\"uml\" >\n"
|
||||
+ " <a href=\"javascript:show()\">\n" + " <a style=\"" + EXPANDABLE_UML_STYLE
|
||||
+ "\" href=\"javascript:show()\">%2$s</a> \n" + "</div>";
|
||||
|
||||
/**
|
||||
* Takes an HTML file, looks for the first instance of the specified insertion point, and
|
||||
* inserts the diagram image reference and a client side map in that point.
|
||||
* Takes an HTML file, looks for the first instance of the specified insertion
|
||||
* point, and inserts the diagram image reference and a client side map in that
|
||||
* point.
|
||||
*/
|
||||
private static void alterHtmlDocs(Options opt, String outputFolder, String packageName, String className,
|
||||
String htmlFileName, Pattern insertPointPattern, RootDoc root) throws IOException {
|
||||
// setup files
|
||||
File output = new File(outputFolder, packageName.replace(".", "/"));
|
||||
File htmlFile = new File(output, htmlFileName);
|
||||
File alteredFile = new File(htmlFile.getAbsolutePath() + ".uml");
|
||||
if (!htmlFile.exists()) {
|
||||
System.err.println("Expected file not found: " + htmlFile.getAbsolutePath());
|
||||
return;
|
||||
}
|
||||
String htmlFileName, Pattern insertPointPattern, RootDoc root) throws IOException {
|
||||
// setup files
|
||||
File output = new File(outputFolder, packageName.replace(".", "/"));
|
||||
File htmlFile = new File(output, htmlFileName);
|
||||
File alteredFile = new File(htmlFile.getAbsolutePath() + ".uml");
|
||||
if (!htmlFile.exists()) {
|
||||
System.err.println("Expected file not found: " + htmlFile.getAbsolutePath());
|
||||
return;
|
||||
}
|
||||
|
||||
// parse & rewrite
|
||||
BufferedWriter writer = null;
|
||||
BufferedReader reader = null;
|
||||
boolean matched = false;
|
||||
try {
|
||||
writer = new BufferedWriter(new OutputStreamWriter(new
|
||||
FileOutputStream(alteredFile), opt.outputEncoding));
|
||||
reader = new BufferedReader(new InputStreamReader(new
|
||||
FileInputStream(htmlFile), opt.outputEncoding));
|
||||
// parse & rewrite
|
||||
BufferedWriter writer = null;
|
||||
BufferedReader reader = null;
|
||||
boolean matched = false;
|
||||
try {
|
||||
writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(alteredFile), opt.outputEncoding));
|
||||
reader = new BufferedReader(new InputStreamReader(new FileInputStream(htmlFile), opt.outputEncoding));
|
||||
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
writer.write(line);
|
||||
writer.newLine();
|
||||
if (!matched && insertPointPattern.matcher(line).matches()) {
|
||||
matched = true;
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
writer.write(line);
|
||||
writer.newLine();
|
||||
if (!matched && insertPointPattern.matcher(line).matches()) {
|
||||
matched = true;
|
||||
|
||||
String tag;
|
||||
if (opt.autoSize)
|
||||
tag = String.format(UML_AUTO_SIZED_DIV_TAG, className);
|
||||
else
|
||||
tag = String.format(UML_DIV_TAG, className);
|
||||
if (opt.collapsibleDiagrams)
|
||||
tag = String.format(EXPANDABLE_UML, tag, "Show UML class diagram", "Hide UML class diagram");
|
||||
writer.write("<!-- UML diagram added by UMLGraph version " +
|
||||
Version.VERSION +
|
||||
" (http://www.spinellis.gr/umlgraph/) -->");
|
||||
writer.newLine();
|
||||
writer.write(tag);
|
||||
writer.newLine();
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
if (writer != null)
|
||||
writer.close();
|
||||
if (reader != null)
|
||||
reader.close();
|
||||
}
|
||||
String tag;
|
||||
if (opt.autoSize)
|
||||
tag = String.format(UML_AUTO_SIZED_DIV_TAG, className);
|
||||
else
|
||||
tag = String.format(UML_DIV_TAG, className);
|
||||
if (opt.collapsibleDiagrams)
|
||||
tag = String.format(EXPANDABLE_UML, tag, "Show UML class diagram", "Hide UML class diagram");
|
||||
writer.write("<!-- UML diagram added by UMLGraph version " + Version.VERSION + " (http://www.spinellis.gr/umlgraph/) -->");
|
||||
writer.newLine();
|
||||
writer.write(tag);
|
||||
writer.newLine();
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
if (writer != null)
|
||||
writer.close();
|
||||
if (reader != null)
|
||||
reader.close();
|
||||
}
|
||||
|
||||
// if altered, delete old file and rename new one to the old file name
|
||||
if (matched) {
|
||||
htmlFile.delete();
|
||||
alteredFile.renameTo(htmlFile);
|
||||
} else {
|
||||
root.printNotice("Warning, could not find a line that matches the pattern '" + insertPointPattern.pattern()
|
||||
+ "'.\n Class diagram reference not inserted");
|
||||
alteredFile.delete();
|
||||
}
|
||||
// if altered, delete old file and rename new one to the old file name
|
||||
if (matched) {
|
||||
htmlFile.delete();
|
||||
alteredFile.renameTo(htmlFile);
|
||||
} else {
|
||||
root.printNotice("Warning, could not find a line that matches the pattern '"
|
||||
+ insertPointPattern.pattern() + "'.\n Class diagram reference not inserted");
|
||||
alteredFile.delete();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the output path specified on the javadoc options
|
||||
*/
|
||||
private static String findOutputPath(String[][] options) {
|
||||
for (int i = 0; i < options.length; i++) {
|
||||
if (options[i][0].equals("-d"))
|
||||
return options[i][1];
|
||||
}
|
||||
return ".";
|
||||
for (int i = 0; i < options.length; i++) {
|
||||
if (options[i][0].equals("-d"))
|
||||
return options[i][1];
|
||||
}
|
||||
return ".";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
/* Automatically generated file */
|
||||
package org.umlgraph.doclet;
|
||||
class Version { public static String VERSION = "R5_7_2-60-g0e99a6";}
|
||||
|
||||
class Version {
|
||||
public static String VERSION = "R5_7_2-60-g0e99a6";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ import com.sun.javadoc.Tag;
|
|||
* will lead to the creation of a UML class diagram. Multiple views can be
|
||||
* defined on the same source tree, effectively allowing to create multiple
|
||||
* class diagram out of it.
|
||||
*
|
||||
* @author wolf
|
||||
*
|
||||
* @depend - - - Options
|
||||
|
|
@ -53,121 +54,116 @@ public class View implements OptionProvider {
|
|||
* Builds a view given the class that contains its definition
|
||||
*/
|
||||
public View(RootDoc root, ClassDoc c, OptionProvider provider) {
|
||||
this.viewDoc = c;
|
||||
this.provider = provider;
|
||||
this.root = root;
|
||||
Tag[] tags = c.tags();
|
||||
ClassMatcher currMatcher = null;
|
||||
// parse options, get the global ones, and build a map of the
|
||||
// pattern matched overrides
|
||||
globalOptions = new ArrayList<String[]>();
|
||||
for (int i = 0; i < tags.length; i++) {
|
||||
if (tags[i].name().equals("@match")) {
|
||||
currMatcher = buildMatcher(tags[i].text());
|
||||
if(currMatcher != null) {
|
||||
optionOverrides.put(currMatcher, new ArrayList<String[]>());
|
||||
}
|
||||
} else if (tags[i].name().equals("@opt")) {
|
||||
String[] opts = StringUtil.tokenize(tags[i].text());
|
||||
opts[0] = "-" + opts[0];
|
||||
if (currMatcher == null) {
|
||||
globalOptions.add(opts);
|
||||
} else {
|
||||
optionOverrides.get(currMatcher).add(opts);
|
||||
}
|
||||
}
|
||||
}
|
||||
this.viewDoc = c;
|
||||
this.provider = provider;
|
||||
this.root = root;
|
||||
Tag[] tags = c.tags();
|
||||
ClassMatcher currMatcher = null;
|
||||
// parse options, get the global ones, and build a map of the
|
||||
// pattern matched overrides
|
||||
globalOptions = new ArrayList<String[]>();
|
||||
for (int i = 0; i < tags.length; i++) {
|
||||
if (tags[i].name().equals("@match")) {
|
||||
currMatcher = buildMatcher(tags[i].text());
|
||||
if (currMatcher != null) {
|
||||
optionOverrides.put(currMatcher, new ArrayList<String[]>());
|
||||
}
|
||||
} else if (tags[i].name().equals("@opt")) {
|
||||
String[] opts = StringUtil.tokenize(tags[i].text());
|
||||
opts[0] = "-" + opts[0];
|
||||
if (currMatcher == null) {
|
||||
globalOptions.add(opts);
|
||||
} else {
|
||||
optionOverrides.get(currMatcher).add(opts);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method that builds the appropriate matcher for @match tags
|
||||
*/
|
||||
private ClassMatcher buildMatcher(String tagText) {
|
||||
// check there are at least @match <type> and a parameter
|
||||
String[] strings = StringUtil.tokenize(tagText);
|
||||
if (strings.length < 2) {
|
||||
System.err.println("Skipping uncomplete @match tag, type missing: " + tagText + " in view " + viewDoc);
|
||||
return null;
|
||||
}
|
||||
// check there are at least @match <type> and a parameter
|
||||
String[] strings = StringUtil.tokenize(tagText);
|
||||
if (strings.length < 2) {
|
||||
System.err.println("Skipping uncomplete @match tag, type missing: " + tagText + " in view " + viewDoc);
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
if (strings[0].equals("class")) {
|
||||
return new PatternMatcher(Pattern.compile(strings[1]));
|
||||
} else if (strings[0].equals("context")) {
|
||||
return new ContextMatcher(root, Pattern.compile(strings[1]), getGlobalOptions(),
|
||||
false);
|
||||
} else if (strings[0].equals("outgoingContext")) {
|
||||
return new ContextMatcher(root, Pattern.compile(strings[1]), getGlobalOptions(),
|
||||
false);
|
||||
} else if (strings[0].equals("interface")) {
|
||||
return new InterfaceMatcher(root, Pattern.compile(strings[1]));
|
||||
} else if (strings[0].equals("subclass")) {
|
||||
return new SubclassMatcher(root, Pattern.compile(strings[1]));
|
||||
} else {
|
||||
System.err.println("Skipping @match tag, unknown match type, in view " + viewDoc);
|
||||
}
|
||||
} catch (PatternSyntaxException pse) {
|
||||
System.err.println("Skipping @match tag due to invalid regular expression '" + tagText
|
||||
+ "'" + " in view " + viewDoc);
|
||||
} catch (Exception e) {
|
||||
System.err.println("Skipping @match tag due to an internal error '" + tagText
|
||||
+ "'" + " in view " + viewDoc);
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
try {
|
||||
if (strings[0].equals("class")) {
|
||||
return new PatternMatcher(Pattern.compile(strings[1]));
|
||||
} else if (strings[0].equals("context")) {
|
||||
return new ContextMatcher(root, Pattern.compile(strings[1]), getGlobalOptions(), false);
|
||||
} else if (strings[0].equals("outgoingContext")) {
|
||||
return new ContextMatcher(root, Pattern.compile(strings[1]), getGlobalOptions(), false);
|
||||
} else if (strings[0].equals("interface")) {
|
||||
return new InterfaceMatcher(root, Pattern.compile(strings[1]));
|
||||
} else if (strings[0].equals("subclass")) {
|
||||
return new SubclassMatcher(root, Pattern.compile(strings[1]));
|
||||
} else {
|
||||
System.err.println("Skipping @match tag, unknown match type, in view " + viewDoc);
|
||||
}
|
||||
} catch (PatternSyntaxException pse) {
|
||||
System.err.println("Skipping @match tag due to invalid regular expression '" + tagText + "'" + " in view " + viewDoc);
|
||||
} catch (Exception e) {
|
||||
System.err.println("Skipping @match tag due to an internal error '" + tagText + "'" + " in view " + viewDoc);
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// OptionProvider methods
|
||||
// ----------------------------------------------------------------
|
||||
|
||||
public Options getOptionsFor(ClassDoc cd) {
|
||||
Options localOpt = getGlobalOptions();
|
||||
overrideForClass(localOpt, cd);
|
||||
localOpt.setOptions(cd);
|
||||
return localOpt;
|
||||
Options localOpt = getGlobalOptions();
|
||||
overrideForClass(localOpt, cd);
|
||||
localOpt.setOptions(cd);
|
||||
return localOpt;
|
||||
}
|
||||
|
||||
public Options getOptionsFor(String name) {
|
||||
Options localOpt = getGlobalOptions();
|
||||
overrideForClass(localOpt, name);
|
||||
return localOpt;
|
||||
Options localOpt = getGlobalOptions();
|
||||
overrideForClass(localOpt, name);
|
||||
return localOpt;
|
||||
}
|
||||
|
||||
public Options getGlobalOptions() {
|
||||
Options go = provider.getGlobalOptions();
|
||||
Options go = provider.getGlobalOptions();
|
||||
|
||||
boolean outputSet = false;
|
||||
for (String[] opts : globalOptions) {
|
||||
if (Options.matchOption(opts[0], "output"))
|
||||
outputSet = true;
|
||||
go.setOption(opts);
|
||||
}
|
||||
if (!outputSet)
|
||||
go.setOption(new String[] { "output", viewDoc.name() + ".dot" });
|
||||
boolean outputSet = false;
|
||||
for (String[] opts : globalOptions) {
|
||||
if (Options.matchOption(opts[0], "output"))
|
||||
outputSet = true;
|
||||
go.setOption(opts);
|
||||
}
|
||||
if (!outputSet)
|
||||
go.setOption(new String[] { "output", viewDoc.name() + ".dot" });
|
||||
|
||||
return go;
|
||||
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))
|
||||
opt.setOption(override);
|
||||
provider.overrideForClass(opt, cd);
|
||||
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))
|
||||
opt.setOption(override);
|
||||
provider.overrideForClass(opt, className);
|
||||
for (ClassMatcher cm : optionOverrides.keySet())
|
||||
if (cm.matches(className))
|
||||
for (String[] override : optionOverrides.get(cm))
|
||||
opt.setOption(override);
|
||||
}
|
||||
|
||||
public String getDisplayName() {
|
||||
return "view " + viewDoc.name();
|
||||
return "view " + viewDoc.name();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ 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 {
|
||||
|
|
@ -31,17 +32,17 @@ public enum Visibility {
|
|||
final public String symbol;
|
||||
|
||||
private Visibility(String symbol) {
|
||||
this.symbol = symbol;
|
||||
this.symbol = symbol;
|
||||
}
|
||||
|
||||
public static Visibility get(ProgramElementDoc doc) {
|
||||
if (doc.isPrivate())
|
||||
return PRIVATE;
|
||||
else if (doc.isPackagePrivate())
|
||||
return PACKAGE;
|
||||
else if (doc.isProtected())
|
||||
return PROTECTED;
|
||||
else
|
||||
return PUBLIC;
|
||||
if (doc.isPrivate())
|
||||
return PRIVATE;
|
||||
else if (doc.isPackagePrivate())
|
||||
return PACKAGE;
|
||||
else if (doc.isProtected())
|
||||
return PROTECTED;
|
||||
else
|
||||
return PUBLIC;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue