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.
22 # Group all api handlers in one router.
27 use
("/inheritance/:id", new APIInheritanceGraph(config
))
31 # Render a hierarchy graph for `mentity` if any.
32 class APIInheritanceGraph
35 redef fun get
(req
, res
) do
36 var pdepth
= req
.int_arg
("pdepth")
37 var cdepth
= req
.int_arg
("cdepth")
38 var mentity
= mentity_from_uri
(req
, res
)
39 if mentity
== null then
43 var g
= new InheritanceGraph(mentity
, view
)
44 res
.send g
.draw
(pdepth
, cdepth
).to_svg
48 # Graph for mentity hierarchies
50 # Recursively build parents and children list from a `center`.
51 class InheritanceGraph
54 # MEntity at the center of this graph
57 # ModelView used to filter graph
61 var graph
: DotGraph is lazy
do
62 var graph
= new DotGraph("package_diagram", "digraph")
64 graph
["compound"] = "true"
65 graph
["rankdir"] = "BT"
66 graph
["ranksep"] = 0.3
67 graph
["nodesep"] = 0.3
69 graph
.nodes_attrs
["margin"] = 0.1
70 graph
.nodes_attrs
["width"] = 0
71 graph
.nodes_attrs
["height"] = 0
72 graph
.nodes_attrs
["fontsize"] = 10
73 graph
.nodes_attrs
["fontname"] = "helvetica"
75 graph
.edges_attrs
["dir"] = "none"
76 graph
.edges_attrs
["color"] = "gray"
82 fun draw
(parents_depth
, children_depth
: nullable Int): DotGraph do
84 draw_parents
(center
, parents_depth
)
85 draw_children
(center
, children_depth
)
89 private var nodes
= new HashMap[MEntity, DotElement]
90 private var done_parents
= new HashSet[MEntity]
91 private var done_children
= new HashSet[MEntity]
93 # Recursively draw parents of mentity
94 fun draw_parents
(mentity
: MEntity, max_depth
: nullable Int, current_depth
: nullable Int) do
95 if done_parents
.has
(mentity
) then return
96 done_parents
.add mentity
97 current_depth
= current_depth
or else 0
98 if max_depth
!= null and current_depth
>= max_depth
then
99 from_dotdotdot
(mentity
)
102 var parents
= mentity
.collect_parents
(view
)
103 if parents
.length
> 10 then
104 from_dotdotdot
(mentity
)
107 for parent
in parents
do
108 if parent
isa MModule then
109 var mgroup
= parent
.mgroup
110 if mgroup
!= null and mgroup
.default_mmodule
== parent
then parent
= mgroup
112 if parent
isa MGroup then
113 if parent
.mpackage
.mgroups
.first
== parent
then parent
= parent
.mpackage
115 draw_edge
(mentity
, parent
)
117 for parent
in parents
do
118 if parent
isa MModule then
119 var mgroup
= parent
.mgroup
120 if mgroup
!= null and mgroup
.default_mmodule
== parent
then parent
= mgroup
122 if parent
isa MGroup then
123 if parent
.mpackage
.mgroups
.first
== parent
then parent
= parent
.mpackage
125 draw_parents
(parent
, max_depth
, current_depth
+ 1)
129 # Recursively draw children of mentity
130 fun draw_children
(mentity
: MEntity, max_depth
: nullable Int, current_depth
: nullable Int) do
131 if done_children
.has
(mentity
) then return
132 done_children
.add mentity
133 current_depth
= current_depth
or else 0
134 if max_depth
!= null and current_depth
>= max_depth
then
135 to_dotdotdot
(mentity
)
138 var children
= mentity
.collect_children
(view
)
139 if children
.length
> 10 then
140 to_dotdotdot
(mentity
)
143 for child
in children
do
144 if child
isa MGroup then
145 if child
.mpackage
.mgroups
.first
== child
then child
= child
.mpackage
147 draw_edge
(child
, mentity
)
149 for child
in children
do
150 if child
isa MGroup then
151 if child
.mpackage
.mgroups
.first
== child
then child
= child
.mpackage
153 draw_children
(child
, max_depth
, current_depth
+ 1)
157 # Draw a node from a `mentity`
158 fun draw_node
(mentity
: MEntity): DotElement do
159 if nodes
.has_key
(mentity
) then return nodes
[mentity
]
160 var node
: DotElement = mentity
.to_dot_node
161 if mentity
== center
then node
= highlight
(node
)
162 nodes
[mentity
] = node
167 private var edges
= new HashMap2[MEntity, MEntity, DotEdge]
169 # Draw a edges between two mentities
170 fun draw_edge
(from
, to
: MEntity): DotEdge do
171 if edges
.has
(from
, to
) then return edges
[from
, to
].as(not null)
172 if edges
.has
(to
, from
) then return edges
[to
, from
].as(not null)
173 var nfrom
= draw_node
(from
)
174 var nto
= draw_node
(to
)
175 var edge
= new DotEdge(nfrom
, nto
)
176 edges
[from
, to
] = edge
181 private var to_dots
= new HashMap[MEntity, DotElement]
183 # Create a link from `mentity` to a `...` node
184 fun to_dotdotdot
(mentity
: MEntity): DotEdge do
185 var nto
= draw_node
(mentity
)
186 var dots
= to_dots
.get_or_null
(mentity
)
188 dots
= dotdotdot
("{nto.id}...")
189 to_dots
[mentity
] = dots
192 var edge
= new DotEdge(dots
, nto
)
197 private var from_dots
= new HashMap[MEntity, DotElement]
199 # Create a link from a `...` node to a `mentity`
200 fun from_dotdotdot
(mentity
: MEntity): DotEdge do
201 var nfrom
= draw_node
(mentity
)
202 var dots
= to_dots
.get_or_null
(mentity
)
204 dots
= dotdotdot
("...{nfrom.id}")
205 from_dots
[mentity
] = dots
208 var edge
= new DotEdge(dots
, nfrom
)
213 # Change the border color of the node
214 fun highlight
(dot
: DotElement): DotElement do
215 dot
["color"] = "#1E9431"
219 # Generate a `...` node
220 fun dotdotdot
(id
: String): DotNode do
221 var node
= new DotNode(id
)
222 node
["label"] = "..."
223 node
["shape"] = "none"
229 private fun to_dot_node
: DotNode do
230 var node
= new DotNode(full_name
)
231 node
["URL"] = web_url
238 redef fun to_dot_node
do
240 node
["shape"] = "tab"
246 redef fun to_dot_node
do
248 node
["shape"] = "folder"
254 redef fun to_dot_node
do
256 node
["shape"] = "note"
262 redef fun to_dot_node
do
264 node
["shape"] = "box"