Richard Suchenwirth 2003-03-03 - Here is an enhanced development snapshot of iFile: a little file system browser - see that page for detailed explanations - I stripped lengthy comments from the source for faster editing. Many new features, the biggest chunk being proc introspection. No warranties, but enjoy!
In place of the files font_ce.txt (see Font families workaround) and puts_ce.txt (see puts workaround) sourced below, one might of course just include them here:
if ![llength [info command ::tk::font]] { rename font ::tk::font proc font {cmd args} { switch -- $cmd { f - fa - fam - families { list Bookdings {Courier New}\ Frutiger Tahoma\ {Bitstream Cyberbit}\ {MS Gothic} Sorawin } default { eval ::tk::font $cmd $args } } } } proc redef_puts w { set ::putsw $w if ![llength [info command ::tcl::puts]] { rename puts ::tcl::puts proc puts args { set la [llength $args] if {$la<1 || $la>3} { error "usage: puts ?-nonewline? ?channel? string" } set nl \n if {[lindex $args 0]=="-nonewline"} { set nl "" set args [lrange $args 1 end] } if {[llength $args]==1} { set args [list stdout $args] } foreach {channel s} $args break set s [join $s] ;# (1) prevent braces at leading/tailing spaces if {$channel=="stdout" || $channel=="stderr"} { $::putsw insert end $s$nl } else { set cmd ::tcl::puts if {$nl==""} {lappend cmd -nonewline} lappend cmd $channel $s eval $cmd } } } } #Title: iFile - a little file system browser set version 1.0 set g(about) " iFile $version: a little file system explorer Richard Suchenwirth, Konstanz 2003 Tcl/Tk: [info patchlevel] Exec: [info nameofexecutable] BWidget: [package require BWidget] " #set dir [file dir [info script]] #source [file join $dir font_ce.txt] #source [file join $dir puts_ce.txt] set g(font) {Tahoma 7} option add *Font $g(font) set g(ufont) {{Bitstream Cyberbit} 10} option add *BorderWidth 1 option add *padY 0 set g(sortedby) [set g(sortby) Name] proc drawTree {w} { $w insert end root _ -text / \ -drawcross allways -image $::g(folder) openDir $w _ $w itemconfigure _ -open 1 } proc openDir {w node} { set dc [$w itemcget $node -drawcross] if {$dc=="allways"} { set path [getPath $w $node] cd $path set dirs [glob -nocomp -type d * .??*] set parent $node foreach dir [lsort -unique -dic $dirs] { regsub -all {[^A-Za-z0-9]}\ $path/$dir _ node if [llength [glob -noc -type d \ [file join $path $dir *]]] { set dc allways } else {set dc never} $w insert end $parent $node -text $dir\ -drawcross $dc -image $::g(folder) } $w itemconfigure $parent \ -drawcross auto } set g(marked) "" } proc getPath {w node} { set res "" while {$node != "root"} { set res [$w itemcget $node -text]/$res set node [$w parent $node] } string range $res 1 end ;# avoid leading // } proc selectDir {w dir} { global g if ![file exists $dir] { set dir [getPath $w $dir] } cd $dir wm title . [set g(2) [pwd]] $g(lb) delete [$g(lb) items] set mode -dic switch -- $g(sortby) { Name {set index 1} Type {set index 0} Size {set index 3; set mode -integer} Date {set index 5} } set n -1 set dirs "" foreach i [glob -noc -type d *] { set t [list . [format %-14s $i] -] lappend t [llength [glob -noc $i/*]] files lappend t [dateTime [file mtime $i]] lappend dirs $t } foreach i [lsort $mode $g(dir) -index $index $dirs] { set t [join [lrange $i 1 end]] $g(lb) insert end [incr n] \ -image $g(folder) -text [string map {" - " \t} $t] } set files {} foreach i [glob -noc -type f $g(filter)] { set size [format %5d [file size $i]] lappend files [list [file extension $i] \ [format %-14s $i] - $size B\ [dateTime [file mtime $i]]] } foreach i [lsort $mode $g(dir) -index $index $files] { set t [join [lrange $i 1 end]] $g(lb) insert end [incr n]\ -image $g([fileimage [lindex $i 0]]) \ -text [string map {" - " \t} $t] } .n raise 2 $g(lb) bindImage <1> [list after 9 selectFile $g(lb)] $g(lb) bindText <ButtonRelease-1> [list after 9 markFile $g(lb)] $g(lb) bindText <Double-1> [list after 9 selectFile $g(lb)] set g(filterCmd) selectDir } proc fileimage f { switch -- [file extension $f] { .gif - .ppm - .xbm {return palette} default {return file} } }
When a file is tapped on, a displayer is selected depending on directory attribute or extension:
proc selectFile {w item} { global g set fn [$w itemcget $item -text] regexp {(.+?) *\t} $fn -> fn if [file isdir $fn] { set g(filter) * selectDir $g(tree) [file join [pwd] $fn] return } $g(text) delete 1.0 end switch -- [file extension $fn] { .txt - .tcl - .cfg - .htm {set t [readFile $fn]} .gif - .ppm { set t [render $fn $g(text) photo] } .xbm { set t [render $fn $g(text) bitmap] } default {set t [$g(unk) $fn]} } if {$g(enc) != [encoding system]} { $g(text) config -font $g(ufont) \ -height 14 -width 30 } else { $g(text) config -font $g(font) \ -height 21 -width 43 } $g(text) insert end $t focus $g(text) wm title . [set g(3) $fn] .n raise 3 } proc hexdump fn { set res "" set fp [open $fn] fconfigure $fp -translation binary for {set i 0} {$i<64} {incr i} { set s [read $fp 16] if {$s==""} break binary scan $s H* hex regsub -all (..) $hex {\1 } hex regsub -all {[^ -~]} $s . asc set hexpos [format %.3X0 $i] append res $hex \t\ [format %-16s $asc] \t\ $hexpos \n } close $fp set res } proc copyFile fn { if {$fn==""} return set n [llength [glob -noc "Copy*$fn"]] set no [expr {$n? " [incr n]": ""}] file copy $fn "Copy$no of $fn" selectDir - . } proc deleteFile fn { if {$fn==""} return set msg "OK to delete file\n[infoFile $fn 1]?" set answer [tk_messageBox -type yesno -default no -icon question -message $msg] if {$answer} { file delete -force $fn selectDir - . } } proc markFile {w item} { global g set fn [$w itemcget $item -text] regexp {(.+?) *\t} $fn -> fn if ![file exists $fn] return set g(marked) $fn $g(props) delete 1.2 end ;# keep icon $g(props) insert end [infoFile $fn] } proc readFile fn { set fp [open $fn] set t [read $fp 2] if {$t=="\xff\xfe"} { set ::g(enc) unicode } else {seek $fp 0} fconfigure $fp -encoding $::g(enc) set res [read $fp] close $fp set res } proc newFolder w { file mkdir "New Folder" selectDir - . } proc renameFile w { set item [$w selection get] set fn [$w itemcget $item -text] regexp {(.+?) *\t} $fn -> fn set fn2 [$w edit $item $fn newname] if {$fn2!=""} { file rename $fn $fn2 selectDir - . } } proc newname fn {expr ![file exists $n]} proc listProcs {w {filt ""}} { global g if {$filt !=""} {set g(filter) $filt} $w delete [$w items] set n -1 foreach i [lsort [info procs $g(filter)]] { $w insert end [incr n] -text $i } $w bindText <ButtonRelease-1> [list after 9 selectProc $w] set g(2) "iFile: procs" .n raise 2 set g(filterCmd) listProcs } proc selectProc {w item} { global g set t [$w itemcget $item -text] $g(text) delete 1.0 end $g(text) insert end [showProc $t] set g(3) "iFile: proc $t" .n raise 3 } proc showProc name { set args {} foreach arg [info args $name] { if [info default $name $arg t] { lappend arg $t } lappend args $arg } set body [expr {[info exists ::auto_index($name)]? "\n# $::auto_index($name)\n" : ""}] append body [info body $name] list proc $name $args $body } proc render {fn w type} { global g catch {image delete $g(i)} set i [image create $type -file $fn] $w image create end -image $i set g(i) $i return [image width $i]x[image height $i] } proc infoFile {fn {brief 0}} { set res $fn\n\n append res "Folder:\t[pwd]\n" append res "Size:\t" append res "[file size $fn] Bytes\n" foreach i {atime mtime} { append res \ "$i:\t[dateTime [file $i $fn]]\n" } if {!$brief} { foreach {key val} [file attr $fn] { set k [format %-12s $key:] append res \n$k\t$val } } set res } proc dateTime t { clock format $t \ -format %y-%m-%d,%H:%M:%S } #------------------------- Image scaling proc scaleImage {im xfactor {yfactor 0}} { set mode -subsample if {abs($xfactor) < 1} { set xfactor [expr round(1./$xfactor)] } elseif {$xfactor>=0 && $yfactor>=0} { set mode -zoom } if {$yfactor == 0} {set yfactor $xfactor} set t [image create photo] $t copy $im $im blank $im copy $t -shrink $mode $xfactor $yfactor image delete $t } #------ borrow images from BWidget: set g(images) {folder info palette} foreach i $g(images) { set g($i) [image create photo -file $BWIDGET::LIBRARY/images/$i.gif] } set g(file) [image create photo -data { R0lGODlhEAAQAIUAAPwCBFxaXNze3Ly2rJSWjPz+/Ozq7GxqbJyanPT29HRy dMzOzDQyNIyKjERCROTi3Pz69PTy7Pzy7PTu5Ozm3LyqlJyWlJSSjJSOhOzi 1LyulPz27PTq3PTm1OzezLyqjIyKhJSKfOzaxPz29OzizLyidIyGdIyCdOTO pLymhOzavOTStMTCtMS+rMS6pMSynMSulLyedAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAQABAAAAaQ QIAQECgajcNkQMBkDgKEQFK4LFgLhkMBIVUKroWEYlEgMLxbBKLQUBwc52Hg AQ4LBo049atWQyIPA3pEdFcQEhMUFYNVagQWFxgZGoxfYRsTHB0eH5UJCJAY ICEinUoPIxIcHCQkIiIllQYEGCEhJicoKYwPmiQeKisrKLFKLCwtLi8wHyUl MYwM0tPUDH5BACH+aENyZWF0ZWQgYnkgQk1QVG9HSUYgUHJvIHZlcnNpb24g Mi41DQqpIERldmVsQ29yIDE5OTcsMTk5OC4gQWxsIHJpZ2h0cyByZXNlcnZl ZC4NCmh0dHA6Ly93d3cuZGV2ZWxjb3IuY29tADs=}] #-------- The notebook and its pages: NoteBook .n -internalborderwidth 0 pack .n set 1 [.n insert end 1 -text Tree -raisecmd {wm title . iFile}] set 2 [.n insert end 2 -text Files -raisecmd {wm title . $g(2)}] set 3 [.n insert end 3 -text File -raisecmd {wm title . $g(3)}] set g(3) "iFile - No file selected" set 4 [.n insert end 4 -text Props -raisecmd {wm title . "iFile properties"}] set 5 [.n insert end 5 -text % -raisecmd { wm title . "iFile console" focus $g(ce) }] set 6 [.n insert end 6 -text Setup -raisecmd {wm title . "iFile setup"}] #-----------------------------Tree page set g(tree) [Tree $1.t -width 27 -height 19 \ -deltax 16 -deltay 13 \ -yscrollcommand "$1.y set" \ -opencmd [list openDir $1.t]] scrollbar $1.y -command "$1.t yview" grid $1.t $1.y -sticky ns $1.t bindImage <1> [list + after 9 selectDir $1.t] $1.t bindText <1> [list + after 9 selectDir $1.t] #----------------------------- Files page frame $2.f label $2.f.0 -text "Filter: " entry $2.f.e -textvar g(filter) -width 5 bind $2.f.e <Return> {$g(filterCmd) $g(lb) .} set g(filter) * button $2.f.c -text * -command {set g(filter) *} button $2.f.up -text Up -command { if {[pwd]!="\\"} { set g(filter) * selectDir $g(tree) .. }} set g(ab) [ArrowButton $2.f.ab -fg blue -activeforeground blue \ -command toggleOrder -relief flat] label $2.f.1 -text "Sort by: " ComboBox $2.f.cb -width 5 -editable 0 -textvariable g(sortby) -values {Name Type Size Date} set g(dir) -incr proc toggleOrder {} { global g switch -- [$g(ab) cget -dir] { top {set g(dir) -decr; set t bottom} bottom {set g(dir) -incr; set t top} } $g(ab) configure -dir $t after 50 {selectDir - .} } eval pack [winfo children $2.f] -side left grid $2.f - -sticky news set g(lb) [ListBox $2.l -bg white -height 15 -padx 18 \ -width 27 -yscrollcommand "$2.y set" -selectmode single] scrollbar $2.y -command "$2.l yview" grid $2.l $2.y -sticky ns #------------------------------- File page grid [ScrolledWindow $3.sw -auto both] -sticky news set g(text) [text $3.sw.t -wrap word -height 21 -width 43] $3.sw setwidget $3.sw.t proc saveText {w {name ""}} { if {$name==""} {set name [tk_getSaveFile]} if {$name!=""} { set fp [open $name w] fconfigure $fp -encoding $::g(enc) if {$::g(enc)=="unicode"} {puts -nonewline $fp \ufeff} puts $fp [$w get 1.0 end-1c] close $fp selectDir - . } } #--------------------- Prop(ertie)s page set g(props) [text $4.t -bg [.n cget -bg] \ -height 20 -width 45 -relief flat] grid $4.t -sticky news $4.t image create 1.0 -image $g(info) $4.t insert end $g(about) #-------------------- % (Console) page set g(ce) [ComboBox $5.e -textvariable g(cmd)] set g(chist) {{}} $5.e bind <Return> "ceval $5.t" set g(ct) [text $5.t -height 14 -width 43 -yscrollcommand "$5.y set"] foreach c {red blue black} { $5.t tag config $c -foreground $c } redef_puts $g(ct) scrollbar $5.y -command "$5.t yview" label $5.l -text "\n\nIntentionally\nleft\nblank\n\n" grid $5.e - -sticky ew grid $5.t $5.y -sticky ns grid $5.l proc ceval {text} { global g set cmd $g(cmd) $text insert end $cmd\n blue if [catch {uplevel #0 $cmd} res] { set tag red } else { set tag black if {[lsearch -exact $g(chist) $cmd]<0} { set g(chist) [lrange \ [linsert $g(chist) 1 $cmd] 0 511] $g(ce) configure -values $g(chist) set g(cmd) "" } } set dir [file tail [pwd]] if {$res!=""} {$text insert end $res\n $tag} $text insert end "($dir) % " blue $text see end } #---------------------------- Setup page label $6.info -image $g(info) message $6.00 -text $g(about) -aspect 1000 grid $6.info $6.00 - -sticky nw label $6.0 -text Encoding ComboBox $6.enc -text Encoding \ -textvariable g(enc) \ -values [lsort -dic [encoding names]] -editable 0 set g(enc) [encoding system] button $6.c -text system -command { set g(enc) [encoding system] } grid $6.0 $6.enc $6.c -sticky news label $6.1 -text "ASCII font" entry $6.af -textvariable g(font) grid $6.1 $6.af -sticky ew label $6.2 -text "Unicode font" entry $6.uf -textvariable g(ufont) grid $6.2 $6.uf -sticky ew label $6.3 -text Unknown? ComboBox $6.uk -values { readFile hexdump } -textvariable g(unk) -editable 0 set g(unk) hexdump grid $6.3 $6.uk -sticky ew trace variable g(sortby) w "selectDir $1.t .;#" label $6.4 -text File/wrap checkbutton $6.wr -onvalue word \ -offvalue none -command { $g(text) config -wrap $g(wrap) after 10 .n raise 3 } -variable g(wrap) set g(wrap) word grid $6.4 $6.wr -sticky w #---- place-holder to push others up: grid [label $6.end -text \n\n\n\n] #------------------------------------Menu proc m+ {menu label cmd} { .m.$menu add command -label $label -command $cmd } proc m++ {menu label} { .m add casc -label $label -menu \ [menu .m.$menu -tearoff 0] } . config -menu [menu .m] m++ file File m+ file Hexdump { $g(text) delete 1.0 end $g(text) insert end [hexdump $g(marked)] .n raise 3 } m+ file "New Folder" {newFolder $g(lb)} m+ file Rename {renameFile $g(lb)} m+ file Run {exec wish $g(marked) &} m+ file Copy {copyFile $g(marked)} m+ file Delete {deleteFile $g(marked)} .m.file add separator m+ file Restart {exec wish $argv0 &; exit} m+ file Exit exit m++ image Image foreach i {3 2 0.5 0.33} { m+ image "Zoom x $i" "scaleImage \$g(i) $i" } .m.image add separator m+ image "Flip LR" {scaleImage $g(i) -1 1} m+ image "Flip TB" {scaleImage $g(i) 1 -1} m+ image "Flip both" {scaleImage $g(i) -1 -1} m++ text Text m+ text "Save as..." {saveText $g(text)} m+ text Clear {$g(text) delete 1.0 end} m+ text Eval { set g(cmd) [$g(text) get 1.0 end-1c] ceval $g(ct) .n raise 5 } m++ sel Select m+ sel Color {append $g(cmd) " " [SelectColor .c]} m+ sel Font {append $g(cmd) " {[SelectFont .f]}"} m+ sel Proc {listProcs $g(lb) *} #----------- Final steps to get started: selectDir - / drawTree $1.t .n raise 1 wm geometry . +0+1 update # 8.4a2 workaround: transparency lappend g(images) file foreach i $g(images) { $g(text) image create end -image $g($i) scaleImage $g($i) 2 scaleImage $g($i) 0.5 }