nitc :: MPackageDot :: defaultinit
# Generate graphiz files based on packages, groups and modules
#
# Interesting elements must be selected. See `mmodules`, ``
# Display configuration can be set. See `cluster_group`, `package_group`
class MPackageDot
super Writable
# The model where to look for information
var model: Model
# Set of packages to expand fully (ie all groups and modules are displayed)
# Initially empty, packages can be added
var mpackages = new HashSet[MPackage]
# Set of modules to display
# Initially empty, modules can be added
var mmodules = new HashSet[MModule]
private fun node_for(mmodule: MModule): String
do
return "m_{mmodule.object_id}"
end
# Should groups be shown as clusters?
var cluster_group = true is writable
# Should packages be shown as clusters?
var package_group = true is writable
# Recursively generate node and clusters for a mgroup
private fun dot_cluster(o: Writer, mgroup: MGroup)
do
# Open the cluster, if required
if mgroup.parent == null then
# is is a root group, so display the package
if package_group then
o.write("subgraph cluster_{mgroup.object_id} \{\nlabel=\"{mgroup.mpackage.name}\\n({mgroup.filepath or else "?"})\"\ncolor=black\nstyle=dotted\n")
end
else
if cluster_group then
o.write("subgraph cluster_{mgroup.object_id} \{\nlabel=\"{mgroup.name}\"\ncolor=blue\nstyle=dotted\n")
end
end
# outputs the mmodules to show
for mmodule in mgroup.mmodules do
if not mmodules.has(mmodule) then continue
o.write("\t{node_for(mmodule)} [label=\"{mmodule.name}\",color=green]\n")
end
# recursively progress on sub-clusters
for d in mgroup.in_nesting.direct_smallers do
dot_cluster(o, d)
end
# close the cluster if required
if mgroup.parent == null then
if package_group then o.write("\}\n")
else
if cluster_group then o.write("\}\n")
end
end
# Extends the set of `mmodules` by recursively adding the most specific imported modules of foreign packages
fun collect_important_importation
do
var todo = new List[MModule]
todo.add_all(mmodules)
while not todo.is_empty do
var m = todo.pop
for psm in m.in_importation.greaters do
if m.mgroup.mpackage != psm.mgroup.mpackage then continue
for ssm in psm.in_importation.direct_greaters do
if psm.mgroup.mpackage == ssm.mgroup.mpackage then continue
mmodules.add(ssm)
todo.add(ssm)
end
end
end
end
# Generate the dot content with the current configuration
redef fun write_to(stream)
do
# Collect interesting nodes
for m in model.mmodules do
# filter out modules outside wanted packages
if m.mgroup == null then continue
if not mpackages.has(m.mgroup.mpackage) then continue
mmodules.add(m)
end
collect_important_importation
# Collect interesting edges
var sub_hierarchy = new POSet[MModule]
for m in mmodules do
sub_hierarchy.add_node(m)
for sm in m.in_importation.greaters do
if sm == m then continue
if not mmodules.has(sm) then continue
sub_hierarchy.add_edge(m, sm)
end
end
stream.write("digraph g \{\n")
stream.write("rankdir=BT;node[shape=box];\n")
# Generate the nodes
for p in model.mpackages do
dot_cluster(stream, p.root.as(not null))
end
# Generate the edges
for m in mmodules do
for sm in sub_hierarchy[m].direct_greaters do
var nm = node_for(m)
var nsm = node_for(sm)
if m.in_importation.direct_greaters.has(sm) then
stream.write("\t{nm} -> {nsm}[style=bold]\n")
else
stream.write("\t{nm} -> {nsm}[style=solid]\n")
end
end
end
stream.write("\}\n")
end
end
src/model/model_viz.nit:132,1--259,3