home *** CD-ROM | disk | FTP | other *** search
/ PC World 2005 June / PCWorld_2005-06_cd.bin / software / vyzkuste / firewally / firewally.exe / framework-2.3.exe / xmfbox.tcl < prev    next >
Text File  |  2003-09-01  |  25KB  |  962 lines

  1. # xmfbox.tcl --
  2. #
  3. #    Implements the "Motif" style file selection dialog for the
  4. #    Unix platform. This implementation is used only if the
  5. #    "::tk_strictMotif" flag is set.
  6. #
  7. # RCS: @(#) $Id: xmfbox.tcl,v 1.24 2002/09/09 20:05:27 uid38172 Exp $
  8. #
  9. # Copyright (c) 1996 Sun Microsystems, Inc.
  10. # Copyright (c) 1998-2000 Scriptics Corporation
  11. #
  12. # See the file "license.terms" for information on usage and redistribution
  13. # of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  14.  
  15. namespace eval ::tk::dialog {}
  16. namespace eval ::tk::dialog::file {}
  17.  
  18.  
  19. # ::tk::MotifFDialog --
  20. #
  21. #    Implements a file dialog similar to the standard Motif file
  22. #    selection box.
  23. #
  24. # Arguments:
  25. #    type        "open" or "save"
  26. #    args        Options parsed by the procedure.
  27. #
  28. # Results:
  29. #    When -multiple is set to 0, this returns the absolute pathname
  30. #    of the selected file. (NOTE: This is not the same as a single
  31. #    element list.)
  32. #    When -multiple is set to > 0, this returns a Tcl list of absolute
  33. #       pathnames. The argument for -multiple is ignored, but for consistency
  34. #       with Windows it defines the maximum amount of memory to allocate for
  35. #       the returned filenames.
  36.  
  37. proc ::tk::MotifFDialog {type args} {
  38.     variable ::tk::Priv
  39.     set dataName __tk_filedialog
  40.     upvar ::tk::dialog::file::$dataName data
  41.  
  42.     set w [MotifFDialog_Create $dataName $type $args]
  43.  
  44.     # Set a grab and claim the focus too.
  45.  
  46.     ::tk::SetFocusGrab $w $data(sEnt)
  47.     $data(sEnt) selection range 0 end
  48.  
  49.     # Wait for the user to respond, then restore the focus and
  50.     # return the index of the selected button.  Restore the focus
  51.     # before deleting the window, since otherwise the window manager
  52.     # may take the focus away so we can't redirect it.  Finally,
  53.     # restore any grab that was in effect.
  54.  
  55.     vwait ::tk::Priv(selectFilePath)
  56.     ::tk::RestoreFocusGrab $w $data(sEnt) withdraw
  57.  
  58.     return $Priv(selectFilePath)
  59. }
  60.  
  61. # ::tk::MotifFDialog_Create --
  62. #
  63. #    Creates the Motif file dialog (if it doesn't exist yet) and
  64. #    initialize the internal data structure associated with the
  65. #    dialog.
  66. #
  67. #    This procedure is used by ::tk::MotifFDialog to create the
  68. #    dialog. It's also used by the test suite to test the Motif
  69. #    file dialog implementation. User code shouldn't call this
  70. #    procedure directly.
  71. #
  72. # Arguments:
  73. #    dataName    Name of the global "data" array for the file dialog.
  74. #    type        "Save" or "Open"
  75. #    argList        Options parsed by the procedure.
  76. #
  77. # Results:
  78. #    Pathname of the file dialog.
  79.  
  80. proc ::tk::MotifFDialog_Create {dataName type argList} {
  81.     upvar ::tk::dialog::file::$dataName data
  82.  
  83.     MotifFDialog_Config $dataName $type $argList
  84.  
  85.     if {[string equal $data(-parent) .]} {
  86.         set w .$dataName
  87.     } else {
  88.         set w $data(-parent).$dataName
  89.     }
  90.  
  91.     # (re)create the dialog box if necessary
  92.     #
  93.     if {![winfo exists $w]} {
  94.     MotifFDialog_BuildUI $w
  95.     } elseif {[string compare [winfo class $w] TkMotifFDialog]} {
  96.     destroy $w
  97.     MotifFDialog_BuildUI $w
  98.     } else {
  99.     set data(fEnt) $w.top.f1.ent
  100.     set data(dList) $w.top.f2.a.l
  101.     set data(fList) $w.top.f2.b.l
  102.     set data(sEnt) $w.top.f3.ent
  103.     set data(okBtn) $w.bot.ok
  104.     set data(filterBtn) $w.bot.filter
  105.     set data(cancelBtn) $w.bot.cancel
  106.     }
  107.     MotifFDialog_SetListMode $w
  108.  
  109.     # Dialog boxes should be transient with respect to their parent,
  110.     # so that they will always stay on top of their parent window.  However,
  111.     # some window managers will create the window as withdrawn if the parent
  112.     # window is withdrawn or iconified.  Combined with the grab we put on the
  113.     # window, this can hang the entire application.  Therefore we only make
  114.     # the dialog transient if the parent is viewable.
  115.  
  116.     if {[winfo viewable [winfo toplevel $data(-parent)]] } {
  117.     wm transient $w $data(-parent)
  118.     }
  119.  
  120.     MotifFDialog_FileTypes $w
  121.     MotifFDialog_Update $w
  122.  
  123.     # Withdraw the window, then update all the geometry information
  124.     # so we know how big it wants to be, then center the window in the
  125.     # display (Motif style) and de-iconify it.
  126.  
  127.     ::tk::PlaceWindow $w
  128.     wm title $w $data(-title)
  129.  
  130.     return $w
  131. }
  132.  
  133. # ::tk::MotifFDialog_FileTypes --
  134. #
  135. #    Checks the -filetypes option. If present this adds a list of radio-
  136. #    buttons to pick the file types from.
  137. #
  138. # Arguments:
  139. #    w        Pathname of the tk_get*File dialogue.
  140. #
  141. # Results:
  142. #    none
  143.  
  144. proc ::tk::MotifFDialog_FileTypes {w} {
  145.     upvar ::tk::dialog::file::[winfo name $w] data
  146.  
  147.     set f $w.top.f3.types
  148.     catch {destroy $f}
  149.  
  150.     # No file types: use "*" as the filter and display no radio-buttons
  151.     if {$data(-filetypes) == ""} {
  152.     set data(filter) *
  153.     return
  154.     }
  155.  
  156.     # The filetypes radiobuttons
  157.     # set data(fileType) $data(-defaulttype)
  158.     set data(fileType) 0
  159.  
  160.     MotifFDialog_SetFilter $w [lindex $data(-filetypes) $data(fileType)]
  161.  
  162.     #don't produce radiobuttons for only one filetype
  163.     if {[llength $data(-filetypes)] == 1} {
  164.     return
  165.     }
  166.  
  167.     frame $f
  168.     set cnt 0
  169.     if {$data(-filetypes) != {}} {
  170.     foreach type $data(-filetypes) {
  171.         set title  [lindex [lindex $type 0] 0]
  172.         set filter [lindex $type 1]
  173.         radiobutton $f.b$cnt \
  174.         -text $title \
  175.         -variable ::tk::dialog::file::[winfo name $w](fileType) \
  176.         -value $cnt \
  177.         -command "[list tk::MotifFDialog_SetFilter $w $type]"
  178.         pack $f.b$cnt -side left
  179.         incr cnt
  180.     }
  181.     }
  182.     $f.b$data(fileType) invoke
  183.  
  184.     pack $f -side bottom -fill both
  185.  
  186.     return
  187. }
  188.  
  189. # This proc gets called whenever data(filter) is set
  190. #
  191. proc ::tk::MotifFDialog_SetFilter {w type} {
  192.     upvar ::tk::dialog::file::[winfo name $w] data
  193.     variable ::tk::Priv
  194.  
  195.     set data(filter) [lindex $type 1]
  196.     set Priv(selectFileType) [lindex [lindex $type 0] 0]
  197.  
  198.     MotifFDialog_Update $w
  199. }
  200.  
  201. # ::tk::MotifFDialog_Config --
  202. #
  203. #    Iterates over the optional arguments to determine the option
  204. #    values for the Motif file dialog; gives default values to
  205. #    unspecified options.
  206. #
  207. # Arguments:
  208. #    dataName    The name of the global variable in which
  209. #            data for the file dialog is stored.
  210. #    type        "Save" or "Open"
  211. #    argList        Options parsed by the procedure.
  212.  
  213. proc ::tk::MotifFDialog_Config {dataName type argList} {
  214.     upvar ::tk::dialog::file::$dataName data
  215.  
  216.     set data(type) $type
  217.  
  218.     # 1: the configuration specs
  219.     #
  220.     set specs {
  221.     {-defaultextension "" "" ""}
  222.     {-filetypes "" "" ""}
  223.     {-initialdir "" "" ""}
  224.     {-initialfile "" "" ""}
  225.     {-parent "" "" "."}
  226.     {-title "" "" ""}
  227.     }
  228.     if { [string equal $type "open"] } {
  229.     lappend specs {-multiple "" "" "0"}
  230.     }
  231.  
  232.     set data(-multiple) 0
  233.     # 2: default values depending on the type of the dialog
  234.     #
  235.     if {![info exists data(selectPath)]} {
  236.     # first time the dialog has been popped up
  237.     set data(selectPath) [pwd]
  238.     set data(selectFile) ""
  239.     }
  240.  
  241.     # 3: parse the arguments
  242.     #
  243.     tclParseConfigSpec ::tk::dialog::file::$dataName $specs "" $argList
  244.  
  245.     if {[string equal $data(-title) ""]} {
  246.     if {[string equal $type "open"]} {
  247.         if {$data(-multiple) != 0} {
  248.         set data(-title) "[mc {Open Multiple Files}]"
  249.         } else {
  250.         set data(-title) [mc "Open"]
  251.         }
  252.     } else {
  253.         set data(-title) [mc "Save As"]
  254.     }
  255.     }
  256.  
  257.     # 4: set the default directory and selection according to the -initial
  258.     #    settings
  259.     #
  260.     if {[string compare $data(-initialdir) ""]} {
  261.     if {[file isdirectory $data(-initialdir)]} {
  262.         set data(selectPath) [lindex [glob $data(-initialdir)] 0]
  263.     } else {
  264.         set data(selectPath) [pwd]
  265.     }
  266.  
  267.     # Convert the initialdir to an absolute path name.
  268.  
  269.     set old [pwd]
  270.     cd $data(selectPath)
  271.     set data(selectPath) [pwd]
  272.     cd $old
  273.     }
  274.     set data(selectFile) $data(-initialfile)
  275.  
  276.     # 5. Parse the -filetypes option. It is not used by the motif
  277.     #    file dialog, but we check for validity of the value to make sure
  278.     #    the application code also runs fine with the TK file dialog.
  279.     #
  280.     set data(-filetypes) [::tk::FDGetFileTypes $data(-filetypes)]
  281.  
  282.     if {![info exists data(filter)]} {
  283.     set data(filter) *
  284.     }
  285.     if {![winfo exists $data(-parent)]} {
  286.     error "bad window path name \"$data(-parent)\""
  287.     }
  288. }
  289.  
  290. # ::tk::MotifFDialog_BuildUI --
  291. #
  292. #    Builds the UI components of the Motif file dialog.
  293. #
  294. # Arguments:
  295. #     w        Pathname of the dialog to build.
  296. #
  297. # Results:
  298. #     None.
  299.  
  300. proc ::tk::MotifFDialog_BuildUI {w} {
  301.     set dataName [lindex [split $w .] end]
  302.     upvar ::tk::dialog::file::$dataName data
  303.  
  304.     # Create the dialog toplevel and internal frames.
  305.     #
  306.     toplevel $w -class TkMotifFDialog
  307.     set top [frame $w.top -relief raised -bd 1]
  308.     set bot [frame $w.bot -relief raised -bd 1]
  309.  
  310.     pack $w.bot -side bottom -fill x
  311.     pack $w.top -side top -expand yes -fill both
  312.  
  313.     set f1 [frame $top.f1]
  314.     set f2 [frame $top.f2]
  315.     set f3 [frame $top.f3]
  316.  
  317.     pack $f1 -side top    -fill x
  318.     pack $f3 -side bottom -fill x
  319.     pack $f2 -expand yes -fill both
  320.  
  321.     set f2a [frame $f2.a]
  322.     set f2b [frame $f2.b]
  323.  
  324.     grid $f2a -row 0 -column 0 -rowspan 1 -columnspan 1 -padx 4 -pady 4 \
  325.     -sticky news
  326.     grid $f2b -row 0 -column 1 -rowspan 1 -columnspan 1 -padx 4 -pady 4 \
  327.     -sticky news
  328.     grid rowconfig $f2 0    -minsize 0   -weight 1
  329.     grid columnconfig $f2 0 -minsize 0   -weight 1
  330.     grid columnconfig $f2 1 -minsize 150 -weight 2
  331.  
  332.     # The Filter box
  333.     #
  334.     bind [::tk::AmpWidget label $f1.lab -text [mc "Fil&ter:"] -anchor w] \
  335.     <<AltUnderlined>> [list focus $f1.ent]
  336.     entry $f1.ent
  337.     pack $f1.lab -side top -fill x -padx 6 -pady 4
  338.     pack $f1.ent -side top -fill x -padx 4 -pady 0
  339.     set data(fEnt) $f1.ent
  340.  
  341.     # The file and directory lists
  342.     #
  343.     set data(dList) [MotifFDialog_MakeSList $w $f2a \
  344.         [mc "&Directory:"] DList]
  345.     set data(fList) [MotifFDialog_MakeSList $w $f2b \
  346.         [mc "Fi&les:"]     FList]
  347.  
  348.     # The Selection box
  349.     #
  350.     bind [::tk::AmpWidget label $f3.lab -text [mc "&Selection:"] -anchor w] \
  351.     <<AltUnderlined>> [list focus $f3.ent]
  352.     entry $f3.ent
  353.     pack $f3.lab -side top -fill x -padx 6 -pady 0
  354.     pack $f3.ent -side top -fill x -padx 4 -pady 4
  355.     set data(sEnt) $f3.ent
  356.  
  357.     # The buttons
  358.     #
  359.     set maxWidth [::tk::mcmaxamp &OK &Filter &Cancel]
  360.     set maxWidth [expr {$maxWidth<6?6:$maxWidth}]
  361.     set data(okBtn) [::tk::AmpWidget button $bot.ok -text [mc "&OK"] \
  362.         -width $maxWidth \
  363.         -command [list tk::MotifFDialog_OkCmd $w]]
  364.     set data(filterBtn) [::tk::AmpWidget button $bot.filter -text [mc "&Filter"] \
  365.         -width $maxWidth \
  366.         -command [list tk::MotifFDialog_FilterCmd $w]]
  367.     set data(cancelBtn) [::tk::AmpWidget button $bot.cancel -text [mc "&Cancel"] \
  368.         -width $maxWidth \
  369.         -command [list tk::MotifFDialog_CancelCmd $w]]
  370.  
  371.     pack $bot.ok $bot.filter $bot.cancel -padx 10 -pady 10 -expand yes \
  372.     -side left
  373.  
  374.     # Create the bindings:
  375.     #
  376.     bind $w <Alt-Key> [list ::tk::AltKeyInDialog $w %A]
  377.  
  378.     bind $data(fEnt) <Return> [list tk::MotifFDialog_ActivateFEnt $w]
  379.     bind $data(sEnt) <Return> [list tk::MotifFDialog_ActivateSEnt $w]
  380.  
  381.     wm protocol $w WM_DELETE_WINDOW [list tk::MotifFDialog_CancelCmd $w]
  382. }
  383.  
  384. proc ::tk::MotifFDialog_SetListMode {w} {
  385.     upvar ::tk::dialog::file::[winfo name $w] data
  386.  
  387.     if {$data(-multiple) != 0} {
  388.     set selectmode extended
  389.     } else {
  390.     set selectmode browse
  391.     }
  392.     set f $w.top.f2.b
  393.     $f.l configure -selectmode $selectmode
  394. }
  395.  
  396. # ::tk::MotifFDialog_MakeSList --
  397. #
  398. #    Create a scrolled-listbox and set the keyboard accelerator
  399. #    bindings so that the list selection follows what the user
  400. #    types.
  401. #
  402. # Arguments:
  403. #    w        Pathname of the dialog box.
  404. #    f        Frame widget inside which to create the scrolled
  405. #            listbox. This frame widget already exists.
  406. #    label        The string to display on top of the listbox.
  407. #    under        Sets the -under option of the label.
  408. #    cmdPrefix    Specifies procedures to call when the listbox is
  409. #            browsed or activated.
  410.  
  411. proc ::tk::MotifFDialog_MakeSList {w f label cmdPrefix} {
  412.     bind [::tk::AmpWidget label $f.lab -text $label -anchor w] \
  413.     <<AltUnderlined>> [list focus $f.l]
  414.     listbox $f.l -width 12 -height 5 -exportselection 0\
  415.     -xscrollcommand [list $f.h set]    -yscrollcommand [list $f.v set]
  416.     scrollbar $f.v -orient vertical   -takefocus 0 -command [list $f.l yview]
  417.     scrollbar $f.h -orient horizontal -takefocus 0 -command [list $f.l xview]
  418.     grid $f.lab -row 0 -column 0 -sticky news -rowspan 1 -columnspan 2 \
  419.     -padx 2 -pady 2
  420.     grid $f.l -row 1 -column 0 -rowspan 1 -columnspan 1 -sticky news
  421.     grid $f.v -row 1 -column 1 -rowspan 1 -columnspan 1 -sticky news
  422.     grid $f.h -row 2 -column 0 -rowspan 1 -columnspan 1 -sticky news
  423.  
  424.     grid rowconfig    $f 0 -weight 0 -minsize 0
  425.     grid rowconfig    $f 1 -weight 1 -minsize 0
  426.     grid columnconfig $f 0 -weight 1 -minsize 0
  427.  
  428.     # bindings for the listboxes
  429.     #
  430.     set list $f.l
  431.     bind $list <<ListboxSelect>> [list tk::MotifFDialog_Browse$cmdPrefix $w]
  432.     bind $list <Double-ButtonRelease-1> \
  433.         [list tk::MotifFDialog_Activate$cmdPrefix $w]
  434.     bind $list <Return>    "tk::MotifFDialog_Browse$cmdPrefix [list $w]; \
  435.         tk::MotifFDialog_Activate$cmdPrefix [list $w]"
  436.  
  437.     bindtags $list [list Listbox $list [winfo toplevel $list] all]
  438.     ListBoxKeyAccel_Set $list
  439.  
  440.     return $f.l
  441. }
  442.  
  443. # ::tk::MotifFDialog_InterpFilter --
  444. #
  445. #    Interpret the string in the filter entry into two components:
  446. #    the directory and the pattern. If the string is a relative
  447. #    pathname, give a warning to the user and restore the pattern
  448. #    to original.
  449. #
  450. # Arguments:
  451. #    w        pathname of the dialog box.
  452. #
  453. # Results:
  454. #     A list of two elements. The first element is the directory
  455. #     specified # by the filter. The second element is the filter
  456. #     pattern itself.
  457.  
  458. proc ::tk::MotifFDialog_InterpFilter {w} {
  459.     upvar ::tk::dialog::file::[winfo name $w] data
  460.  
  461.     set text [string trim [$data(fEnt) get]]
  462.  
  463.     # Perform tilde substitution
  464.     #
  465.     set badTilde 0
  466.     if {[string equal [string index $text 0] ~]} {
  467.     set list [file split $text]
  468.     set tilde [lindex $list 0]
  469.     if {[catch {set tilde [glob $tilde]}]} {
  470.         set badTilde 1
  471.     } else {
  472.         set text [eval file join [concat $tilde [lrange $list 1 end]]]
  473.     }
  474.     }
  475.  
  476.     # If the string is a relative pathname, combine it
  477.     # with the current selectPath.
  478.  
  479.     set relative 0
  480.     if {[string equal [file pathtype $text] "relative"]} {
  481.     set relative 1
  482.     } elseif {$badTilde} {
  483.     set relative 1    
  484.     }
  485.  
  486.     if {$relative} {
  487.     tk_messageBox -icon warning -type ok \
  488.         -message "\"$text\" must be an absolute pathname"
  489.  
  490.     $data(fEnt) delete 0 end
  491.     $data(fEnt) insert 0 [::tk::dialog::file::JoinFile $data(selectPath) \
  492.         $data(filter)]
  493.  
  494.     return [list $data(selectPath) $data(filter)]
  495.     }
  496.  
  497.     set resolved [::tk::dialog::file::JoinFile [file dirname $text] [file tail $text]]
  498.  
  499.     if {[file isdirectory $resolved]} {
  500.     set dir $resolved
  501.     set fil $data(filter)
  502.     } else {
  503.     set dir [file dirname $resolved]
  504.     set fil [file tail    $resolved]
  505.     }
  506.  
  507.     return [list $dir $fil]
  508. }
  509.  
  510. # ::tk::MotifFDialog_Update
  511. #
  512. #    Load the files and synchronize the "filter" and "selection" fields
  513. #    boxes.
  514. #
  515. # Arguments:
  516. #     w         pathname of the dialog box.
  517. #
  518. # Results:
  519. #    None.
  520.  
  521. proc ::tk::MotifFDialog_Update {w} {
  522.     upvar ::tk::dialog::file::[winfo name $w] data
  523.  
  524.     $data(fEnt) delete 0 end
  525.     $data(fEnt) insert 0 \
  526.             [::tk::dialog::file::JoinFile $data(selectPath) $data(filter)]
  527.     $data(sEnt) delete 0 end
  528.     $data(sEnt) insert 0 [::tk::dialog::file::JoinFile $data(selectPath) \
  529.         $data(selectFile)]
  530.  
  531.     MotifFDialog_LoadFiles $w
  532. }
  533.  
  534. # ::tk::MotifFDialog_LoadFiles --
  535. #
  536. #    Loads the files and directories into the two listboxes according
  537. #    to the filter setting.
  538. #
  539. # Arguments:
  540. #     w         pathname of the dialog box.
  541. #
  542. # Results:
  543. #    None.
  544.  
  545. proc ::tk::MotifFDialog_LoadFiles {w} {
  546.     upvar ::tk::dialog::file::[winfo name $w] data
  547.  
  548.     $data(dList) delete 0 end
  549.     $data(fList) delete 0 end
  550.  
  551.     set appPWD [pwd]
  552.     if {[catch {cd $data(selectPath)}]} {
  553.     cd $appPWD
  554.  
  555.     $data(dList) insert end ".."
  556.     return
  557.     }
  558.  
  559.     # Make the dir and file lists
  560.     #
  561.     # For speed we only have one glob, which reduces the file system
  562.     # calls (good for slow NFS networks).
  563.     #
  564.     # We also do two smaller sorts (files + dirs) instead of one large sort,
  565.     # which gives a small speed increase.
  566.     #
  567.     set top 0
  568.     set dlist ""
  569.     set flist ""
  570.     foreach f [glob -nocomplain .* *] {
  571.     if {[file isdir ./$f]} {
  572.         lappend dlist $f
  573.     } else {
  574.             foreach pat $data(filter) {
  575.                 if {[string match $pat $f]} {
  576.         if {[string match .* $f]} {
  577.             incr top
  578.         }
  579.         lappend flist $f
  580.                     break
  581.         }
  582.             }
  583.     }
  584.     }
  585.     eval [list $data(dList) insert end] [lsort -dictionary $dlist]
  586.     eval [list $data(fList) insert end] [lsort -dictionary $flist]
  587.  
  588.     # The user probably doesn't want to see the . files. We adjust the view
  589.     # so that the listbox displays all the non-dot files
  590.     $data(fList) yview $top
  591.  
  592.     cd $appPWD
  593. }
  594.  
  595. # ::tk::MotifFDialog_BrowseDList --
  596. #
  597. #    This procedure is called when the directory list is browsed
  598. #    (clicked-over) by the user.
  599. #
  600. # Arguments:
  601. #     w        The pathname of the dialog box.
  602. #
  603. # Results:
  604. #    None.    
  605.  
  606. proc ::tk::MotifFDialog_BrowseDList {w} {
  607.     upvar ::tk::dialog::file::[winfo name $w] data
  608.  
  609.     focus $data(dList)
  610.     if {[string equal [$data(dList) curselection] ""]} {
  611.     return
  612.     }
  613.     set subdir [$data(dList) get [$data(dList) curselection]]
  614.     if {[string equal $subdir ""]} {
  615.     return
  616.     }
  617.  
  618.     $data(fList) selection clear 0 end
  619.  
  620.     set list [MotifFDialog_InterpFilter $w]
  621.     set data(filter) [lindex $list 1]
  622.  
  623.     switch -- $subdir {
  624.     . {
  625.         set newSpec [::tk::dialog::file::JoinFile $data(selectPath) $data(filter)]
  626.     }
  627.     .. {
  628.         set newSpec [::tk::dialog::file::JoinFile [file dirname $data(selectPath)] \
  629.         $data(filter)]
  630.     }
  631.     default {
  632.         set newSpec [::tk::dialog::file::JoinFile [::tk::dialog::file::JoinFile \
  633.             $data(selectPath) $subdir] $data(filter)]
  634.     }
  635.     }
  636.  
  637.     $data(fEnt) delete 0 end
  638.     $data(fEnt) insert 0 $newSpec
  639. }
  640.  
  641. # ::tk::MotifFDialog_ActivateDList --
  642. #
  643. #    This procedure is called when the directory list is activated
  644. #    (double-clicked) by the user.
  645. #
  646. # Arguments:
  647. #     w        The pathname of the dialog box.
  648. #
  649. # Results:
  650. #    None.    
  651.  
  652. proc ::tk::MotifFDialog_ActivateDList {w} {
  653.     upvar ::tk::dialog::file::[winfo name $w] data
  654.  
  655.     if {[string equal [$data(dList) curselection] ""]} {
  656.     return
  657.     }
  658.     set subdir [$data(dList) get [$data(dList) curselection]]
  659.     if {[string equal $subdir ""]} {
  660.     return
  661.     }
  662.  
  663.     $data(fList) selection clear 0 end
  664.  
  665.     switch -- $subdir {
  666.     . {
  667.         set newDir $data(selectPath)
  668.     }
  669.     .. {
  670.         set newDir [file dirname $data(selectPath)]
  671.     }
  672.     default {
  673.         set newDir [::tk::dialog::file::JoinFile $data(selectPath) $subdir]
  674.     }
  675.     }
  676.  
  677.     set data(selectPath) $newDir
  678.     MotifFDialog_Update $w
  679.  
  680.     if {[string compare $subdir ..]} {
  681.     $data(dList) selection set 0
  682.     $data(dList) activate 0
  683.     } else {
  684.     $data(dList) selection set 1
  685.     $data(dList) activate 1
  686.     }
  687. }
  688.  
  689. # ::tk::MotifFDialog_BrowseFList --
  690. #
  691. #    This procedure is called when the file list is browsed
  692. #    (clicked-over) by the user.
  693. #
  694. # Arguments:
  695. #     w        The pathname of the dialog box.
  696. #
  697. # Results:
  698. #    None.    
  699.  
  700. proc ::tk::MotifFDialog_BrowseFList {w} {
  701.     upvar ::tk::dialog::file::[winfo name $w] data
  702.  
  703.     focus $data(fList)
  704.     set data(selectFile) ""
  705.     foreach item [$data(fList) curselection] {
  706.     lappend data(selectFile) [$data(fList) get $item]
  707.     }
  708.     if {[llength $data(selectFile)] == 0} {
  709.     return
  710.     }
  711.  
  712.     $data(dList) selection clear 0 end
  713.  
  714.     $data(fEnt) delete 0 end
  715.     $data(fEnt) insert 0 [::tk::dialog::file::JoinFile $data(selectPath) \
  716.         $data(filter)]
  717.     $data(fEnt) xview end
  718.  
  719.     # if it's a multiple selection box, just put in the filenames 
  720.     # otherwise put in the full path as usual 
  721.     $data(sEnt) delete 0 end
  722.     if {$data(-multiple) != 0} {
  723.     $data(sEnt) insert 0 $data(selectFile)
  724.     } else {
  725.     $data(sEnt) insert 0 [::tk::dialog::file::JoinFile $data(selectPath) \
  726.                   [lindex $data(selectFile) 0]]
  727.     }
  728.     $data(sEnt) xview end
  729. }
  730.  
  731. # ::tk::MotifFDialog_ActivateFList --
  732. #
  733. #    This procedure is called when the file list is activated
  734. #    (double-clicked) by the user.
  735. #
  736. # Arguments:
  737. #     w        The pathname of the dialog box.
  738. #
  739. # Results:
  740. #    None.    
  741.  
  742. proc ::tk::MotifFDialog_ActivateFList {w} {
  743.     upvar ::tk::dialog::file::[winfo name $w] data
  744.  
  745.     if {[string equal [$data(fList) curselection] ""]} {
  746.     return
  747.     }
  748.     set data(selectFile) [$data(fList) get [$data(fList) curselection]]
  749.     if {[string equal $data(selectFile) ""]} {
  750.     return
  751.     } else {
  752.     MotifFDialog_ActivateSEnt $w
  753.     }
  754. }
  755.  
  756. # ::tk::MotifFDialog_ActivateFEnt --
  757. #
  758. #    This procedure is called when the user presses Return inside
  759. #    the "filter" entry. It updates the dialog according to the
  760. #    text inside the filter entry.
  761. #
  762. # Arguments:
  763. #     w        The pathname of the dialog box.
  764. #
  765. # Results:
  766. #    None.    
  767.  
  768. proc ::tk::MotifFDialog_ActivateFEnt {w} {
  769.     upvar ::tk::dialog::file::[winfo name $w] data
  770.  
  771.     set list [MotifFDialog_InterpFilter $w]
  772.     set data(selectPath) [lindex $list 0]
  773.     set data(filter)    [lindex $list 1]
  774.  
  775.     MotifFDialog_Update $w
  776. }
  777.  
  778. # ::tk::MotifFDialog_ActivateSEnt --
  779. #
  780. #    This procedure is called when the user presses Return inside
  781. #    the "selection" entry. It sets the ::tk::Priv(selectFilePath) 
  782. #    variable so that the vwait loop in tk::MotifFDialog will be
  783. #    terminated.
  784. #
  785. # Arguments:
  786. #     w        The pathname of the dialog box.
  787. #
  788. # Results:
  789. #    None.    
  790.  
  791. proc ::tk::MotifFDialog_ActivateSEnt {w} {
  792.     variable ::tk::Priv
  793.     upvar ::tk::dialog::file::[winfo name $w] data
  794.  
  795.     set selectFilePath [string trim [$data(sEnt) get]]
  796.  
  797.     if {[string equal $selectFilePath ""]} {
  798.     MotifFDialog_FilterCmd $w
  799.     return
  800.     }
  801.  
  802.     if {$data(-multiple) == 0} {
  803.     set selectFilePath [list $selectFilePath]
  804.     }
  805.  
  806.     if {[file isdirectory [lindex $selectFilePath 0]]} {
  807.     set data(selectPath) [lindex [glob $selectFilePath] 0]
  808.     set data(selectFile) ""
  809.     MotifFDialog_Update $w
  810.     return
  811.     }
  812.  
  813.     set newFileList ""
  814.     foreach item $selectFilePath {
  815.     if {[string compare [file pathtype $item] "absolute"]} {
  816.         set item [file join $data(selectPath) $item]
  817.     } elseif {![file exists [file dirname $item]]} {
  818.         tk_messageBox -icon warning -type ok \
  819.             -message [mc {Directory "%1$s" does not exist.} \
  820.             [file dirname $item]]
  821.         return
  822.     }
  823.  
  824.     if {![file exists $item]} {
  825.         if {[string equal $data(type) open]} {
  826.         tk_messageBox -icon warning -type ok \
  827.             -message [mc {File "%1$s" does not exist.} $item]
  828.         return
  829.         }
  830.     } else {
  831.         if {[string equal $data(type) save]} {
  832.         set message [format %s%s \
  833.             [mc {File "%1$s" already exists.\n\n} \
  834.             $selectFilePath] \
  835.             [mc {Replace existing file?}]]
  836.         set answer [tk_messageBox -icon warning -type yesno \
  837.             -message $message]
  838.         if {[string equal $answer "no"]} {
  839.             return
  840.         }
  841.         }
  842.     }
  843.     
  844.     lappend newFileList $item
  845.     }
  846.  
  847.     if {$data(-multiple) != 0} {
  848.     set Priv(selectFilePath) $newFileList
  849.     } else {
  850.     set Priv(selectFilePath) [lindex $newFileList 0]
  851.     }
  852.  
  853.     # Set selectFile and selectPath to first item in list
  854.     set Priv(selectFile)     [file tail    [lindex $newFileList 0]]
  855.     set Priv(selectPath)     [file dirname [lindex $newFileList 0]]
  856. }
  857.  
  858.  
  859. proc ::tk::MotifFDialog_OkCmd {w} {
  860.     upvar ::tk::dialog::file::[winfo name $w] data
  861.  
  862.     MotifFDialog_ActivateSEnt $w
  863. }
  864.  
  865. proc ::tk::MotifFDialog_FilterCmd {w} {
  866.     upvar ::tk::dialog::file::[winfo name $w] data
  867.  
  868.     MotifFDialog_ActivateFEnt $w
  869. }
  870.  
  871. proc ::tk::MotifFDialog_CancelCmd {w} {
  872.     variable ::tk::Priv
  873.  
  874.     set Priv(selectFilePath) ""
  875.     set Priv(selectFile)     ""
  876.     set Priv(selectPath)     ""
  877. }
  878.  
  879. proc ::tk::ListBoxKeyAccel_Set {w} {
  880.     bind Listbox <Any-KeyPress> ""
  881.     bind $w <Destroy> [list tk::ListBoxKeyAccel_Unset $w]
  882.     bind $w <Any-KeyPress> [list tk::ListBoxKeyAccel_Key $w %A]
  883. }
  884.  
  885. proc ::tk::ListBoxKeyAccel_Unset {w} {
  886.     variable ::tk::Priv
  887.  
  888.     catch {after cancel $Priv(lbAccel,$w,afterId)}
  889.     catch {unset Priv(lbAccel,$w)}
  890.     catch {unset Priv(lbAccel,$w,afterId)}
  891. }
  892.  
  893. # ::tk::ListBoxKeyAccel_Key--
  894. #
  895. #    This procedure maintains a list of recently entered keystrokes
  896. #    over a listbox widget. It arranges an idle event to move the
  897. #    selection of the listbox to the entry that begins with the
  898. #    keystrokes.
  899. #
  900. # Arguments:
  901. #     w        The pathname of the listbox.
  902. #    key        The key which the user just pressed.
  903. #
  904. # Results:
  905. #    None.    
  906.  
  907. proc ::tk::ListBoxKeyAccel_Key {w key} {
  908.     variable ::tk::Priv
  909.  
  910.     if { $key == "" } {
  911.     return
  912.     }
  913.     append Priv(lbAccel,$w) $key
  914.     ListBoxKeyAccel_Goto $w $Priv(lbAccel,$w)
  915.     catch {
  916.     after cancel $Priv(lbAccel,$w,afterId)
  917.     }
  918.     set Priv(lbAccel,$w,afterId) [after 500 \
  919.         [list tk::ListBoxKeyAccel_Reset $w]]
  920. }
  921.  
  922. proc ::tk::ListBoxKeyAccel_Goto {w string} {
  923.     variable ::tk::Priv
  924.  
  925.     set string [string tolower $string]
  926.     set end [$w index end]
  927.     set theIndex -1
  928.  
  929.     for {set i 0} {$i < $end} {incr i} {
  930.     set item [string tolower [$w get $i]]
  931.     if {[string compare $string $item] >= 0} {
  932.         set theIndex $i
  933.     }
  934.     if {[string compare $string $item] <= 0} {
  935.         set theIndex $i
  936.         break
  937.     }
  938.     }
  939.  
  940.     if {$theIndex >= 0} {
  941.     $w selection clear 0 end
  942.     $w selection set $theIndex $theIndex
  943.     $w activate $theIndex
  944.     $w see $theIndex
  945.     event generate $w <<ListboxSelect>>
  946.     }
  947. }
  948.  
  949. proc ::tk::ListBoxKeyAccel_Reset {w} {
  950.     variable ::tk::Priv
  951.  
  952.     catch {unset Priv(lbAccel,$w)}
  953. }
  954.  
  955. proc ::tk_getFileType {} {
  956.     variable ::tk::Priv
  957.  
  958.     return $Priv(selectFileType)
  959. }
  960.  
  961.