1# 2# Tcl Library for TkCVS 3# 4 5namespace eval joincanvas { 6 variable instance 0 7 8 proc new {localfile filelog {current_tagname {}}} { 9 variable instance 10 set my_idx $instance 11 incr instance 12 13 if {[catch "image type Modules"]} { 14 workdir_images 15 } 16 if {[catch "image type Workdir"]} { 17 modbrowse_images 18 } 19 20 # 21 # Creates a new log canvas. filelog must be the output of a cvs 22 # log or rlog command. 23 # 24 namespace eval $my_idx { 25 set my_idx [uplevel {concat $my_idx}] 26 set filelog [uplevel {concat $filelog}] 27 variable localfile [uplevel {concat $localfile}] 28 variable current_tagname [uplevel {concat $current_tagname}] 29 30 global cvscfg 31 global cvsglb 32 global cvs 33 global tcl_platform 34 35 # Height and width to draw boxes 36 variable cvscanv 37 set cvscanv(boxx) 60 38 set cvscanv(boxy) 20 39 set cvscanv(midx) [expr {$cvscanv(boxx) / 2}] 40 set cvscanv(midy) [expr {$cvscanv(boxy) / 2}] 41 set cvscanv(boxmin) 64 42 # Gaps between boxes 43 set cvscanv(space) [expr {$cvscanv(boxy) + 16}] 44 # Indent at top left of canvas 45 set cvscanv(indx) 5 46 set cvscanv(indy) 5 47 # Static type variables used while drawing on the canvas. 48 set cvscanv(xhigh) 0 49 set cvscanv(yhigh) 0 50 set cvscanv(xlow) 0 51 set cvscanv(ylow) 0 52 53 variable revlist 54 variable revbranches 55 variable tags 56 variable headrev 57 variable joincanvas 58 59 set joincanvas ".joincanvas$my_idx" 60 61 proc parse_cvslog_tags {filelog} { 62 variable joincanvas 63 variable tags 64 variable headrev 65 66 gen_log:log T "ENTER ($joincanvas ...)" 67 set loglist [split $filelog "\n"] 68 set logstate "rcsfile" 69 foreach logline $loglist { 70 #puts "$logline" 71 switch -exact -- $logstate { 72 "rcsfile" { 73 # Look for the first text line which should give the file name. 74 set fileline [split $logline] 75 if {[lindex $fileline 0] == "RCS"} { 76 set logstate "head" 77 continue 78 } 79 } 80 "head" { 81 set fileline [split $logline] 82 if {[lindex $fileline 0] == "head:"} { 83 set headrev [lindex $fileline 1] 84 set logstate "tags" 85 set taglist "" 86 continue 87 } 88 } 89 "tags" { 90 # Any line with a tab leader is a tag 91 if { [string index $logline 0] == "\t" } { 92 set taglist "$taglist$logline\n" 93 set tagitems [split $logline ":"] 94 set tagrevision [string trim [lindex $tagitems 1]] 95 set tagname [string trim [lindex $tagitems 0]] 96 # Add all the tags to a picklist for our "since" tag 97 ::picklist::used alltags $tagname 98 99 set parts [split $tagrevision {.}] 100 if {[expr {[llength $parts] & 1}] == 1} { 101 set parts [linsert $parts end-1 {0}] 102 set tagrevision [join $parts {.}] 103 } 104 # But we only want to know the branch tags 105 if { [regexp {\.0\.\d+$} $tagrevision] } { 106 set tagstring [string trim [lindex $tagitems 0]] 107 lappend tags($tagrevision) $tagstring 108 } 109 } else { 110 if {$logline == "description:"} { 111 # No more tags after this point 112 set logstate "searching" 113 continue 114 } 115 if {$logline == "----------------------------"} { 116 # Oops, missed something. 117 set logstate "revision" 118 continue 119 } 120 } 121 } 122 "terminated" { 123 # ignore any further lines 124 continue 125 } 126 } 127 } 128 ::picklist::used alltags "" 129 } 130 131 proc node {joincanvas rev x y} { 132 global cvscfg 133 variable cvscanv 134 variable tags 135 upvar treelist treelist 136 upvar ylevel ylevel 137 upvar ind ind 138 139 gen_log:log T "ENTER ($rev $x $y)" 140 $joincanvas.canvas create line \ 141 $x [expr {$y + $cvscanv(boxy)}] \ 142 $x [expr {$y + $cvscanv(space)}] 143 144 gen_log:log T "LEAVE" 145 } 146 147 proc rectangle {joincanvas rev x y} { 148 # 149 # Breaks out some of the code from the joincanvas_draw_box procedure. 150 # Work out the width of the text to go in the box first, then draw a 151 # box wide enough. 152 # 153 global cvscfg 154 variable cvscanv 155 variable tags 156 variable current_tagname 157 upvar x xpos 158 159 gen_log:log T "ENTER ($rev $x $y)" 160 161 set parts [split $rev "."] 162 163 set tagtext $tags($rev) 164 gen_log:log D "$tagtext\t$rev" 165 $joincanvas.canvas create text \ 166 [expr {$x + 4}] [expr {$y + 2}] \ 167 -text "$tagtext" \ 168 -anchor nw -fill blue \ 169 -font {Helvetica -12 bold} \ 170 -tags b$rev 171 172 set tagwidth [font measure {Helvetica -12 bold} \ 173 -displayof $joincanvas.canvas $tagtext] 174 if {$tagwidth < $cvscanv(boxmin)} { set tagwidth $cvscanv(boxmin) } 175 176 # draw the box 177 set boxid [$joincanvas.canvas create rectangle \ 178 $x $y \ 179 [expr {$x + $tagwidth + 5}] [expr {$y + $cvscanv(boxy)}] \ 180 -width 3 \ 181 -fill gray90 \ 182 -tags [list b$rev rect$rev] \ 183 ] 184 # Drop the fill color below the text so the text isn't hidden 185 $joincanvas.canvas lower $boxid 186 187 # Bind button-presses to the rectangles. 188 if {$tags($rev) != ""} { 189 $joincanvas.canvas bind b$rev <ButtonPress-1> \ 190 [namespace code "select_rectangle $rev $tags($rev)"] 191 } 192 193 if {"$current_tagname" == "$tagtext"} { 194 you_are_here $rev $tagwidth $x $y 195 } 196 gen_log:log T "LEAVE" 197 } 198 199 proc unselect_all {} { 200 variable joincanvas 201 set t [$joincanvas.canvas gettags current] 202 if {$t != {} } {return} 203 unselect_rectangle 204 } 205 206 proc unselect_rectangle {} { 207 variable joincanvas 208 catch {$joincanvas.canvas itemconfigure SelA -fill gray90} 209 $joincanvas.up.rversFrom delete 0 end 210 $joincanvas.canvas dtag SelA 211 } 212 213 proc select_rectangle {rev tags} { 214 global cvscfg 215 variable joincanvas 216 217 gen_log:log T "ENTER ($rev $tags)" 218 219 unselect_rectangle 220 $joincanvas.up.rversFrom delete 0 end 221 $joincanvas.up.rversFrom insert end $tags 222 $joincanvas.canvas addtag SelA withtag rect$rev 223 $joincanvas.canvas itemconfigure SelA -fill $cvscfg(colourA) 224 } 225 226 proc fillcanvas {filename filelog} { 227 global cvscfg 228 variable joincanvas 229 variable cvscanv 230 variable headrev 231 variable tags 232 variable current_tagname 233 234 gen_log:log T "ENTER ($filename <filelog suppressed>)" 235 236 catch {unset tags} 237 # Collect the history from the RCS log 238 $joincanvas.canvas delete all 239 parse_cvslog_tags $filelog 240 241 # Sort the branch revisions 242 set tagrevlist [lsort -command sortrevs [array names tags]] 243 # Get rid of duplicates 244 set revlist "" 245 foreach t $tagrevlist { 246 if {[lsearch -exact $revlist $t] < 0} { 247 lappend revlist $t 248 } 249 } 250 251 # Find everybody's parents. Add parent nodes to a new nodelist. 252 # Keep track of everybody's children 253 set treelist "" 254 foreach rev $revlist { 255 gen_log:log D "$rev" 256 # Find its parent 257 set alist [split $rev "."] 258 set alength [llength $alist] 259 set isodd [expr {$alength % 2}] 260 set parent($rev) [join [lrange $alist 0 [expr {$alength - 3}]] "."] 261 #gen_log:log D " parent $parent($rev)" 262 set parentbranch [join [lrange $alist 0 [expr {$alength - 5}]] "."] 263 #gen_log:log D " parentbrancch $parentbranch" 264 set branchnum [lindex $alist [expr {$alength - 4}]] 265 set branchparent [join [list $parentbranch 0 $branchnum] "."] 266 #gen_log:log D " branchparent $branchparent" 267 if {$isodd > 0} { 268 set parent($rev) [join [lrange $alist 0 [expr {$alength - 2}]] "."] 269 #gen_log:log D " parent $parent($rev)" 270 } 271 if {[string length $parentbranch] > 0} { 272 gen_log:log D "set parent parent($rev)" 273 set parent($rev) $branchparent 274 lappend children($branchparent) $rev 275 } else { 276 lappend children($parent($rev)) $rev 277 } 278 # Add to new list of nodes 279 if {[lsearch -exact $revlist $parent($rev)] < 0 && \ 280 [lsearch -exact $treelist $parent($rev)] < 0 } { 281 lappend treelist $parent($rev) 282 gen_log:log D " add parent $parent($rev) of $rev" 283 } 284 } 285 # Do it all over again for the new ones we added 286 foreach rev $treelist { 287 gen_log:log D "new $rev" 288 # Find its parent 289 set alist [split $rev "."] 290 set alength [llength $alist] 291 set isodd [expr {$alength % 2}] 292 set parent($rev) [join [lrange $alist 0 [expr {$alength - 3}]] "."] 293 #gen_log:log D " parent $parent($rev)" 294 set parentbranch [join [lrange $alist 0 [expr {$alength - 5}]] "."] 295 #gen_log:log D " parentbrancch $parentbranch" 296 set branchnum [lindex $alist [expr {$alength - 4}]] 297 set branchparent [join [list $parentbranch 0 $branchnum] "."] 298 #gen_log:log D " branchparent $branchparent" 299 if {$isodd > 0} { 300 set parent($rev) [join [lrange $alist 0 [expr {$alength - 2}]] "."] 301 #gen_log:log D " parent $parent($rev)" 302 } 303 if {[string length $parentbranch] > 0} { 304 gen_log:log D "set parent parent($rev)" 305 set parent($rev) $branchparent 306 lappend children($branchparent) $rev 307 } else { 308 lappend children($parent($rev)) $rev 309 } 310 } 311 set treelist [concat $revlist $treelist] 312 set treelist [lsort -command sortrevs $treelist] 313 314 # Now prepare to draw the revision tree 315 # Root first 316 set y $cvscanv(space) 317 set px(0) 10 318 set x [font measure {Helvetica -12 bold} \ 319 -displayof $joincanvas.canvas $cvscfg(mergetrunkname)] 320 321 set px(1) [expr {$px(0) + $x / 2}] 322 set py(1) [expr {$cvscanv(boxy) - 4}] 323 324 $joincanvas.canvas create text \ 325 $px(1) $y \ 326 -text "ROOT" \ 327 -anchor n -fill black \ 328 -font {Helvetica -12 bold} 329 330 # Then the rest 331 foreach rev $treelist { 332 gen_log:log D "$rev" 333 if {[info exists children($rev)]} { 334 foreach r $children($rev) { 335 gen_log:log D "\tparent of $r" 336 } 337 set nchildren($rev) [llength $children($rev)] 338 set kids [array names children $rev.*] 339 foreach kid $kids { 340 set descendents $children($kid) 341 set ndescendents [llength $descendents] 342 gen_log:log D "\tgranchildren: $descendents" 343 incr nchildren($rev) $ndescendents 344 } 345 } else { 346 set nchildren($rev) 0 347 } 348 gen_log:log D "\t$nchildren($rev) descendents" 349 if {[info exists parent($rev)]} { 350 gen_log:log D "\tchild of $parent($rev)" 351 } 352 353 set alist [split $rev "."] 354 set alength [llength $alist] 355 # Round up instead of down 356 set ind [expr {($alength +1)/ 2}] 357 set pind [expr {$ind - 1}] 358 359 if {! [info exists py($ind)]} { 360 gen_log:log D " starting new column $ind" 361 set py($ind) $cvscanv(space) 362 set px($ind) [expr {$px($pind) + $cvscanv(midx) + $cvscanv(space)}] 363 } 364 if {[info exists parent($rev)] && $parent($rev) != ""} { 365 gen_log:log D " this one has a parent in col >=1" 366 if {[info exists ylevel($parent($rev))] && $py($ind) > $ylevel($parent($rev))} { 367 gen_log:log D " jumping to level of parent" 368 set py($ind) $ylevel($parent($rev)) 369 if {$ind > 2} { 370 # Give it a node if its parent isn't in column1 371 incr ylevel($parent($rev)) -$cvscanv(space) 372 set px($ind) [expr {$px($pind) + $cvscanv(boxx) + $cvscanv(space)}] 373 set py($ind) $ylevel($parent($rev)) 374 node $joincanvas $rev \ 375 [expr {$px($pind) + $cvscanv(midx)}] \ 376 [expr {$py($ind) - 1}] 377 } 378 } else { 379 gen_log:log D " parent not higher" 380 set py($ind) [expr {$py($ind) - $cvscanv(space)}] 381 } 382 set xlevel($rev) [expr {$px($ind) + $cvscanv(midx)}] 383 } else { 384 set py($ind) [expr {$py($ind) - $cvscanv(space)}] 385 gen_log:log D " just stacking it above the last one" 386 set xlevel($rev) $px($ind) 387 } 388 set ylevel($rev) $py($ind) 389 390 # For column 1, just draw a nondescript node 391 if {$ind == 1} { 392 #node $joincanvas $rev $px($ind) $py($ind) 393 set py($ind) [expr {$py($ind) - ($nchildren($rev) - 1) * $cvscanv(space)}] 394 } else { 395 if {! [info exists tags($rev)]} { 396 set tags($rev) "" 397 } 398 gen_log:log D " tag: $tags($rev)" 399 rectangle $joincanvas $rev $px($ind) $py($ind) 400 # Line linking it to parent 401 if {$ind > 2} { 402 set ly [expr {$ylevel($parent($rev)) + $cvscanv(midy)}] 403 } else { 404 set ly [expr {$py($ind) + $cvscanv(midy)}] 405 } 406 if {![info exists xlevel($parent($rev))]} {set xlevel($parent($rev)) $px([expr $ind-1])} 407 $joincanvas.canvas create line \ 408 $xlevel($parent($rev)) [expr {$ly + 10}] \ 409 [expr {$xlevel($parent($rev)) + 10}] $ly \ 410 $px($ind) [expr {$py($ind) + $cvscanv(midy)}] 411 set py($ind) [expr {$py($ind) - $nchildren($rev) * $cvscanv(space)}] 412 } 413 } 414 415 set py(1) [expr {$cvscanv(boxy) - 4}] 416 set maxyind 0 417 foreach i [array names py] { 418 if {$py($i) < $maxyind} { 419 set maxyind $py($i) 420 } 421 } 422 423 set tags($headrev) $cvscfg(mergetrunkname) 424 gen_log:log D "HEAD $headrev" 425 gen_log:log D "tagtext \"$tags($headrev)\"" 426 # Make a box for top of trunk 427 set ylevel(trunk) [expr {$maxyind - $cvscanv(boxy)}] 428 set tagwidth [font measure {Helvetica -12 bold} \ 429 -displayof $joincanvas.canvas $cvscfg(mergetrunkname)] 430 if {$tagwidth < $cvscanv(boxmin)} { set tagwidth $cvscanv(boxmin) } 431 set boxid [$joincanvas.canvas create rectangle \ 432 [expr {$px(1) - $tagwidth / 2}] $ylevel(trunk) \ 433 [expr {$px(1) + 5 + $tagwidth / 2}] \ 434 [expr {$ylevel(trunk) - $cvscanv(boxy)}] \ 435 -width 3 \ 436 -fill gray90 \ 437 -tags b$headrev] 438 $joincanvas.canvas lower $boxid 439 $joincanvas.canvas create text \ 440 [expr {$px(1) + 2}] [expr {$ylevel(trunk) - 2}] \ 441 -text "$cvscfg(mergetrunkname)" \ 442 -anchor s -justify center -fill blue \ 443 -font {Helvetica -12 bold} \ 444 -tags b$headrev 445 # Bottom then top 446 $joincanvas.canvas create line \ 447 $px(1) [expr {$cvscanv(space) - 4}] \ 448 $px(1) $ylevel(trunk) 449 450 # Bind button-press 451 $joincanvas.canvas bind b$headrev <ButtonPress-1> \ 452 [namespace code "select_rectangle $headrev $cvscfg(mergetrunkname)"] 453 # Clicking in a blank part of the canvas unselects boxes 454 bind $joincanvas.canvas <ButtonPress-1> \ 455 [namespace code unselect_all] 456 457 458 # You are Here 459 if {$current_tagname == "trunk"} { 460 you_are_here $headrev $tagwidth \ 461 [expr {$px(1) - $tagwidth / 2 }] \ 462 [expr {$ylevel(trunk) - $cvscanv(boxy)}] 463 } 464 465 # now calculate the bounding box using the canvas bbox function 466 set bbox [$joincanvas.canvas bbox all] 467 set boty [lindex $bbox 1] 468 set topy [lindex $bbox 3] 469 set bheight [expr {$topy - $boty}] 470 471 set origheight [lindex [$joincanvas.canvas config -height] 4] 472 473 set screenHeight [winfo vrootheight .] 474 if {$bheight > $screenHeight} { 475 set bheight $screenHeight 476 } 477 if {$bheight > $origheight} { 478 $joincanvas.canvas config -height $bheight 479 } 480 481 $joincanvas.canvas config -scrollregion $bbox 482 $joincanvas.canvas yview moveto 0 483 484 set here [$joincanvas.up.rversTo get] 485 if {$here == ""} { 486 cvsfail "I can't find where I am. Perhaps the working directory isn't at the head of a branch?" $joincanvas 487 } 488 gen_log:log T "LEAVE" 489 } 490 491 proc you_are_here {rev offset hx hy} { 492 variable cvscanv 493 variable joincanvas 494 variable tags 495 496 gen_log:log T "ENTER ($rev $offset $hx $hy)" 497 gen_log:log D "tags($rev) $tags($rev)" 498 $joincanvas.canvas create image \ 499 [expr {$hx + $offset + 16}] [expr {$hy + $cvscanv(boxy)}] \ 500 -image Man -anchor s \ 501 -tag you_are_here_icon 502 $joincanvas.canvas create text \ 503 [expr {$hx + $offset + 26}] [expr {$hy + $cvscanv(boxy)}] \ 504 -text "You are\nhere" -anchor sw \ 505 -fill red3 \ 506 -font {Helvetica -10 bold} \ 507 -tag you_are_here_icon 508 509 # Put the name in the "To" entry and disable it. You can only 510 # merge to where you are. 511 $joincanvas.up.rversTo configure -state normal 512 $joincanvas.up.rversTo delete 0 end 513 $joincanvas.up.rversTo insert end $tags($rev) 514 $joincanvas.up.rversTo configure -state readonly 515 $joincanvas.canvas bind b$rev <ButtonPress-1> {} 516 } 517 518 toplevel $joincanvas 519 wm title $joincanvas "CVS Directory Merge" 520 if {$tcl_platform(platform) != "windows"} { 521 wm iconbitmap $joincanvas @$cvscfg(bitmapdir)/dirbranch.xbm 522 } 523 wm protocol $joincanvas WM_DELETE_WINDOW \ 524 [namespace code {$joincanvas.close invoke}] 525 526 $joincanvas configure -menu $joincanvas.menubar 527 menu $joincanvas.menubar 528 529 $joincanvas.menubar add cascade -label "File" \ 530 -menu $joincanvas.menubar.file -underline 0 531 menu $joincanvas.menubar.file -tearoff 0 532 $joincanvas.menubar.file add command -label "Close" -underline 0 \ 533 -command [namespace code {$joincanvas.close invoke}] 534 $joincanvas.menubar.file add command -label "Exit" -underline 1 \ 535 -command { exit_cleanup 1 } 536 537 $joincanvas.menubar add cascade -label "Help" \ 538 -menu $joincanvas.menubar.help -underline 0 539 menu $joincanvas.menubar.help -tearoff 0 540 $joincanvas.menubar.help add command -label "Merge Tool" -underline 0 \ 541 -command directory_branch_viewer 542 543 frame $joincanvas.up -relief groove -border 2 544 pack $joincanvas.up -side top -fill x 545 546 button $joincanvas.up.bworkdir -image Workdir \ 547 -command { workdir_setup } 548 button $joincanvas.up.bmodbrowse -image Modules_cvs \ 549 -command { modbrowse_run cvs } 550 551 label $joincanvas.up.lfname -text "Representative File" -anchor w 552 entry $joincanvas.up.rfname -textvariable [namespace current]::repfile 553 bind $joincanvas.up.rfname <Return> \ 554 [namespace code {join_getlog $repfile [namespace current]}] 555 556 label $joincanvas.up.lversFrom -text "Merge From" -anchor w 557 frame $joincanvas.up.eFrom -bg $cvscfg(colourA) 558 entry $joincanvas.up.rversFrom 559 560 label $joincanvas.up.lversSince -text " Since" -anchor w 561 frame $joincanvas.up.eSince -bg $cvscfg(colourB) 562 ::picklist::clear alltags 563 ::picklist::entry $joincanvas.up.rversSince "" alltags 564 label $joincanvas.up.lversTo -text "Merge To" -anchor w 565 entry $joincanvas.up.rversTo -relief groove \ 566 -bd 1 -relief sunk -state readonly -readonlybackground $cvsglb(bg) 567 568 grid columnconf $joincanvas.up 1 -weight 1 569 grid rowconf $joincanvas.up 3 -weight 1 570 grid $joincanvas.up.lfname -column 0 -row 0 -sticky w 571 grid $joincanvas.up.rfname -column 1 -row 0 -padx 3 -sticky ew 572 grid $joincanvas.up.bworkdir -column 2 -row 0 -rowspan 2 \ 573 -sticky e -padx 2 -pady 1 574 grid $joincanvas.up.lversFrom -column 0 -row 1 -sticky w 575 grid $joincanvas.up.eFrom -column 1 -row 1 -sticky ew -padx 4 576 grid $joincanvas.up.bmodbrowse -column 2 -row 2 -rowspan 2 \ 577 -sticky e -padx 2 -pady 1 578 grid $joincanvas.up.lversSince -column 0 -row 2 -sticky w 579 grid $joincanvas.up.eSince -column 1 -row 2 -sticky ew -padx 4 580 grid $joincanvas.up.lversTo -column 0 -row 3 -sticky w 581 grid $joincanvas.up.rversTo -column 1 -row 3 -padx 3 -sticky ew 582 583 pack $joincanvas.up.rversFrom -in $joincanvas.up.eFrom \ 584 -padx 2 -pady 2 -fill x 585 pack $joincanvas.up.rversSince -in $joincanvas.up.eSince \ 586 -padx 2 -pady 2 -fill x 587 588 set textfont [$joincanvas.up.rfname cget -font] 589 590 # Pack the bottom before the middle so it doesnt disappear if 591 # the window is resized smaller 592 frame $joincanvas.down -relief groove -border 2 593 pack $joincanvas.down -side bottom -fill x 594 595 set repfile $localfile 596 597 # The canvas for the big picture 598 canvas $joincanvas.canvas -relief sunken -border 2 \ 599 -yscrollcommand "$joincanvas.yscroll set" \ 600 -xscrollcommand "$joincanvas.xscroll set" 601 scrollbar $joincanvas.xscroll -relief sunken -orient horizontal \ 602 -command "$joincanvas.canvas xview" 603 scrollbar $joincanvas.yscroll -relief sunken \ 604 -command "$joincanvas.canvas yview" 605 606 # 607 # Create buttons 608 # 609 button $joincanvas.delta -image Mergediff \ 610 -command [namespace code { 611 set fromrev [$joincanvas.up.rversFrom get] 612 if {$fromrev == ""} { 613 cvsfail "Please select a branch!" $joincanvas; return 614 } 615 set sincerev [$joincanvas.up.rversSince.e get] 616 cvs_merge $joincanvas $fromrev $sincerev $fromrev . 617 }] 618 619 button $joincanvas.down.blogfile -image Branches \ 620 -command "cvs_branches $repfile" 621 frame $joincanvas.down.btnfm 622 frame $joincanvas.down.closefm -relief groove -bd 2 623 button $joincanvas.close -text "Close" \ 624 -command [namespace code " 625 destroy $joincanvas 626 namespace delete [namespace current] 627 exit_cleanup 0 628 "] 629 630 pack $joincanvas.down.blogfile -side left \ 631 -ipadx 4 -ipady 4 632 pack $joincanvas.down.btnfm -side left -fill y -expand 1 633 pack $joincanvas.delta \ 634 -in $joincanvas.down.btnfm -side left \ 635 -ipadx 4 -ipady 4 636 pack $joincanvas.down.closefm -side right 637 pack $joincanvas.close \ 638 -in $joincanvas.down.closefm -side right \ 639 -fill both -expand 1 640 641 set_tooltips $joincanvas.down.blogfile \ 642 {"Revision Log and Branch Diagram of the current file"} 643 set_tooltips $joincanvas.delta \ 644 {"Merge to current"} 645 set_tooltips $joincanvas.up.bworkdir \ 646 {"Open the Working Directory Browser"} 647 set_tooltips $joincanvas.up.bmodbrowse \ 648 {"Open the Repository Browser"} 649 650 # 651 # Put the canvas on to the display. 652 # 653 pack $joincanvas.xscroll -side bottom -fill x -padx 1 -pady 1 654 pack $joincanvas.yscroll -side right -fill y -padx 1 -pady 1 655 pack $joincanvas.canvas -fill both -expand 1 656 657 $joincanvas.canvas delete all 658 659 # 660 # Window manager stuff. 661 # 662 wm minsize $joincanvas 1 1 663 664 scrollbindings Canvas 665 focus $joincanvas.canvas 666 667 fillcanvas $localfile $filelog 668 669 return [namespace current] 670 } 671 } 672} 673 674proc cvs_joincanvas { } { 675# Find the bushiest file in the directory and diagram it 676 global cvs 677 global incvs 678 global cvscfg 679 global current_tagname 680 681 gen_log:log T "ENTER" 682 if {! $incvs} { 683 cvs_notincvs 684 return 1 685 } 686 set files [glob -nocomplain -types f -- .??* *] 687 688 regsub -all {\$} $files {\$} files 689 set commandline "$cvs -d $cvscfg(cvsroot) log $files" 690 gen_log:log C "$commandline" 691 catch {eval "exec $commandline"} raw_log 692 set log_lines [split $raw_log "\n"] 693 694 gen_log:log D "Directory tag: $current_tagname" 695 foreach logline $log_lines { 696 if {[string match "Working file:*" $logline]} { 697 set filename [lrange [split $logline] 2 end] 698 set nbranches($filename) 0 699 continue 700 } 701 if {[string match "total revisions:*" $logline]} { 702 set nrevs($filename) [lindex [split $logline] end] 703 continue 704 } 705 if { [regexp {^\t[-\w]+: .*\.0\.\d+$} $logline] } { 706 incr nbranches($filename) 707 } 708 } 709 set bushiestfile "" 710 set mostrevisedfile "" 711 set nbrmax 0 712 foreach br [array names nbranches] { 713 if {$nbranches($br) > $nbrmax} { 714 set bushiestfile $br 715 set nbrmax $nbranches($br) 716 } 717 } 718 set nrevmax 0 719 foreach br [array names nrevs] { 720 if {$nrevs($br) > $nrevmax} { 721 set mostrevisedfile $br 722 set nrevmax $nrevs($br) 723 } 724 } 725 gen_log:log F "Bushiest file \"$bushiestfile\" has $nbrmax branches" 726 gen_log:log F "Most Revised file \"$mostrevisedfile\" has $nrevmax revisions" 727 728 # Sometimes we don't find a file with any branches at all, so bushiest 729 # is empty. Fall back to mostrevised. All files have at least one rev. 730 if {[string length $bushiestfile] > 0} { 731 join_getlog $bushiestfile 732 } else { 733 join_getlog $mostrevisedfile 734 } 735 736 gen_log:log T "LEAVE" 737} 738 739# Get the file log. Make a new canvas or re-draw an existing one. 740proc join_getlog {filename {name_idx {}}} { 741 global cvscfg 742 global cvs 743 global current_tagname 744 745 gen_log:log T "ENTER ($filename $name_idx)" 746 set commandline "$cvs -d $cvscfg(cvsroot) log \"$filename\"" 747 gen_log:log C "$commandline" 748 set ret [catch {eval "exec $commandline"} view_this] 749 # If you bail, sometimes you discard a perfectly good log 750 #if {$ret} { 751 #cvsfail $view_this 752 #gen_log:log T "LEAVE ERROR ($view_this)" 753 #return 754 #} 755 if {$name_idx == ""} { 756 joincanvas::new $filename $view_this $current_tagname 757 } else { 758 $name_idx\::fillcanvas $filename $view_this 759 } 760 gen_log:log T "LEAVE" 761} 762