package versiontree final class GridMgr { private tclstring canv_ private tclarray cells_ # this is the canvas item id to GridItem object mapping. Key is the id # value is the GridItem objref private tclarray GIidmap_ # map for connector lines private tclarray Cidmap_ # the current item selected private GridItem GIselected_ # the current line selected private Connector Cselected_ # list of listeners who want notification when versions are selected private tcllist listeners_ private tclint treespread_ 3 GridMgr {canvas} { set canv_ $canvas # set up the bindings to highlight lines and grid items when selected $canv_ bind LINE "$this lineSelected" $canv_ bind GRIDITEM "$this itemSelected" } public void lineSelected {} { # get the line selected with the mouse set id [$canv_ find withtag current] objref Connector newselected [getConnector $id] if { $newselected == "null" } { return } # unselect whatever currently has the selection if { $Cselected_ != "null" } { $Cselected_ unselect } # did we just select what was already selected? if { $newselected == $Cselected_ } { set Cselected_ null return } { set Cselected_ $newselected $Cselected_ select } } public void itemSelected {} { # get the item selected with the mouse set id [$canv_ find withtag current] # is it the text? if { [$canv_ type current] == "text" } { # get the item underneath the text set id [$canv_ find below $id] } objref GridItem newselected [getGridItem $id] if { $newselected == "null" } { return } # unselect whatever currently has the selection if { $GIselected_ != "null" } { $GIselected_ unselect # send the unselected notifications out foreach listener $listeners_ { if { [$GIselected_ instanceof Rectangle] } { $listener branchUnSelected [$GIselected_ getTreeNode] } else { $listener snapshotUnSelected [$GIselected_ getTreeNode] } } } # did we just select what was already selected? if { $newselected == $GIselected_ } { set GIselected_ null return } { set GIselected_ $newselected $GIselected_ select # send the selected notifications out foreach listener $listeners_ { if { [$GIselected_ instanceof Rectangle] } { $listener branchSelected [$GIselected_ getTreeNode] } else { $listener snapshotSelected [$GIselected_ getTreeNode] } } } } void addListener {SelectedVersionListener.listener} { lappend listeners_ $listener } void mapGridItem {GridItem.item tclint.id} { set GIidmap_($id) $item } GridItem getGridItem {tclint.id} { if { ! [info exists GIidmap_($id)] } { return null } { return $GIidmap_($id) } } void mapConnector {Connector.line tclint.id} { set Cidmap_($id) $line } Connector getConnector {tclint.id} { if { ! [info exists Cidmap_($id)] } { return null } { return $Cidmap_($id) } } tclstring getCanvas {} { return $canv_ } tclint getCellWidth {} { return 100 } tclint getCellHeight {} { return 71 } # you ask for number of rows somewhere near , and the # grid manager will find a spot where it will fit. void need {tclint.rows tclint&.col tclint&.row} { # does this column even exist? if { [array names cells_ "$col,*"] == "" } { # no, just return what they want then return } # starting at the given row, keep going till we reach the end # we don't want to go any farther than $treespread_ steps though for {set origrow $row} {1} {incr col; set row $origrow} { for {set d 0} {$d < $treespread_} {incr d;incr row} { if { ! [info exists cells_($col,$row)] } { # we found a free spot, but does it have enough space? for {set i 1;set r [expr {$row+1}]} {$i < $rows} {incr i;incr r} { if { [info exists cells_($col,$r) ] } { # damn something there, better start looking in another col # set this variable to kick us out of outer loop set d $treespread_ break } } if { $d == $treespread_ } break # I guess it's big enough return } } } } # this version uses a hole data structure private tclarray holes_ void need2 {tclint.rows tclint&.col tclint&.row} { while {1} { # does this column even exist? if { ! [info exists holes_($col)] } { # no, just return what they want then # # set up the holes made tho set end [expr {$row + $rows}] if { $row > 2 } { set holes_($col) [list [list 0 $row] [list $end -1]] } { set holes_($col) [list $end -1] } #parray holes_ return } # find a hole big enough for us set len [llength $holes_($col)] for {set i 0} {$i < $len} {incr i} { foreach {r s} [lindex $holes_($col) $i] {} if { $r < $row } continue # have we gone beyond our spread limit? if { [expr {($r - $row) > $treespread_}] } break # is this hole big enough? if { $s == -1 || $s >= $rows} { # we'll take it set row $r # now fix up the hole info if { $s == -1 } { set r [expr {$r + $rows}] set holes_($col) [lreplace $holes_($col) $i $i [list $r -1]] } elseif { $s - $rows < 2 } { # don't want a 2 row hole; outright remove the entry set holes_($col) [lreplace $holes_($col) $i $i] } else { # update the entry set r [expr {$r + $rows}] set s [expr {$s - $rows}] set holes_($col) [lreplace $holes_($col) $i $i [list $r $s]] } #parray holes_ return } } incr col } } GridItem addItem {tclstring.class tclint.x tclint.y TreeNode.treeNode} { # get the cell for this location objref GridCell cell [getCell $x $y] # create the item return [$cell addItem $class $treeNode] } void addConnector {GridItem.i1 GridItem.i2} { new Connector [$i1 getCell] [$i2 getCell] } void addConnector {GridItem.i1 GridItem.i2 tclbool.arrow} { new Connector [$i1 getCell] [$i2 getCell] $arrow } GridCell getCell {tclint.x tclint.y} { if { ! [info exists cells_($x,$y)] } { set cells_($x,$y) [new GridCell $this $x $y] } return $cells_($x,$y) } tclint getLastCol {} { tclint maxcol -1 foreach col [array names cells_] { # pull off the column set col [lindex [split $col ,] 0] # is it bigger? if { $col > $maxcol } { set maxcol $col } } return $maxcol } # return the current size of the grid, in pixels tcllist getSize {} { set maxcol [getLastCol] tclint maxrow -1 foreach row [array names cells_] { # pull off the row set row [lindex [split $row ,] 1] # is it bigger? if { $row > $maxrow } { set maxrow $row } } incr maxcol incr maxrow return [list [expr {$maxcol * [getCellWidth]}] [expr {$maxrow * [getCellHeight]}]] } void drawAllItems {} { $canv_ raise GRIDITEM LINE $canv_ raise GHOSTGRIDITEM LINE } void print {} { # this could stand a lot of customization! foreach {x1 y1 x2 y2} [$canv_ bbox all] {} $canv_ postscript -file versiontree.ps -pageheight 10i -pagewidth 8.5i -width [expr {$x2 - $x1}] -height [expr {$y2 - $y1}] } }