| [ Index ] |
|
Code source de Mantis 1.1.0rc3 |
1 <?php 2 # Mantis - a php based bugtracking system 3 4 # Copyright (C) 2000 - 2002 Kenzaburo Ito - kenito@300baud.org 5 # Copyright (C) 2002 - 2007 Mantis Team - mantisbt-dev@lists.sourceforge.net 6 7 # Mantis is free software: you can redistribute it and/or modify 8 # it under the terms of the GNU General Public License as published by 9 # the Free Software Foundation, either version 2 of the License, or 10 # (at your option) any later version. 11 # 12 # Mantis is distributed in the hope that it will be useful, 13 # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 # GNU General Public License for more details. 16 # 17 # You should have received a copy of the GNU General Public License 18 # along with Mantis. If not, see <http://www.gnu.org/licenses/>. 19 20 # -------------------------------------------------------- 21 # $Id: relationship_graph_api.php,v 1.6.2.1 2007-10-13 22:35:42 giallu Exp $ 22 # -------------------------------------------------------- 23 24 ### Relationship Graph API ### 25 26 $t_core_dir = dirname( __FILE__ ).DIRECTORY_SEPARATOR; 27 28 require_once ( $t_core_dir . 'relationship_api.php' ); 29 require_once ( $t_core_dir . 'graphviz_api.php' ); 30 31 # ================================================================ 32 # Author: Juliano Ravasi Ferraz <jferraz at users sourceforge net> 33 # ================================================================ 34 # 35 # This uses GraphViz utilities to generate relationship graphs for 36 # issues. Either GraphViz (for all OSs except Windows) or 37 # WinGraphviz (for Windows) must be installed in order to use this 38 # feature. 39 # 40 # Graphviz is available at: 41 # - http://www.graphviz.org/ 42 # - http://www.research.att.com/sw/tools/graphviz/ 43 # 44 # WinGraphviz is available at: 45 # - http://home.so-net.net.tw/oodtsen/wingraphviz/ 46 # 47 # Most Linux distributions already have a GraphViz package 48 # conveniently available for download and install. Refer to 49 # config_defaults_inc.php for how to enable this feature once 50 # GraphViz is installed. 51 52 # -------------------- 53 # Generate a relationship graph for the given issue. 54 function relgraph_generate_rel_graph( $p_bug_id, $p_bug = null ) { 55 56 # List of visited issues and their data. 57 $v_bug_list = array ( ); 58 $v_rel_list = array ( ); 59 60 # Queue for breadth-first 61 $v_queue = array ( ); 62 63 # Now we visit all related issues. 64 $t_max_depth = config_get( 'relationship_graph_max_depth' ); 65 66 # Put the first element into queue. 67 array_push( $v_queue, array ( 0, $p_bug_id ) ); 68 69 # And now we proccess it 70 while ( !empty( $v_queue ) ) { 71 list( $t_depth, $t_id ) = array_shift( $v_queue ); 72 73 if ( isset( $v_bug_list[$t_id] ) ) 74 continue; 75 76 if ( !bug_exists( $t_id ) ) 77 continue; 78 79 if ( !access_has_bug_level( VIEWER, $t_id ) ) 80 continue; 81 82 $v_bug_list[$t_id] = bug_prepare_display( bug_get( $t_id, false ) ); 83 84 $t_relationships = relationship_get_all_src( $t_id ); 85 foreach ( $t_relationships as $t_relationship ) { 86 $t_dst = $t_relationship->dest_bug_id; 87 if ( BUG_DEPENDANT == $t_relationship->type ) { 88 $v_rel_list[$t_id][$t_dst] = BUG_DEPENDANT; 89 $v_rel_list[$t_dst][$t_id] = BUG_BLOCKS; 90 } else { 91 $v_rel_list[$t_id][$t_dst] = $t_relationship->type; 92 $v_rel_list[$t_dst][$t_id] = $t_relationship->type; 93 } 94 95 if ( $t_depth < $t_max_depth ) 96 array_push( $v_queue, array ( $t_depth + 1, $t_dst ) ); 97 } 98 99 $t_relationships = relationship_get_all_dest( $t_id ); 100 foreach ( $t_relationships as $t_relationship ) { 101 $t_dst = $t_relationship->src_bug_id; 102 if ( BUG_DEPENDANT == $t_relationship->type ) { 103 $v_rel_list[$t_id][$t_dst] = BUG_BLOCKS; 104 $v_rel_list[$t_dst][$t_id] = BUG_DEPENDANT; 105 } else { 106 $v_rel_list[$t_id][$t_dst] = $t_relationship->type; 107 $v_rel_list[$t_dst][$t_id] = $t_relationship->type; 108 } 109 110 if ( $t_depth < $t_max_depth ) 111 array_push( $v_queue, array ( $t_depth + 1, $t_dst ) ); 112 } 113 } 114 115 # We have already collected all the information we need to generate 116 # the graph. Now it is the matter to create a Digraph object and 117 # store the information there, along with graph formatting attributes. 118 $t_id_string = bug_format_id( $p_bug_id ); 119 $t_graph_fontname = config_get( 'relationship_graph_fontname' ); 120 $t_graph_fontsize = config_get( 'relationship_graph_fontsize' ); 121 $t_graph_fontpath = config_get( 'system_font_folder' ); 122 $t_view_on_click = config_get( 'relationship_graph_view_on_click' ); 123 $t_neato_tool = config_get( 'neato_tool' ); 124 125 $t_graph_attributes = array ( ); 126 127 if ( !empty( $t_graph_fontpath ) ) 128 $t_graph_attributes['fontpath'] = $t_graph_fontpath; 129 130 $t_graph = new Graph( $t_id_string, $t_graph_attributes, $t_neato_tool ); 131 132 $t_graph->set_default_node_attr( array ( 133 'fontname' => $t_graph_fontname, 134 'fontsize' => $t_graph_fontsize, 135 'shape' => 'record', 136 'style' => 'filled', 137 'height' => '0.2', 138 'width' => '0.4' 139 ) ); 140 141 $t_graph->set_default_edge_attr( array ( 142 'style' => 'solid', 143 'color' => '#0000C0', 144 'dir' => 'none' 145 ) ); 146 147 # Add all issue nodes and edges to the graph. 148 ksort( $v_bug_list ); 149 foreach ( $v_bug_list as $t_id => $t_bug ) { 150 $t_id_string = bug_format_id( $t_id ); 151 152 if ( $t_view_on_click ) 153 $t_url = string_get_bug_view_url( $t_id ); 154 else 155 $t_url = 'bug_relationship_graph.php?bug_id=' . $t_id . '&graph=relation'; 156 157 relgraph_add_bug_to_graph( $t_graph, $t_id_string, $t_bug, 158 $t_url, $t_id == $p_bug_id ); 159 160 # Now add all relationship edges to the graph. 161 if ( isset( $v_rel_list[$t_id] ) ) { 162 foreach ( $v_rel_list[$t_id] as $t_dst => $t_relation ) { 163 # Do not create edges for unvisited bugs. 164 if ( !isset( $v_bug_list[$t_dst] ) ) 165 continue; 166 167 # avoid double links 168 if ( $t_dst < $t_id ) 169 continue; 170 171 $t_related_id = bug_format_id( $t_dst ); 172 173 global $g_relationships; 174 if ( isset( $g_relationships[ $t_relation ] ) && isset( $g_relationships[ $t_relation ][ '#edge_style' ] ) ) { 175 $t_edge_style = $g_relationships[ $t_relation ][ '#edge_style' ]; 176 } else { 177 $t_edge_style = array ( ); 178 } 179 180 $t_graph->add_edge( $t_id_string, $t_related_id, $t_edge_style ); 181 } 182 } 183 } 184 185 return $t_graph; 186 } 187 188 189 # -------------------- 190 # Generate a dependency relationship graph for the given issue. 191 function relgraph_generate_dep_graph( $p_bug_id, $p_bug = null, $p_horizontal = false ) { 192 193 # List of visited issues and their data. 194 $v_bug_list = array ( ); 195 196 # Firstly, we visit all ascendant issues and all descendant issues 197 # and collect all the necessary data in the $v_bug_list variable. 198 # We do not visit other descendants of our parents, neither other 199 # ascendants of our children, to avoid displaying too much unrelated 200 # issues. We still collect the information about those relationships, 201 # so, if these issues happen to be visited also, relationship links 202 # will be preserved. 203 204 # The first issue in the list is the one we are parting from. 205 if ( null === $p_bug ) 206 $p_bug = bug_prepare_display( bug_get( $p_bug_id, true ) ); 207 208 $v_bug_list[$p_bug_id] = $p_bug; 209 $v_bug_list[$p_bug_id]->is_descendant = true; 210 $v_bug_list[$p_bug_id]->parents = array ( ); 211 $v_bug_list[$p_bug_id]->children = array ( ); 212 213 # Now we visit all ascendants of the root issue. 214 $t_relationships = relationship_get_all_dest( $p_bug_id ); 215 foreach ( $t_relationships as $t_relationship ) { 216 if ( $t_relationship->type != BUG_DEPENDANT ) 217 continue; 218 219 $v_bug_list[$p_bug_id]->parents[] = $t_relationship->src_bug_id; 220 relgraph_add_parent( $v_bug_list, $t_relationship->src_bug_id ); 221 } 222 223 $t_relationships = relationship_get_all_src( $p_bug_id ); 224 foreach ( $t_relationships as $t_relationship ) { 225 if ( $t_relationship->type != BUG_DEPENDANT ) 226 continue; 227 228 $v_bug_list[$p_bug_id]->children[] = $t_relationship->dest_bug_id; 229 relgraph_add_child( $v_bug_list, $t_relationship->dest_bug_id ); 230 } 231 232 # We have already collected all the information we need to generate 233 # the graph. Now it is the matter to create a Digraph object and 234 # store the information there, along with graph formatting attributes. 235 $t_id_string = bug_format_id( $p_bug_id ); 236 $t_graph_fontname = config_get( 'relationship_graph_fontname' ); 237 $t_graph_fontsize = config_get( 'relationship_graph_fontsize' ); 238 $t_graph_fontpath = config_get( 'system_font_folder' ); 239 $t_view_on_click = config_get( 'relationship_graph_view_on_click' ); 240 $t_dot_tool = config_get( 'dot_tool' ); 241 242 $t_graph_attributes = array ( ); 243 244 if ( !empty( $t_graph_fontpath ) ) 245 $t_graph_attributes['fontpath'] = $t_graph_fontpath; 246 247 if ( $p_horizontal ) { 248 $t_graph_attributes['rankdir'] = 'LR'; 249 $t_graph_orientation = 'horizontal'; 250 } else { 251 $t_graph_orientation = 'vertical'; 252 } 253 254 $t_graph = new Digraph( $t_id_string, $t_graph_attributes, $t_dot_tool ); 255 256 $t_graph->set_default_node_attr( array ( 257 'fontname' => $t_graph_fontname, 258 'fontsize' => $t_graph_fontsize, 259 'shape' => 'record', 260 'style' => 'filled', 261 'height' => '0.2', 262 'width' => '0.4' 263 ) ); 264 265 $t_graph->set_default_edge_attr( array ( 266 'style' => 'solid', 267 'color' => '#C00000', 268 'dir' => 'back' 269 ) ); 270 271 # Add all issue nodes and edges to the graph. 272 foreach ( $v_bug_list as $t_related_bug_id => $t_related_bug ) { 273 $t_id_string = bug_format_id( $t_related_bug_id ); 274 275 if ( $t_view_on_click ) 276 $t_url = string_get_bug_view_url( $t_related_bug_id ); 277 else 278 $t_url = 'bug_relationship_graph.php?bug_id=' . $t_related_bug_id . '&graph=dependency&orientation=' . $t_graph_orientation; 279 280 relgraph_add_bug_to_graph( $t_graph, $t_id_string, $t_related_bug, 281 $t_url, $t_related_bug_id == $p_bug_id ); 282 283 # Now add all relationship edges to the graph. 284 foreach ( $v_bug_list[$t_related_bug_id]->parents as $t_parent_id ) { 285 # Do not create edges for unvisited bugs. 286 if ( !isset( $v_bug_list[$t_parent_id] ) ) 287 continue; 288 289 $t_parent_node = bug_format_id( $t_parent_id ); 290 $t_graph->add_edge( $t_parent_node, $t_id_string ); 291 } 292 } 293 294 return $t_graph; 295 } 296 297 298 # -------------------- 299 # Internal function used to visit ascendant issues recursively. 300 function relgraph_add_parent( &$p_bug_list, $p_bug_id ) { 301 302 # If the issue is already in the list, we already visited it, just 303 # leave. 304 if ( isset( $p_bug_list[$p_bug_id] ) ) 305 return true; 306 307 # Check if the issue really exists and we have access to it. If not, 308 # it is like it didn't exist. 309 if ( !bug_exists( $p_bug_id ) ) 310 return false; 311 312 if ( !access_has_bug_level( VIEWER, $p_bug_id ) ) 313 return false; 314 315 # Add the issue to the list. 316 $p_bug_list[$p_bug_id] = bug_prepare_display( bug_get( $p_bug_id, false ) ); 317 $p_bug_list[$p_bug_id]->is_descendant = false; 318 $p_bug_list[$p_bug_id]->parents = array ( ); 319 $p_bug_list[$p_bug_id]->children = array ( ); 320 321 # Add all parent issues to the list of parents and visit them 322 # recursively. 323 $t_relationships = relationship_get_all_dest( $p_bug_id ); 324 foreach ( $t_relationships as $t_relationship ) { 325 if ( $t_relationship->type != BUG_DEPENDANT ) 326 continue; 327 328 $p_bug_list[$p_bug_id]->parents[] = $t_relationship->src_bug_id; 329 relgraph_add_parent( $p_bug_list, $t_relationship->src_bug_id ); 330 } 331 332 # Add all child issues to the list of children. Do not visit them 333 # since this will add too much data that is unrelated to the original 334 # issue, and has a potential to generate really huge graphs. 335 $t_relationships = relationship_get_all_src( $p_bug_id ); 336 foreach ( $t_relationships as $t_relationship ) { 337 if ( $t_relationship->type != BUG_DEPENDANT ) 338 continue; 339 340 $p_bug_list[$p_bug_id]->children[] = $t_relationship->dest_bug_id; 341 } 342 343 return true; 344 } 345 346 347 # -------------------- 348 # Internal function used to visit descendant issues recursively. 349 function relgraph_add_child( &$p_bug_list, $p_bug_id ) { 350 351 # Check if the issue is already in the issue list. 352 if ( isset( $p_bug_list[$p_bug_id] ) ) { 353 354 # The issue is in the list, but we cannot discard it since it 355 # may be a parent issue (whose children were not visited). 356 357 if ( !$p_bug_list[$p_bug_id]->is_descendant ) { 358 # Yes, we visited this issue as a parent... This is the case 359 # where someone set up a cyclic relationship (I really hope 360 # nobody ever do this, but should keep sanity) for this 361 # issue. We just have to finish the job, visiting all issues 362 # that were already listed by _add_parent(). 363 $p_bug_list[$p_bug_id]->is_descendant = true; 364 365 foreach ( $p_bug_list[$p_bug_id]->children as $t_child ) 366 relgraph_add_child( $p_bug_id, $t_child ); 367 } 368 } else { 369 # The issue is not in the list, proceed as usual. 370 371 # Check if the issue really exists and we have access to it. 372 # If not, it is like it didn't exist. 373 if ( !bug_exists( $p_bug_id ) ) 374 return false; 375 376 if ( !access_has_bug_level( VIEWER, $p_bug_id ) ) 377 return false; 378 379 # Add the issue to the list. 380 $p_bug_list[$p_bug_id] = bug_prepare_display( bug_get( $p_bug_id, false ) ); 381 $p_bug_list[$p_bug_id]->is_descendant = true; 382 $p_bug_list[$p_bug_id]->parents = array ( ); 383 $p_bug_list[$p_bug_id]->children = array ( ); 384 385 # Add all parent issues to the list of parents. Do not visit them 386 # for the same reason we didn't visit the children of all 387 # ancestors. 388 $t_relationships = relationship_get_all_dest( $p_bug_id ); 389 foreach ( $t_relationships as $t_relationship ) { 390 if ( $t_relationship->type != BUG_DEPENDANT ) 391 continue; 392 393 $p_bug_list[$p_bug_id]->parents[] = $t_relationship->src_bug_id; 394 } 395 396 # Add all child issues to the list of children and visit them 397 # recursively. 398 $t_relationships = relationship_get_all_src( $p_bug_id ); 399 foreach ( $t_relationships as $t_relationship ) { 400 if ( $t_relationship->type != BUG_DEPENDANT ) 401 continue; 402 403 $p_bug_list[$p_bug_id]->children[] = $t_relationship->dest_bug_id; 404 relgraph_add_child( $p_bug_list, $t_relationship->dest_bug_id ); 405 } 406 } 407 408 return true; 409 } 410 411 412 # -------------------- 413 # Outputs a png image for the given relationship graph, previously 414 # generated by relgraph_generate_graph_for_bug(). 415 function relgraph_output_image( $p_graph ) { 416 $p_graph->output( 'png', true ); 417 } 418 419 420 # -------------------- 421 # Outputs an image map in HTML form (too bad dot didn't output XHTML...) 422 # for the given relationship graph, previously generated by 423 # relgraph_generate_graph_for_bug(). 424 function relgraph_output_map( $p_graph, $p_name ) { 425 echo '<map name="' . $p_name . '">' . "\n"; 426 $p_graph->output( 'cmap' ); 427 echo '</map>' . "\n"; 428 } 429 430 431 # -------------------- 432 # Internal function used to add a bug to the given graph. 433 function relgraph_add_bug_to_graph( &$p_graph, $p_bug_id, $p_bug, $p_url = null, $p_highlight = false ) { 434 $t_node_attributes = array ( ); 435 $t_node_attributes['label'] = $p_bug_id; 436 437 if ( $p_highlight ) { 438 $t_node_attributes['color'] = '#0000FF'; 439 $t_node_attributes['style'] = 'bold, filled'; 440 } else { 441 $t_node_attributes['color'] = 'black'; 442 $t_node_attributes['style'] = 'filled'; 443 } 444 445 $t_node_attributes['fillcolor'] = get_status_color( $p_bug->status ); 446 447 if ( null !== $p_url ) 448 $t_node_attributes['URL'] = $p_url; 449 450 $t_summary = $p_bug->summary; 451 $t_status = get_enum_element( 'status', $p_bug->status ); 452 $t_node_attributes['tooltip'] = '[' . $t_status . '] ' . $t_summary; 453 454 $p_graph->add_node( $p_bug_id, $t_node_attributes ); 455 } 456 457 ?>
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
| Généré le : Thu Nov 29 09:42:17 2007 | par Balluche grâce à PHPXref 0.7 |
|