1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
7 # http://www.apache.org/licenses/LICENSE-2.0
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
15 # Render various graph from a model.
25 use
("/graph/inheritance/:id", new APIInheritanceGraph(config
))
29 # Render a hierarchy graph for `mentity` if any.
30 class APIInheritanceGraph
33 redef fun get
(req
, res
) do
34 var mentity
= mentity_from_uri
(req
, res
)
35 if mentity
== null then return
36 var pdepth
= req
.int_arg
("pdepth")
37 var cdepth
= req
.int_arg
("cdepth")
38 var g
= new InheritanceGraph(mentity
, config
.view
)
39 res
.send g
.draw
(pdepth
, cdepth
).to_svg
43 # Graph for mentity hierarchies
45 # Recursively build parents and children list from a `center`.
46 class InheritanceGraph
49 autoinit center
, view
, filter
51 # MEntity at the center of this graph
54 # ModelView used to filter graph
58 var graph
: DotGraph is lazy
do
59 var graph
= new DotGraph("package_diagram", "digraph")
61 graph
["compound"] = "true"
62 graph
["rankdir"] = "BT"
63 graph
["ranksep"] = 0.3
64 graph
["nodesep"] = 0.3
66 graph
.nodes_attrs
["margin"] = 0.1
67 graph
.nodes_attrs
["width"] = 0
68 graph
.nodes_attrs
["height"] = 0
69 graph
.nodes_attrs
["fontsize"] = 10
70 graph
.nodes_attrs
["fontname"] = "helvetica"
72 graph
.edges_attrs
["dir"] = "none"
73 graph
.edges_attrs
["color"] = "gray"
79 fun draw
(parents_depth
, children_depth
: nullable Int): DotGraph do
81 draw_parents
(center
, parents_depth
)
82 draw_children
(center
, children_depth
)
86 private var nodes
= new HashMap[MEntity, DotElement]
87 private var done_parents
= new HashSet[MEntity]
88 private var done_children
= new HashSet[MEntity]
90 # Recursively draw parents of mentity
91 fun draw_parents
(mentity
: MEntity, max_depth
: nullable Int, current_depth
: nullable Int) do
92 if done_parents
.has
(mentity
) then return
93 done_parents
.add mentity
94 current_depth
= current_depth
or else 0
95 if max_depth
!= null and current_depth
>= max_depth
then
96 from_dotdotdot
(mentity
)
99 var parents
= mentity
.collect_parents
(view
)
100 if parents
.length
> 10 then
101 from_dotdotdot
(mentity
)
104 for parent
in parents
do
105 if parent
isa MModule then
106 var mgroup
= parent
.mgroup
107 if mgroup
!= null and mgroup
.default_mmodule
== parent
then parent
= mgroup
109 if parent
isa MGroup then
110 if parent
.mpackage
.mgroups
.first
== parent
then parent
= parent
.mpackage
112 draw_edge
(mentity
, parent
)
114 for parent
in parents
do
115 if parent
isa MModule then
116 var mgroup
= parent
.mgroup
117 if mgroup
!= null and mgroup
.default_mmodule
== parent
then parent
= mgroup
119 if parent
isa MGroup then
120 if parent
.mpackage
.mgroups
.first
== parent
then parent
= parent
.mpackage
122 draw_parents
(parent
, max_depth
, current_depth
+ 1)
126 # Recursively draw children of mentity
127 fun draw_children
(mentity
: MEntity, max_depth
: nullable Int, current_depth
: nullable Int) do
128 if done_children
.has
(mentity
) then return
129 done_children
.add mentity
130 current_depth
= current_depth
or else 0
131 if max_depth
!= null and current_depth
>= max_depth
then
132 to_dotdotdot
(mentity
)
135 var children
= mentity
.collect_children
(view
)
136 if children
.length
> 10 then
137 to_dotdotdot
(mentity
)
140 for child
in children
do
141 if child
isa MGroup then
142 if child
.mpackage
.mgroups
.first
== child
then child
= child
.mpackage
144 draw_edge
(child
, mentity
)
146 for child
in children
do
147 if child
isa MGroup then
148 if child
.mpackage
.mgroups
.first
== child
then child
= child
.mpackage
150 draw_children
(child
, max_depth
, current_depth
+ 1)
154 # Draw a node from a `mentity`
155 fun draw_node
(mentity
: MEntity): DotElement do
156 if nodes
.has_key
(mentity
) then return nodes
[mentity
]
157 var node
: DotElement = mentity
.to_dot_node
158 if mentity
== center
then node
= highlight
(node
)
159 nodes
[mentity
] = node
164 private var edges
= new HashMap2[MEntity, MEntity, DotEdge]
166 # Draw a edges between two mentities
167 fun draw_edge
(from
, to
: MEntity): DotEdge do
168 if edges
.has
(from
, to
) then return edges
[from
, to
].as(not null)
169 if edges
.has
(to
, from
) then return edges
[to
, from
].as(not null)
170 var nfrom
= draw_node
(from
)
171 var nto
= draw_node
(to
)
172 var edge
= new DotEdge(nfrom
, nto
)
173 edges
[from
, to
] = edge
178 private var to_dots
= new HashMap[MEntity, DotElement]
180 # Create a link from `mentity` to a `...` node
181 fun to_dotdotdot
(mentity
: MEntity): DotEdge do
182 var nto
= draw_node
(mentity
)
183 var dots
= to_dots
.get_or_null
(mentity
)
185 dots
= dotdotdot
("{nto.id}...")
186 to_dots
[mentity
] = dots
189 var edge
= new DotEdge(dots
, nto
)
194 private var from_dots
= new HashMap[MEntity, DotElement]
196 # Create a link from a `...` node to a `mentity`
197 fun from_dotdotdot
(mentity
: MEntity): DotEdge do
198 var nfrom
= draw_node
(mentity
)
199 var dots
= to_dots
.get_or_null
(mentity
)
201 dots
= dotdotdot
("...{nfrom.id}")
202 from_dots
[mentity
] = dots
205 var edge
= new DotEdge(dots
, nfrom
)
210 # Change the border color of the node
211 fun highlight
(dot
: DotElement): DotElement do
212 dot
["color"] = "#1E9431"
216 # Generate a `...` node
217 fun dotdotdot
(id
: String): DotNode do
218 var node
= new DotNode(id
)
219 node
["label"] = "..."
220 node
["shape"] = "none"
226 private fun to_dot_node
: DotNode do
227 var node
= new DotNode(full_name
)
228 node
["URL"] = web_url
235 redef fun to_dot_node
do
237 node
["shape"] = "tab"
243 redef fun to_dot_node
do
245 node
["shape"] = "folder"
251 redef fun to_dot_node
do
253 node
["shape"] = "note"
259 redef fun to_dot_node
do
261 node
["shape"] = "box"