#
# $Id: modbrowse.tcl,v 1.27 2002/01/23 06:55:26 dorothyr Exp $
#
# Set up a check out dialog.
#

proc modbrowse_setup {} {
  global cwd
  global modbrowse_module
  global mod_tagA
  global cvsglb
  global cvscfg
  global feedback

  gen_log:log T "ENTER"
  set cwd [pwd]
  set mod_tagA "HEAD"

  # Window manager stuff.
  toplevel .modbrowse
  wm title .modbrowse "Module Browser"
  wm iconname .modbrowse "CVS Modules"
  wm iconbitmap .modbrowse @$cvscfg(bitmapdir)/tkcvs48.xbm
  wm protocol .modbrowse WM_DELETE_WINDOW {module_exit}
  if {[info exists cvscfg(modgeom)]} {
    wm geometry .modbrowse $cvscfg(modgeom)
  } else {
    wm geometry .modbrowse 510x470
  }

  if {[catch "image type Who"]} {
    modbrowse_images
  }

  modbrowse_menus

  #
  # Top section - module, tags, root
  #
  frame .modbrowse.top -relief groove -border 2
  pack .modbrowse.top -side top -fill x

  label .modbrowse.top.lmcode -text "Module"
  entry .modbrowse.top.tmcode -textvariable modbrowse_module

  label .modbrowse.top.lroot -text "CVSROOT"
  entry .modbrowse.top.troot -textvariable cvscfg(cvsroot)
  bind .modbrowse.top.troot <KeyPress-Return> {
     ModTree:delitem .modbrowse.treeframe.pw /
     destroy .modbrowse.treeframe.pw
     ModTree:create .modbrowse.treeframe.pw
     pack .modbrowse.treeframe.pw -side bottom -fill both -expand yes
     modbrowse_run $cvscfg(cvsroot)
  }

  button .modbrowse.top.bworkdir -image Workdir -command {workdir_setup}

  label .modbrowse.top.lcwd -text "Current Directory"
  entry .modbrowse.top.tcwd -textvariable cwd
  bind .modbrowse.top.tcwd <Return> {module_changedir $cwd}

  label .modbrowse.top.ltaga -text "Tag A"
  entry .modbrowse.top.ttaga -textvariable mod_tagA

  label .modbrowse.top.ltagb -text "Tag B"
  entry .modbrowse.top.ttagb -textvariable mod_tagB

  grid columnconf .modbrowse.top 1 -weight 1
  grid rowconf .modbrowse.top 4 -weight 1
  grid .modbrowse.top.lmcode -column 0 -row 0 -sticky w
  grid .modbrowse.top.tmcode -column 1 -row 0 -columnspan 2 -padx 4 -sticky ew
  grid .modbrowse.top.lroot -column 0 -row 1 -sticky w
  grid .modbrowse.top.troot -column 1 -row 1 -columnspan 2 -padx 4 -sticky ew
  grid .modbrowse.top.lcwd -column 0 -row 2 -sticky w
  grid .modbrowse.top.tcwd -column 1 -row 2 -columnspan 2 -padx 4 -sticky ew
  grid .modbrowse.top.bworkdir -column 2 -row 3 -rowspan 2 -sticky w
  grid .modbrowse.top.ltaga -column 0 -row 3 -sticky nw
  grid .modbrowse.top.ttaga -column 1 -row 3 -padx 4 -sticky new
  grid .modbrowse.top.ltagb -column 0 -row 4 -sticky nw
  grid .modbrowse.top.ttagb -column 1 -row 4 -padx 4 -sticky new

  # Pack the bottom before the middle so it doesnt disappear if
  # the window is resized smaller
  frame .modbrowse.bottom -relief groove -border 2 -height 128
  frame .modbrowse.bottom.buttons
  frame .modbrowse.bottom.buttons.cvsfuncs -relief groove -bd 2
  frame .modbrowse.bottom.buttons.modfuncs -relief groove -bd 2
  frame .modbrowse.bottom.buttons.close -relief groove -bd 2

  pack .modbrowse.bottom -side bottom -fill x
  pack .modbrowse.bottom.buttons -side top -fill x -expand yes
  pack .modbrowse.bottom.buttons.cvsfuncs -side left -fill x -expand yes
  pack .modbrowse.bottom.buttons.modfuncs -side left -fill x -expand yes
  pack .modbrowse.bottom.buttons.close -side left -fill both -expand yes

  #
  # Create buttons
  #
  button .modbrowse.filebrowse -image Files \
    -command { browse_files $modbrowse_module }
  button .modbrowse.patchsummary -image Patches \
    -command {
       cvs_patch_summary $modbrowse_module \
                         $mod_tagA \
                         $mod_tagB
    }
  button .modbrowse.patchfile -image Patchfile \
    -command {
       cvs_patch $modbrowse_module $mod_tagA $mod_tagB
    }
  button .modbrowse.checkout -image Checkout \
    -command { 
       cvsroot_check
       cvs_checkout $modbrowse_module $mod_tagA 
    }
  button .modbrowse.export -image Export \
    -command {
       cvsroot_check
       cvs_export $modbrowse_module $mod_tagA
    }
  button .modbrowse.tag -image Tag \
    -command {
       rtag_dialog $modbrowse_module "no"
    }
  button .modbrowse.branchtag -image Branchtag \
    -command {
       rtag_dialog $modbrowse_module "yes"
    }
  button .modbrowse.import -image Import \
     -command import_run
  button .modbrowse.who -image Who \
     -command {cvs_history all $modbrowse_module}

  button .modbrowse.close -text "Close" \
    -padx 0 -pady 0 \
    -command {module_exit}

  pack .modbrowse.who \
       .modbrowse.filebrowse \
       .modbrowse.checkout  \
       .modbrowse.export  \
    -in .modbrowse.bottom.buttons.cvsfuncs \
    -side left -ipadx 1 -ipady 1 -fill x -expand 1
  pack .modbrowse.tag  \
       .modbrowse.branchtag  \
       .modbrowse.patchsummary \
       .modbrowse.patchfile \
       .modbrowse.import \
    -in .modbrowse.bottom.buttons.modfuncs \
    -side left -ipadx 1 -ipady 1 -fill x -expand 1
  pack .modbrowse.close \
    -in .modbrowse.bottom.buttons.close \
    -side right -ipadx 0 -ipady 0 -fill both -expand 1

  set_tooltips .modbrowse.checkout \
     {"Check out a module from the repository"}
  set_tooltips .modbrowse.export \
     {"Export a module from the repository"}
  set_tooltips .modbrowse.tag \
     {"Tag all files in a module"}
  set_tooltips .modbrowse.branchtag \
     {"Branch all files in a module"}
  set_tooltips .modbrowse.filebrowse \
     {"Browse the files in a module"}
  set_tooltips .modbrowse.patchsummary \
     {"Show a summary of differences between versions"}
  set_tooltips .modbrowse.patchfile \
     {"Create a patch file"}
  set_tooltips .modbrowse.import \
     {"Import the current directory into the repository"}
  set_tooltips .modbrowse.who \
     {"Show who has modules checked out"}
  set_tooltips .modbrowse.close \
     {"Close the module browser"}

  set_tooltips .modbrowse.top.bworkdir \
    {"Open the Working Directory Browser"}

  set feedback(mod) [entry .modbrowse.bottom.feedback -width 55 -state disabled]
  pack .modbrowse.bottom.feedback -side bottom -fill x -expand yes

  frame .modbrowse.treeframe
  pack .modbrowse.treeframe -side bottom -fill both -expand yes
  ModTree:create .modbrowse.treeframe.pw
  pack .modbrowse.treeframe.pw -side bottom -fill both -expand yes

  gen_log:log T " cvsroot: $cvscfg(cvsroot)"
  if {[string match "*:*" $cvscfg(cvsroot)]} {
    set cvsglb(remote) 1
  } else {
    set cvsglb(remote) 0
  }
  gen_log:log T " remote=$cvsglb(remote)"

  set screenWidth [winfo vrootwidth .]
  set screenHeight [winfo vrootheight .]

  wm maxsize .modbrowse $screenWidth $screenHeight
  wm minsize .modbrowse 10 10

  gen_log:log T "LEAVE"
}

proc modbrowse_images {} {
  global cvscfg

  image create photo Files -format gif -file [file join $cvscfg(bitmapdir) files.gif]
  image create photo Patches -format gif -file [file join $cvscfg(bitmapdir) patches.gif]
  image create photo Patchfile -format gif -file [file join $cvscfg(bitmapdir) patchfile.gif]
  image create photo Tag -format gif -file [file join $cvscfg(bitmapdir) tag.gif]
  image create photo Import -format gif -file [file join $cvscfg(bitmapdir) import.gif]
  image create photo Branchtag -format gif -file [file join $cvscfg(bitmapdir) branchtag.gif]
  image create photo Who -format gif -file [file join $cvscfg(bitmapdir) who.gif]
}

proc modbrowse_menus {} {
  global cvscfg
  global cvs
  global logclass

  gen_log:log T "ENTER"

  menu .modmenu
  .modbrowse configure -menu .modmenu

  #
  # Create the Menu bar
  #
  .modmenu add cascade -menu .modmenu.file -label "File" -underline 0
  menu .modmenu.file
  .modmenu add cascade -menu .modmenu.reports -label "Reports" -underline 0
  menu .modmenu.reports
  .modmenu add cascade -menu .modmenu.checkouts -label "Checkouts" -underline 0
  menu .modmenu.checkouts
  .modmenu add cascade -menu .modmenu.options -label "Options" -underline 0
  menu .modmenu.options
  .modmenu add cascade -menu .modmenu.patch -label "Patch" -underline 0
  menu .modmenu.patch
  .modmenu add cascade -menu .modmenu.tag -label "Tag" -underline 0
  menu .modmenu.tag
  .modmenu add cascade -menu .modmenu.help -label "Help" -underline 0
  menu .modmenu.help

  #
  # Create the menus
  #
  set selcolor [option get .modbrowse selectColor selectColor]
  .modmenu.file add command -label "Browse Working Directory" -underline 0 \
     -command workdir_setup
  .modmenu.file add command -label "Module File" \
     -command module_file
  .modmenu.file add separator
  .modmenu.file add command -label "Import" -underline 0 \
     -command import_run
  .modmenu.file add command -label "Vendor Merge" -underline 0 \
     -command {merge_run $modbrowse_module}
  .modmenu.file add separator
  .modmenu.file add command -label "Exit" -underline 1 \
     -command { module_exit; exit_cleanup }

  .modmenu.reports add command -label "Module Tree" -underline 0 \
     -command {modlist_by_code $modbrowse_module 0 $mod_tagA}
  .modmenu.reports add command -label "Version Tree" -underline 0 \
     -command {modlist_by_code $modbrowse_module 1 $mod_tagA}

  .modmenu.options add checkbutton -label "Group Aliases in a Folder" \
     -variable cvscfg(aliasfolder) -onvalue true -offvalue false \
     -selectcolor $selcolor -command {
        ModTree:delitem .modbrowse.treeframe.pw /
        destroy .modbrowse.treeframe.pw
        ModTree:create .modbrowse.treeframe.pw
        pack .modbrowse.treeframe.pw -side bottom -fill both -expand yes
        modbrowse_tree [lsort [array names modval]] "/"
     }
  .modmenu.options add separator
  .modmenu.options add checkbutton -label "Tracing On/Off" \
     -variable cvscfg(logging) -onvalue true -offvalue false \
     -selectcolor $selcolor -command log_toggle
  .modmenu.options add cascade -label "Trace Level" \
     -menu .modmenu.options.loglevel
  menu .modmenu.options.loglevel
  .modmenu.options.loglevel add checkbutton -label "CVS commands (C)" \
     -variable logclass(C) -onvalue "C" -offvalue "" \
     -selectcolor $selcolor -command gen_log:changeclass
  .modmenu.options.loglevel add checkbutton -label "File creation/deletion (F)"\
     -variable logclass(F) -onvalue F -offvalue "" \
     -selectcolor $selcolor -command gen_log:changeclass
  .modmenu.options.loglevel add checkbutton -label "Function entry/exit (T)" \
     -variable logclass(T) -onvalue T -offvalue "" \
     -selectcolor $selcolor -command gen_log:changeclass
  .modmenu.options.loglevel add checkbutton -label "Debugging (D)" \
     -variable logclass(D) -onvalue D -offvalue "" \
     -selectcolor $selcolor -command gen_log:changeclass

  .modmenu.checkouts add command -label "My Checkouts" -underline 0 \
     -command {cvs_history me ""}
  .modmenu.checkouts add command -label "Checkouts of Selected Module" -underline 0 \
     -command {cvs_history all $modbrowse_module}
  .modmenu.checkouts add command -label "All Checkouts" -underline 0 \
     -command {cvs_history all ""}

  .modmenu.patch add command -label "Make Patch File" -underline 0 \
     -command {
      cvs_patch $modbrowse_module $mod_tagA $mod_tagB
    }
  .modmenu.patch add command -label "View Patch Summary" -underline 0 \
     -command {
      cvs_patch_summary $modbrowse_module $mod_tagA $mod_tagB
    }

  .modmenu.tag add command -label "Tag Module" -underline 0 \
     -command {
        rtag_dialog $modbrowse_module "no"
    }
  .modmenu.tag add command -label "Branch Tag Module" -underline 0 \
     -command {
      rtag_dialog $modbrowse_module "yes"
    }

  .modmenu.help add command -label "Module Browser Overview" \
     -command module_browser
  .modmenu.help add separator
  .modmenu.help add command -label "Checking out Modules" \
     -command checking_out_modules
  .modmenu.help add command -label "Exporting" \
     -command exporting
  .modmenu.help add command -label "Tagging and Branching" \
     -command tagging_and_branching
  .modmenu.help add separator
  .modmenu.help add command -label "Menu" \
     -command module_browser_menu
  .modmenu.help add command -label "Buttons" \
     -command module_browser_buttons
  .modmenu.help add separator
  .modmenu.help add command -label "File Browser" \
     -command file_browser
  .modmenu.help add command -label "Log Browser" \
     -command log_browser
  .modmenu.help add separator
  .modmenu.help add command -label "CVS modules File" \
     -command cvs_modules_file

  gen_log:log T "LEAVE"
}

proc modbrowse_run {root} {
  global modval
  global cvscfg

  gen_log:log T "ENTER ($root)"

  set modbrowse_module ""
  read_modules $root

  if {! [winfo exists .modbrowse]} {
    modbrowse_setup
  }

  # Populate the tree
  modbrowse_tree [lsort [array names modval]] "/"

  wm deiconify .modbrowse
  raise .modbrowse
  gen_log:log T "LEAVE"
}

proc modbrowse_tree { mnames node } {
#
# Do this to update the display of the listbox (body proc).
#
  global cvscfg
  global modval
  global modtitle
  global dcontents
  global Tree

  gen_log:log T "ENTER ($mnames $node)"

  if {! [info exists cvscfg(aliasfolder)]} {
    set cvscfg(aliasfolder) false
  }

  set tf ".modbrowse.treeframe.pw"
  foreach mname $mnames {
    gen_log:log D "{$mname} {$modval($mname)}"
    set dimage "dir"
    # The descriptive title of the module.  If not specified, modval is used.
    set title $modval($mname)
    if {[info exists modtitle($mname)]} {
      set title $modtitle($mname)
      #gen_log:log D "* modtitle($mname) {$title}"
    }
    if {[string match "-a *" $modval($mname)]} {
      # Its an alias module
      regsub {\-a } $modtitle($mname) "Alias for " title
      if {$cvscfg(aliasfolder)} {
        gen_log:log D "path=Aliases/$mname pathtop=Aliases pathroot=/Aliases"
        if {! [info exists Tree($tf:/Aliases:children)]} {
          gen_log:log D "Making Aliases"
          ModTree:newitem $tf /Aliases Aliases "Aliases" -image "adir"
        }
        ModTree:newitem $tf /Aliases/$mname $mname "$title" -image "amod"
        continue
      }
      set dimage amod
    } elseif {[string match "*/*" $modval($mname)]} {
      #gen_log:log D "Set image to dir because $modval($mname) contains a slash"
      set dimage dir
      set path $modval($mname)
      if {[llength $modval($mname)] > 1} {
        regsub { &\S+} $path {} path
      }
      set pathitems [file split $path]
      set pathdepth [llength $pathitems]
      set pathtop [lindex [file split $path] 0]
      set pathroot [file join $node $pathtop]
      set pathroot "$pathroot"
      if {[info exists modtitle($pathtop)]} {
        set title $modtitle($pathtop)
        #gen_log:log D "* Using pathtop * modtitle($pathtop) {$title}"
      } elseif {[info exists modtitle($path)]} {
        set title $modtitle($path)
        #gen_log:log D "* Using path * modtitle($path) {$title}"
      } else {
        #gen_log:log D "* No modtitle($path)"
      }
      gen_log:log D "path=$path pathtop=$pathtop pathroot=$pathroot"
      if {! [info exists Tree($tf:$pathroot:children)]} {
        gen_log:log D "1 Making $pathtop for something with a \"/\" in its module name"
        if {[info exists modval($pathtop)]} { set dimage mdir }
        ModTree:newitem $tf $pathroot $pathtop "$title" -image $dimage
      }
      set pathroot ""
      for {set i 1} {$i < $pathdepth} {incr i} {
        set newnode [lindex $pathitems $i]
        set pathroot [file join $pathroot [lindex $pathitems [expr {$i -1} ]]]
        set newpath [file join "/" $pathroot $newnode]
        set namepath [string range $newpath 1 end]
        #gen_log:log D "* * mname=$mname namepath=$namepath pathroot=$pathroot newpath=$newpath newnode=$newnode"
        if {[info exists modtitle($namepath)]} {
          set title $modtitle($namepath)
          #gen_log:log D "* Using namepath * modtitle($namepath) {$title}"
        } elseif {[info exists modtitle($newnode)]} {
          set title $modtitle($newnode)
          #gen_log:log D "* Using newnode * modtitle($newnode) {$title}"
        } elseif {[info exists modtitle($mname)]} {
          set title $modtitle($mname)
          #gen_log:log D "* Using mname * modtitle($mname) {$title}"
        } else {
          #gen_log:log D "* * No modtitle($namepath)"
        }
        if {! [info exists Tree($tf:$newpath:children)]} {
          set modvalpath [file join "/" $modval($mname)]
          regsub { &\S+} $modvalpath {} modvalpath
          #gen_log:log D "* * mname=$mname modvalpath=$modvalpath newpath=$newpath newnode=$newnode"
          if {$modvalpath == $newpath} {
            set newnode $mname
          }
          set dimage dir
          gen_log:log D "2 Making $newnode for an intermediate node"
          lappend dcontents($pathroot) $newnode
          if {[info exists modval($newnode)]} {set dimage mdir}
          ModTree:newitem $tf $newpath $newnode "$title" -image $dimage
        }
      }
      # If we got here we just did a leaf, so break out and dont put it
      # at the toplevel too.
      continue
    }
    set treepath [file join $node $mname]
    if {[info exists Tree($tf:$treepath:children)]} {
      gen_log:log D "  Already handled $treepath"
      continue
    }
    gen_log:log D "3 Making $mname"
        if {[info exists modval($mname)] && ($dimage != "amod")} { set dimage mdir }
    ModTree:newitem $tf $treepath $mname $title -image $dimage
  }
  update
  gather_mod_index
  gen_log:log T "LEAVE"
}

proc modbrowse_select_code {yposition} {
#
# Do this when a code is clicked on.
#
  global modbrowse_ypos
  global modbrowse_module

  set modbrowse_ypos $yposition

  selection clear
  # This does the actual selection
  .modbrowse.codelist select set \
    [.modbrowse.codelist nearest $yposition]
  set code [selection get]

  # This will update the "Module Name" entry box.
  set modbrowse_module [lindex $code 0]

  return $code
}

proc module_exit { } {
  global cvscfg
  global cvs

  gen_log:log T "ENTER"


  set pid [pid]
  set cwd [pwd]
  set sandbox [file join $cvscfg(tmpdir) cvstmpdir.$pid]
  if {[file isdirectory $sandbox]} {
    gen_log:log F "CD $sandbox"
    cd $sandbox
    foreach d [glob -nocomplain *] {
      gen_log:log C "$cvs -Q release $d"
      catch {eval exec $cvs -Q release $d}
    }
  }
  cd $cwd
  gen_log:log F "cd [pwd]"

  if {[winfo exists .modbrowse]} {
    ModTree:delitem .modbrowse.treeframe.pw /
    set cvscfg(modgeom) [wm geometry .modbrowse]
    destroy .modbrowse
    destroy .modmenu
    catch {destroy .tooltips_wind}
  }

  # If no workdir browser, quit entirely.  Otherwise, just quit the
  # module browser.
  if {! [winfo exists .workdir]} {
    exit_cleanup
  }
  gen_log:log T "LEAVE"
}

proc module_changedir {new_dir} {
# Make sure a directory exists before trying to cd to it
  global cwd
  global cvscfg

  gen_log:log T "ENTER ($new_dir)"
  if {[file exists $new_dir]} {
    cd $new_dir
    gen_log:log F "CD [pwd]"
    # If this directory has a different cvsroot, redo the tree
    set savroot $cvscfg(cvsroot)
    set cvsdir [file join $new_dir CVS]
    if {[file isdirectory $cvsdir]} {
      read_cvs_dir $cvsdir
      if {$savroot != $cvscfg(cvsroot)} {
        read_modules $cvscfg(cvsroot)
      }
    }
    if {[winfo exists .workdir]} {
      update_go $new_dir
      setup_dir
    }
  } else {
    set cwd [pwd]
    cvsfail "Directory $new_dir doesn\'t exist!"
  }
  gen_log:log T "LEAVE"
}

proc module_file { } {
  global cvs
  global cvscfg

  set commandline "$cvs -d $cvscfg(cvsroot) checkout -p CVSROOT/modules"
  gen_log:log C "$commandline"
  exec_command "CVSROOT/modules" "$commandline"
}
