package provide EE 1.2
proc ExtEditor {} {
    global xf ea ee tags

    set xf(ee_on) 1
    if {[winfo exists .ext_edit]} {
	wm deiconify .ext_edit
	raise .ext_edit
	return
    }
    set ee(top) [toplevel .ext_edit -bd 2]
    #wm geometry $ee(top) +100+100
    wm resizable $ee(top) 0 1
    wm title $ee(top) "Extension Editor v1.3"
    wm protocol $ee(top) WM_DELETE_WINDOW EE_Exit
    SetCnfMenuBg

    frame $ee(top).top -relief groove -bd 3
    frame $ee(top).top.d
    #frame $ee(top).top.d.1
    #frame $ee(top).top.d.1.radio
    #frame $ee(top).top.d.2
    frame $ee(top).top.d.line
    frame $ee(top).top.d.check
    #frame $ee(top).middle
    frame $ee(top).lists
    frame $ee(top).buttons -relief groove -bd 3
    frame $ee(top).buttons.d

    label $ee(top).top.d.l1 -text "Extension:"
    entry $ee(top).top.d.e1 -textvariable ea(ext) -width 12
    #pack $ee(top).top.d.1.l -side left
    #pack $ee(top).top.d.1.e -side left

    radiobutton $ee(top).top.d.rl -text "Left mousebutton" \
	    -variable ea(button) -value "L"  -selectcolor palevioletred1 \
	    -bd 2 -relief ridge
    radiobutton $ee(top).top.d.rm -text "Middle mousebutton" \
	    -variable ea(button) -value "M"  -selectcolor palevioletred1 \
	    -bd 2 -relief ridge
    #pack $ee(top).top.d.1.radio.l $ee(top).top.d.1.radio.m -side left
    #pack $ee(top).top.d.1.radio -side right -anchor c
    #pack $ee(top).top.d.1 -side top -fill x
    grid $ee(top).top.d.l1 $ee(top).top.d.e1 $ee(top).top.d.rl $ee(top).top.d.rm -sticky ew -padx 1

    label $ee(top).top.d.l2 -text "Command:"
    set ea(cmdtxt) "Execute"
    menubutton $ee(top).top.d.cmd -textvariable ea(cmdtxt) \
	    -menu $ee(top).top.d.cmd.menu \
	    -width 8 -relief raised -indicatoron true
    set cm [menu $ee(top).top.d.cmd.menu -tearoff 0]
    foreach it {Execute VirtualZip VirtualTar VirtualLha VirtualRpm VirtualRar} {
	$cm add radio -label $it -variable ea(cmdtxt) -value $it
    }
    entry $ee(top).top.d.e2 -textvariable ea(cmd)
    #pack $ee(top).top.d.2.l -side left
    #pack $ee(top).top.d.2.mb -side left
    #pack $ee(top).top.d.2.e -side left -fill x -expand true
    grid $ee(top).top.d.l2 $ee(top).top.d.cmd $ee(top).top.d.e2 - -sticky ew -padx 1 -pady 2
    #pack $ee(top).top.d.2 -side top -fill x -pady 2

    label $ee(top).top.d.l3 -text "Group:"
    set ea(tag) None
    menubutton $ee(top).top.d.tag -textvariable ea(tag) \
	    -menu $ee(top).top.d.tag.menu \
	    -width 5 -relief raised -indicatoron true
    set cm [menu $ee(top).top.d.tag.menu -tearoff 0]
    $cm add radio -label None -variable ea(tag) -value None
    foreach it $tags(tags) {
	$cm add radio -label $it -variable ea(tag) -value $it
    }
    grid $ee(top).top.d.l3 $ee(top).top.d.tag -sticky ew -padx 1
    # left justify labels
    for {set ag 1} {$ag < 4} {incr ag} {
	grid config $ee(top).top.d.l$ag -sticky nws
    }
    #pack $ee(top).top.d.line -side top -fill x -expand true -pady 5
    grid $ee(top).top.d.line
    grid rowconfigure $ee(top).top.d 3 -minsize 10

    checkbutton $ee(top).top.d.check.c -text "Confirm" -variable ea(c) \
	    -bd 2 -relief ridge -selectcolor palevioletred1 -width 13 -anchor w
    checkbutton $ee(top).top.d.check.d -text "Quiet" -variable ea(d) \
	    -bd 2 -relief ridge -selectcolor palevioletred1 -width 13 -anchor w
    checkbutton $ee(top).top.d.check.w -text "OutputWin" -variable ea(w) \
	    -bd 2 -relief ridge -selectcolor palevioletred1 \
	    -width 13 -anchor w
    checkbutton $ee(top).top.d.check.u -text "Update" -variable ea(u) \
	    -bd 2 -relief ridge -selectcolor palevioletred1 -width 13 -anchor w
    pack $ee(top).top.d.check.c $ee(top).top.d.check.d $ee(top).top.d.check.w \
	    $ee(top).top.d.check.u -side left -fill x -expand true
    #grid $ee(top).top.d.check.c $ee(top).top.d.check.d $ee(top).top.d.check.w $ee(top).top.d.check.u -sticky news
    #pack $ee(top).top.d.check -side top -fill x -expand true
    grid $ee(top).top.d.check -columnspan 4 -sticky news -padx 1
    pack $ee(top).top.d -side top -padx 10 -pady 5
    pack $ee(top).top -side top

    label $ee(top).lists.e -text "Ext" ;#-width 10 -anchor center
    label $ee(top).lists.m -text "Button" ;#-width 6 -anchor w
    label $ee(top).lists.c -text "Command" ;#-width 9 -anchor w
    label $ee(top).lists.o -text "Opts" ;#-width 6 -anchor w
    label $ee(top).lists.t -text "Group" ;#-width 6 -anchor w
    grid x $ee(top).lists.e $ee(top).lists.m $ee(top).lists.c $ee(top).lists.o $ee(top).lists.t -sticky nws
    #pack $ee(top).middle.e $ee(top).middle.m $ee(top).middle.c -side left
    #pack $ee(top).middle.o -side right
    #pack $ee(top).middle -side top -fill x -expand true

    button $ee(top).buttons.d.new -text "New" -width 6 -command EE_New
    button $ee(top).buttons.d.rm -text "Remove" -width 6 -command EE_Remove \
	    -cursor pirate
    button $ee(top).buttons.d.save -text "Save" -width 6 -command EE_Save
    button $ee(top).buttons.d.close -text "Close" -width 6 -command EE_Exit
    pack $ee(top).buttons.d.new $ee(top).buttons.d.rm $ee(top).buttons.d.save -side left
    pack $ee(top).buttons.d.close -side right
    pack $ee(top).buttons.d -side top -fill x -padx 10 -pady 5
    pack $ee(top).buttons -side bottom -fill x

    scrollbar $ee(top).lists.s -orient vertical \
	    -command "EE_LBSet yview"
    listbox $ee(top).lists.ext -yscrollcommand EE_LBScroll -width 7 -exportselection false -selectbackground "#dfdfaf" -selectborderwidth 1
    listbox $ee(top).lists.mb -yscrollcommand EE_LBScroll -width 5 -exportselection false -selectbackground "#dfdfaf" -selectborderwidth 1
    listbox $ee(top).lists.cmd -yscrollcommand EE_LBScroll -selectbackground "#dfdfaf" -selectborderwidth 1
    listbox $ee(top).lists.opts -yscrollcommand EE_LBScroll -width 6 -exportselection false -selectbackground "#dfdfaf" -selectborderwidth 1
    listbox $ee(top).lists.tag -yscrollcommand EE_LBScroll -width 6 -exportselection false -selectbackground "#dfdfaf" -selectborderwidth 1

    #pack $ee(top).lists.s -side left -fill y
    #pack $ee(top).lists.ext $ee(top).lists.mb -side left -fill y
    #pack $ee(top).lists.cmd -side left -fill both -expand true
    #pack $ee(top).lists.opts -side left -fill y
    grid $ee(top).lists.s $ee(top).lists.ext $ee(top).lists.mb $ee(top).lists.cmd $ee(top).lists.opts $ee(top).lists.tag -sticky news
    grid columnconfigure $ee(top).lists 3 -weight 1
    grid rowconfigure $ee(top).lists 1 -weight 1
    pack $ee(top).lists -side bottom -fill both -expand true

    foreach l {ext mb cmd opts tag} {
	bind $ee(top).lists.$l <Button-1> {
	    EE_LBSet select clear 0 end
	    EE_LBSet select set [%W nearest %y]
	}
	bind $ee(top).lists.$l <ButtonRelease-1> {
	    EE_LBSet select clear 0 end
	    EE_LBSet select set [%W nearest %y]
	    EE_Select %y
	}
    }
    bind $ee(top).top.d.e1 <Return> {focus $ee(top).top.d.e2}
    bind $ee(top).top.d.e2 <Return> {focus $ee(top)}
    bind $ee(top) <Control-c> EE_Exit
    bind $ee(top) <Escape> EE_Exit

    EE_Display 1 $xf(extensions_file) $xf(tag_file)
    trace variable ea w EE_Update

    EE_Select 0
    foreach w {ext mb cmd opts tag} {
	$ee(top).lists.$w select clear 0 end
	$ee(top).lists.$w select anchor 0
	$ee(top).lists.$w select set anchor 0
    }

}
proc EE_LBSet args {
    global ee
    foreach lb {ext mb cmd opts tag} {
	eval $ee(top).lists.$lb $args
    }
}
proc EE_LBScroll args {
    global ee
    eval $ee(top).lists.s set $args
    EE_LBSet yview moveto [lindex $args 0]
}
proc EE_Select { y } {
    global ee ea

    set ee(%y) $y
    set ind [$ee(top).lists.ext nearest $y]

    trace vdelete ea w EE_Update
    set ea(c) [string match *C* [lindex $ee(opts) $ind]]
    set ea(d) [string match *Q* [lindex $ee(opts) $ind]]
    set ea(w) [string match *W* [lindex $ee(opts) $ind]]
    set ea(u) [string match *U* [lindex $ee(opts) $ind]]
    set ea(ext) [lindex $ee(ext) $ind]
    set tag [lindex $ee(tag) $ind]
    if {[string compare {} $tag] == 0} {
	set tag None
    }
    set ea(tag) $tag
    $ee(top).top.d.e1 icursor end
    set ea(button) [lindex $ee(button) $ind]
    set ea(cmdtxt) [lindex $ee(cmdtxt) $ind]

    switch -glob -- [lindex $ee(cmdtxt) $ind] {
	"VirtualTar" {
	    grid $ee(top).top.d.e2
	    set tmp [string trimleft [lindex $ee(cmd) $ind] "VirtualTar %f "]
	    set ea(cmd) [string trim $tmp \"]
	}
	"Execute" {
	    grid $ee(top).top.d.e2
	    set ea(cmd) [string trimright [lindex $ee(cmd) $ind] &]
	}
	"Virtual*" {
	    grid remove $ee(top).top.d.e2
	    set ea(cmd) "%f"
	}
    }
    $ee(top).top.d.e2 icursor end
    trace variable ea w EE_Update
}
proc EE_Exit {} {
    global ee ea xf

    if {[info exists ee(changed)]} {
	if {$ee(changed)} {
	    set ret [AskWin "You have made changes! Close the editor without saving?" -100 -100 "Save"]
	    switch $ret {
		0 {return}
		2 {EE_Save}
	    }
	}
    }
    trace vdelete ea w EE_Update
    uplevel #0 {source $xf(extensions_file)}
    uplevel #0 {source $xf(tag_file)}
    MakeTagMatch
    set xf(redrawleft) 1
    set xf(redrawright) 1
    UpdBoth
    set xf(ee_on) 0
    SetCnfMenuBg
    destroy $ee(top)
    unset ee
    unset ea
}

proc EE_Update {var index op} {
    global ea ee count

    set ee(changed) 1
    trace vdelete ea w EE_Update
    set ind [$ee(top).lists.ext curselection]
    if {$ea(c)} {
	set c "C"
    } {
	set c ""
    }
    if {$ea(d)} {
	set d "Q"
    } {
	set d ""
    }
    if {$ea(w)} {
	set w "W"
    } {
	set w ""
    }
    if {$ea(u)} {
	set u "U"
    } {
	set u ""
    }

    switch $index {
	c -
	d -
	w -
	u {set ee(opts) [lreplace $ee(opts) $ind $ind [format "%s%s%s%s" $c $d $w $u]]}
	cmdtxt {
	    if {![string match $ea(cmdtxt) [lindex $ee(cmdtxt) $ind]]} {
		switch -glob -- $ea(cmdtxt) {
		    "Execute" {
			set ee(cmd) [lreplace $ee(cmd) $ind $ind {}]
			set ea(cmd) {}
			grid $ee(top).top.d.e2
			focus $ee(top).top.d.e2
		    }
		    "VirtualTar" {
			set ee(cmd) [lreplace $ee(cmd) $ind $ind "$ea(cmdtxt) %f"]
			set ea(cmd) {}
			grid $ee(top).top.d.e2
			focus $ee(top).top.d.e2
		    }
		    "Virtual*" {
			set ee(cmd) [lreplace $ee(cmd) $ind $ind "$ea(cmdtxt) %f"]
			set ea(cmd) "%f"
			grid remove $ee(top).top.d.e2
		    }
		}
		set ee(cmdtxt) [lreplace $ee(cmdtxt) $ind $ind $ea(cmdtxt)]
	    }
	}
	cmd {
	    set ea(cmd) [string trimright $ea(cmd) "&"]
	    switch -glob -- $ea(cmdtxt) {
		"Execute" {set ee(cmd) [lreplace $ee(cmd) $ind $ind $ea(cmd)]}
		"VirtualTar" {
		    if {[string compare $ea(cmd) {}] == 0} {
			set temp [format "%s %%f" $ea(cmdtxt)]
		    } {
			set temp [format "%s %%f \"%s\"" $ea(cmdtxt) $ea(cmd)]
		    }
		    set ee(cmd) [lreplace $ee(cmd) $ind $ind $temp]
		}
		"Virtual*" {
		    set ea(cmd) "%f"
		    set ee(cmd) [lreplace $ee(cmd) $ind $ind \
			    [format "%s %s" $ea(cmdtxt) $ea(cmd)]]
		}
	    }
	}
	tag {
	    set tag $ea($index)
	    if {[string match None $tag]} {
		set tag {}
	    }
	    set ee($index) [lreplace $ee($index) $ind $ind $tag]
	}
	default {
	    set ee($index) [lreplace $ee($index) $ind $ind $ea($index)]
	}
    }
    switch $index {
	button -
	ext {
	    if {[string compare $ea(button) {}] && [string compare $ea(ext) {}]} {
		for {set i 0} {$i < [llength [$ee(top).lists.ext get 0 end]]} {incr i} {
		    set extmb  [format "%s%s" [string trimleft [lindex $ee(ext) $i] .] \
			    [lindex $ee(button) $i]]
		    lappend list $extmb
		}

		if {[set dp [lsearch -exact [lreplace $list $ind $ind] \
			[lindex $list $ind]]] >= 0} {
		    foreach l {ext mb opts cmd tag} {
			$ee(top).lists.$l select clear 0 end
			$ee(top).lists.$l yview $dp
			$ee(top).lists.$l select anchor $dp
			$ee(top).lists.$l select set anchor $dp
		    }
		    if {$dp <= $ind} {
			incr dp
		    }
		    set resp [AskWin "Overwrite the already existing combination ?"]
		    if {$resp == 1} {
			set ee(ext) [lreplace $ee(ext) $dp $dp $ea(ext)]
			set ee(button) [lreplace $ee(button) $dp $dp $ea(button)]
			set ee(cmdtxt) [lreplace $ee(cmdtxt) $dp $dp $ea(cmdtxt)]
			switch -glob -- $ea(cmdtxt) {
			    "Execute" {set ee(cmd) [lreplace $ee(cmd) $dp $dp $ea(cmd)]}
			    "Virtual*" {
				set ea(cmd) "%f"
				set ee(cmd) [lreplace $ee(cmd) $dp $dp \
					[format "%s %s" $ea(cmdtxt) $ea(cmd)]]
			    }
			}
			set ee(opts) [lreplace $ee(opts) $dp $dp \
				[format "%s%s%s%s" $c $d $w $u]]
			set ee(ext) [lreplace $ee(ext) $ind $ind]
			set ee(button) [lreplace $ee(button) $ind $ind]
			set ee(cmdtxt) [lreplace $ee(cmdtxt) $ind $ind]
			set ee(cmd) [lreplace $ee(cmd) $ind $ind]
			set ee(opts) [lreplace $ee(opts) $ind $ind]
			if {[llength $ee(ext)] < [$ee(top).lists.ext size]} {
			    foreach l {ext mb opts cmd tag} {
				$ee(top).lists.$l delete $ind
			    }
			}
			incr count -1
			set ind [expr {$dp-1}]
			focus $ee(top).top.d.e2
		    } {
			set ea(ext) {}
			set ea(button) {}
			set ee(ext) [lreplace $ee(ext) $ind $ind {}]
			set ee(button) [lreplace $ee(button) $ind $ind {}]
			focus $ee(top).top.d.e1
		    }
		} {
		    set this [lindex $list $ind]
		    set list [lsort $list]
		    set nind [lsearch -exact $list $this]
		    if {$nind != $ind} {
			set ee(ext) [lreplace $ee(ext) $ind $ind]
			set ee(button) [lreplace $ee(button) $ind $ind]
			set ee(cmdtxt) [lreplace $ee(cmdtxt) $ind $ind]
			set ee(cmd) [lreplace $ee(cmd) $ind $ind]
			set ee(opts) [lreplace $ee(opts) $ind $ind]
			set ee(ext) [linsert $ee(ext) $nind $ea(ext)]
			set ee(button) [linsert $ee(button) $nind $ea(button)]
			set ee(cmdtxt) [linsert $ee(cmdtxt) $nind $ea(cmdtxt)]
			switch -glob -- $ea(cmdtxt) {
			    "Execute" {set ee(cmd) [linsert $ee(cmd) $nind $ea(cmd)]}
			    "Virtual*" {
				set ea(cmd) "%f"
				set ee(cmd) [linsert $ee(cmd) $nind \
					[format "%s %s" $ea(cmdtxt) $ea(cmd)]]
			    }
			}
			set ee(opts) [linsert $ee(opts) $nind [format "%s%s%s%s" $c $d $w $u]]
			set ind $nind
		    }
		}
	    }
	}
    }


    foreach l {ext mb opts cmd tag} {
	$ee(top).lists.$l delete 0 end
    }

    for {set a 0} {$a < $count} {incr a} {
	$ee(top).lists.ext insert end [lindex $ee(ext) $a]
	$ee(top).lists.mb insert end [lindex $ee(button) $a]
	$ee(top).lists.opts insert end [lindex $ee(opts) $a]
	$ee(top).lists.cmd insert end [lindex $ee(cmd) $a]
	$ee(top).lists.tag insert end [lindex $ee(tag) $a]
    }
    foreach l {ext mb opts cmd tag} {
	$ee(top).lists.$l see $ind
	$ee(top).lists.$l select anchor $ind
	$ee(top).lists.$l select set anchor $ind
    }
    trace variable ea w EE_Update

}

proc EE_Display {open dotfile tagfile} {
    global ee count tcl_platform

    if {$open == 1} {
	if {[catch {source $dotfile} err]} {
	    MessageBox "Opening $dotfile failed: $err"
	}
	if {[catch {source $tagfile} err]} {
	    MessageBox "Opening $tagfile failed: $err"
	}
    }
    set extlist [lsort $extlist]

    set n 0
    foreach z $extlist {
	set pituus [expr {[string length $z]-1}]
	lappend ee(button) [string index $z $pituus]
	set ext [string range $z 0 [expr {$pituus-1}]]
	lappend ee(ext) $ext
	# TODO: tag
	set tag {}
	if {[info exists tags(tags)]} {
	    foreach t $tags(tags) {
		if {[lsearch $tags($t.list) $ext] > -1} {
		    set tag $t
		    break
		}
	    }
	}
	lappend ee(tag) $tag
	set opts [lindex [set $z] 0]
	if {[string match $opts "N"]} {
	    lappend ee(opts) {}
	} {
	    lappend ee(opts) $opts
	}

	#puts "EE1: $z"
	#puts "EE2: [set $z]"
	#puts "EE: [lindex [set $z] 1]"
	switch -glob -- [lindex [set $z] 1] {
	    "exec" {
		lappend ee(cmdtxt) "Execute"
		if {[string match {unix} $tcl_platform(platform)]} {
		    lappend ee(cmd) [string trimright [lrange [set $z] 2 end] &]
		} {
		    lappend ee(cmd) [string trimright [lrange [set $z] 4 end] &]
		}
	    }
	    "VirtualTar" {
		lappend ee(cmdtxt) [lindex [set $z] 1]
		set tmp [lrange [set $z] 1 2]
		if {[llength [set $z]] > 4} {
		    # add command only if one exists
		    append tmp " \"[lindex [set $z] 4]\""
		}
		lappend ee(cmd) $tmp
	    }
	    "Virtual*" {
		lappend ee(cmdtxt) [lindex [set $z] 1]
		lappend ee(cmd) [string trimright [lrange [set $z] 1 2] &]
	    }
	}

	#$ee(top).lists.ext insert end [lindex $ee(ext) $n]
	#$ee(top).lists.mb insert end [lindex $ee(button) $n]
	#$ee(top).lists.opts insert end [lindex $ee(opts) $n]
	#$ee(top).lists.cmd insert end [lindex $ee(cmd) $n]
	#$ee(top).lists.tag insert end [lindex $ee(tag) $n]
	incr n
    }
    eval $ee(top).lists.ext insert end $ee(ext)
    eval $ee(top).lists.mb insert end $ee(button)
    eval $ee(top).lists.opts insert end $ee(opts)
    eval $ee(top).lists.cmd insert end $ee(cmd)
    eval $ee(top).lists.tag insert end $ee(tag)
    set count $n
    unset extlist

}
proc EE_New {} {
    global ee ea count

    set ee(%y) [expr {10 * $count}]
    set ee(changed) 1
    trace vdelete ea w EE_Update
    foreach x {ext button opts cmd tag} {
	lappend ee($x) {}
	set ea($x) {}
    }
    set ea(cmdtxt) "Execute"
    lappend ee(cmdtxt) "Execute"
    incr count

    $ee(top).lists.ext insert end [lindex $ee(ext) $count]
    $ee(top).lists.mb insert end [lindex $ee(button) $count]
    $ee(top).lists.opts insert end [lindex $ee(opts) $count]
    $ee(top).lists.cmd insert end [lindex $ee(cmd) $count]
    $ee(top).lists.tag insert end [lindex $ee(tag) $count]

    foreach l {ext mb opts cmd tag} {
	$ee(top).lists.$l yview moveto 1
	$ee(top).lists.$l select clear 0 end
	$ee(top).lists.$l select anchor $count
	$ee(top).lists.$l select set anchor $count
    }
    foreach x [list c d w u] {
	set ea($x) 0
    }
    focus $ee(top).top.d.e1
    trace variable ea w EE_Update
}
proc EE_Remove {} {
    global ee count

    if {[AskWin "Are You sure ?!"] == 0} {
	return
    }
    set ee(changed) 1
    set ind [$ee(top).lists.ext curselection]
    foreach l {ext mb opts cmd} {
	$ee(top).lists.$l delete $ind
    }
    set var [lindex $ee(ext) $ind][lindex $ee(button) $ind]
    global $var
    catch {unset $var}

    foreach x {ext button cmd cmdtxt opts tag} {
	set ee($x) [lreplace $ee($x) $ind $ind]
    }
    incr count -1

    EE_Select $ee(%y)
}
proc EE_Save {} {
    global ee xf count tags

    MakeSaveDir
    set xf(extensions_file) "$xf(user_home)[file tail $xf(extensions_file)]"
    set out [open $xf(extensions_file).new w]
    set wrong 0

    #parray tags
    # clear the relevant items from tags -array 
    #foreach t $tags(tags) {
	#set tags($t.list) {}
    #}
    #set tags(tags) {}
    for {set i 0} {$i < $count} {incr i} {
	set ext [string trimleft [lindex $ee(ext) $i] .]
	set extmb  [format "%s%s" $ext [lindex $ee(button) $i]]
	set tag [lindex $ee(tag) $i]
	if {[string compare {} $tag] != 0} {
	    # tag defined
	    if {[lsearch $tags($tag.list) $ext] == -1} {
		# not yet included
		lappend tags($tag.list) $ext
	    }
	}

	if {![string match {*[LM]} $extmb] || [string match {[LM]} $extmb]} {
	    foreach l {ext mb opts cmd tag} {
		$ee(top).lists.$l select clear 0 end
		$ee(top).lists.$l yview $i
		$ee(top).lists.$l select anchor $i
		$ee(top).lists.$l select set anchor $i
	    }
	    MessageBox "Not enough for input...\next+mb: $extmb"
	    close $out
	    file delete $xf(extensions_file).new
	    return
	}
	lappend list $extmb

	set cmd [string trimright [lindex $ee(cmd) $i] " &"]
	switch -glob -- [lindex $ee(cmdtxt) $i] {
	    "Execute" {
		set cmdtxt " exec"
		if {![string match *W* [lindex $ee(opts) $i]]} {
		    set bg " &"
		} {
		    set bg ""
		}
	    }
	    "VirtualTar" {
		set cmdtxt ""
		if {[llength $cmd] > 2} {
		    # add cmd only if it exists
		    set bg " \{[lindex $cmd 2]\}"
		} {
		    set bg ""
		}
		set cmd [lrange $cmd 0 1]
		append cmd " %s"
	    }
	    "Virtual*" {set cmdtxt ""; set bg " %s"}
	}
	if {[string match [$ee(top).lists.opts get $i] ""]} {
	    set opts "N"
	} {
	    set opts [lindex $ee(opts) $i]
	}
	set line [format "%s %s %s%s %s%s %s%s%s" "set" $extmb "\[" "list" \
		$opts $cmdtxt $cmd $bg "\]"]
	puts $out $line
    }
    puts $out ""
    puts $out [format "%s %s %s%s %s%s" "set" "extlist" "\[" "list" [lsort $list] "\]"]
    puts $out ""

    close $out
    file rename -force -- $xf(extensions_file).new $xf(extensions_file)
    #parray tags
    # TODO: save changes to tags
    TE_Save
    set ee(changed) 0
    #uplevel #0 {source $xf(extensions_file)}

    $ee(top).buttons.d.save flash
}

# HERE BE DRAGONS! ie. the TagEditor part

# This procedure is the Tag Editor -dialog. It is used to define tags
# for different kind of filetypes, distinguished by the extension.
proc TagEditor {} {
    global xf TAG tags

    set xf(te_on) 1
    if {[winfo exists .tag_edit]} {
	wm deiconify .tag_edit
	raise .tag_edit
	return
    }
    set w [toplevel .tag_edit -bd 2]
    wm iconify $w
    #wm geometry $w +100+100
    wm resizable $w 0 0
    wm title $w "File Group Editor v0.5"
    wm protocol $w WM_DELETE_WINDOW TE_Exit
    SetCnfMenuBg

    # init variables
    set TAG(changed) 0

    # create controls
    set f [frame $w.d -bd 3]

    # create tag listbox
    set t [frame $f.tags]
    label $t.label -text "Groups"
    set TAG(tlist) [listbox $t.list -selectmode single \
	    -selectbackground "#dfdfaf" \
	    -yscrollcommand [list $t.sy set] -height 7 \
	    -width 15 -highlightthickness 1 \
	    -exportselection 0] 
    scrollbar $t.sy -orient vertical -command [list $t.list yview] \
	    -highlightthickness 1 -takefocus 0

    # fill tags
    eval $t.list insert end DIR DEFAULT $tags(tags)

    # create extensions listbox
    set e [frame $f.exts]
    label $e.label -text "Extensions"
    set TAG(elist) [listbox $e.list -selectmode single \
	    -selectbackground "#dfdfaf" \
	    -yscrollcommand [list $e.sy set] -height 7 \
	    -width 15 -highlightthickness 1 \
	    -exportselection 0] 
    scrollbar $e.sy -orient vertical -command [list $e.list yview] \
	    -highlightthickness 1 -takefocus 0

    # fill extensions
    #eval $e.list insert end $tags([lindex $tags(tags) 0].list)
    #$e.list select anchor 0
    #$e.list select set anchor

    # lb buttons
    foreach it [list $t $e] {
	frame $it.b
	button $it.b.add -text "Add..." -width 6 -command [list TE_Edit $it.list 1]
	button $it.b.ed -text "Edit..." -width 6 -command [list TE_Edit $it.list 0]
	button $it.b.del -text "Delete" -width 6 -command [list TE_Del $it.list]

	grid $it.b.add -padx 5 -pady 3 
	grid $it.b.ed -padx 5 -pady 3 
	grid $it.b.del -padx 5 -pady 3 
    }
    # bind lb doubleclick to edit
    bind $t.list <Double-Button-1> {
	# DIR and Default cannot be edited
	if {[%W curselection] > 1} {
	    TE_Edit %W 0
	}
    }
    # bind lb doubleclick to edit
    bind $e.list <Double-Button-1> {TE_Edit %W 0}

    # save attributes of the selected tag
    bind $t.list <1> {
	TE_TagAttr
    }
    # tags list selection changes the contents of extensions list
    bind $t.list <ButtonRelease-1> {
	TE_TagSelect [%W curselection]
    }

    # tag attributes
    #label $f.header -text "Tag attributes:"
    set a [frame $f.attr -bd 3 -relief groove]
    label $a.lf -text "Font:"
    entry $a.ef -textvariable TAG(font) -width 10
    button $a.bf -text "Select..." -width 9 -padx 0 -pady 0 \
	    -highlightthickness 0 -command [list TE_GetItem $a.bf font]

    label $a.lfg -text "Foreground:"
    entry $a.efg -textvariable TAG(fg) -width 10
    button $a.bfg -text "Select..." -width 9 -padx 0 -pady 0 \
	    -highlightthickness 0 -command [list TE_GetItem $a.bfg fg]

    label $a.lbg -text "Background:"
    entry $a.ebg -textvariable TAG(bg) -width 10
    button $a.bbg -text "Select..." -width 9 -padx 0 -pady 0 \
	    -highlightthickness 0 -command [list TE_GetItem $a.bbg bg]

    label $a.ltext -text "Sample file row:"
    set TAG(text) [text $a.text -height 2 -width 40]
    set TAG(text.attr) "-font [lindex [$a.text config -font] end] -fg [lindex [$a.text config -fg] end] -bg [lindex [$a.text config -bg] end]"
    set time [clock format [clock seconds] -format "%d %b %y %H:%M"]
    $a.text insert end "lrwxrwxrwx  $time  123456  File.sample"
    $a.text tag add SAMPLE 0.0 end
    eval $a.text configure -state disabled $tags(DEFAULT.attr)

    # dialog buttons
    frame $f.buttons -relief groove -bd 3
    button $f.buttons.close -text "Close" -width 6 -command TE_Exit
    button $f.buttons.save -text "Save" -width 6 -command {TE_TagAttr; TE_Save}
    button $f.buttons.apply -text "Apply" -width 6 -command {set TAG(changed) 1; TE_TagAttr; TE_SampleTag}

    # show controls 
    grid x x $t.label -sticky nws
    #grid $t.label x x -sticky nws
    #grid $t.list $t.sy $t.b -sticky news
    grid $t.b $t.sy $t.list -sticky news
    grid configure $t.b -sticky ews
    grid columnconfigure $t 0 -weight 1

    grid x x $e.label -sticky nws
    #grid $e.label x x -sticky nws
    #grid $e.list $e.sy $e.b -sticky news
    grid $e.b $e.sy $e.list -sticky news
    grid configure $e.b -sticky ews
    grid columnconfigure $e 0 -weight 1

    grid $a.lf $a.ef $a.bf -sticky ew
    grid $a.lfg $a.efg $a.bfg -sticky ew
    grid $a.lbg $a.ebg $a.bbg -sticky ew
    grid $a.ltext - - -sticky w -pady 3 
    grid $a.text - - -sticky news
    grid columnconfigure $a 1 -weight 1
    grid configure $a.lf $a.lfg $a.lbg -sticky w
    grid configure $a.bf $a.bfg $a.bbg -padx 5

    grid $f.buttons.apply $f.buttons.save $f.buttons.close -sticky w -padx 5 -pady 5
    grid configure $f.buttons.close -sticky e 
    grid columnconfigure $f.buttons 1 -weight 1

    grid $t $e -sticky news
    #grid $f.header - -sticky ws
    grid $a - -sticky news -pady 5 -ipadx 3 -ipady 3
    grid $f.buttons - -sticky news
    grid $f -sticky news

    # rest of dialog init
    # this has to be after creating extensions list and buttons and text
    $t.list select anchor 0
    $t.list select set anchor
    TE_TagSelect 0

    bind $w <Control-c> {TE_Exit}
    bind $w <Escape> {TE_Exit}

    # show dialog
    wm deiconify $w
    tkwait visibility $w
    KeepInScreen $w

    # wait for ok or cancel
    tkwait variable TAG(rc)

    # finalizing procedures
    set xf(te_on) 0
    SetCnfMenuBg
    
    # if changes, make them visible
    uplevel #0 {source $xf(tag_file)}
    MakeTagMatch
    set xf(redrawleft) 1
    set xf(redrawright) 1
    UpdBoth
    unset TAG
    destroy $w
}

# Opens the right attribute dialog for given item and updates the entry
# if necessary.
proc TE_GetItem {btn item} {
    global TAG

    set bg [lindex [$btn config -bg] end]
    $btn config -relief sunken -bg #fcbcbc
    switch $item {
	font {
	    set new [SelectFont $TAG($item)]
	}
	fg -
	bg {
	    set new [tk_chooseColor -initialcolor $TAG($item) -parent .tag_edit -title "Select Color"]	
	}
    }
    $btn config -relief raised -bg $bg
    if {[string compare $TAG($item) $new] == 0 || \
	    [string compare {} $new] == 0} {
	# either no change or canceled
	return
    }
    set TAG(changed) 1
    set TAG($item) $new

    # change the sample to reflect new attributes
    TE_TagAttr
    TE_SampleTag
}

# Gets the current attributes for the selected tag
proc TE_TagAttr {} {
    global TAG tags

    set sel [$TAG(tlist) get [$TAG(tlist) curselection]]
    set tags($sel.attr) {}
    if {[string compare {} $TAG(font)] != 0} {
	append tags($sel.attr) "-font \"$TAG(font)\" "
    }
    if {[string compare {} $TAG(fg)] != 0} {
	append tags($sel.attr) "-foreground \"$TAG(fg)\" "
    }
    if {[string compare {} $TAG(bg)] != 0} {
	append tags($sel.attr) "-background \"$TAG(bg)\""
    }
    #puts $tags($sel.attr)
}

# Selects the given item in tags list
proc TE_TagSelect {ind} {
    global TAG tags

    $TAG(elist) delete 0 end
    set sel [$TAG(tlist) get $ind]
    if {$ind > 1} {
	eval $TAG(elist) insert end [subst $tags($sel.list)]
	$TAG(elist) select anchor 0
	$TAG(elist) select set anchor
	.tag_edit.d.tags.b.ed config -state normal
	.tag_edit.d.tags.b.del config -state normal
	.tag_edit.d.exts.b.add config -state normal
	.tag_edit.d.exts.b.del config -state normal
	.tag_edit.d.exts.b.ed config -state normal
    } {
	.tag_edit.d.tags.b.ed config -state disabled
	.tag_edit.d.tags.b.del config -state disabled
	.tag_edit.d.exts.b.add config -state disabled
	.tag_edit.d.exts.b.del config -state disabled
	.tag_edit.d.exts.b.ed config -state disabled
    }
    if {$ind > 1 && [llength $tags($sel.list)] == 0} {
	# no extensions yet, disable edit and delete
	.tag_edit.d.exts.b.del config -state disabled
	.tag_edit.d.exts.b.ed config -state disabled
    }
    # clear previous
    set TAG(font) {}
    set TAG(fg) {}
    set TAG(bg) {}

    # change the attributes to show current tag
    foreach {item value} $tags($sel.attr) {
	switch -- $item {
	    -font {
		set TAG(font) $value
	    }
	    -foreground {
		set TAG(fg) $value
	    }
	    -background {
		set TAG(bg) $value
	    }
	}
    }

    TE_SampleTag
}

# Shows the sample tag with current configuration
proc TE_SampleTag {} {
    global TAG tags

    set sel [$TAG(tlist) get [$TAG(tlist) curselection]]
    $TAG(text) tag delete SAMPLE 0.0 end
    eval $TAG(text) configure $TAG(text.attr)
    eval $TAG(text) configure $tags(DEFAULT.attr)
    if {[string compare $sel DEFAULT] != 0} {
	# other than default text
	eval $TAG(text) tag configure SAMPLE $tags($sel.attr)
	$TAG(text) tag add SAMPLE 0.0 end
    }
}

# Confirms exit if changes made
proc TE_Exit {} {
    global xf TAG

    set rc 0
    if {$TAG(changed)} {
	set ret [AskWin "You have made changes! Close the editor without saving?" -100 -100 "Save"]
	switch $ret {
	    0 {return}
	    2 {
		TE_Save
		set rc 1
	    }
	}
    }
    set TAG(rc) $rc
}

# Adds/edits the selected list item
proc TE_Edit {lb add} {
    global TAG tags prompt

    if {[string match {*tags*} $lb]} {
	set str "tag"
    } {
	set str "extension"
	set seltag [$TAG(tlist) get [$TAG(tlist) curselection]]
    }

    set ind [$lb curselection]
    set prompt(1.label) {}
    if {$add} {
	# adding
	if {[DialogWin "Add $str:"] == 0} {
	    # canceled
	    unset prompt
	    return
	}
	if {[string match {*tags*} $lb]} {
	    # tag list
	    if {[regexp { } $prompt(1.result)]} {
		MessageBox "Sorry, no spaces allowed!"
		return
	    }
	    if {[lsearch $tags(tags) $item] > -1} {
		MessageBox "Tag with this name exists already!"
		return
	    }
	    lappend tags(tags) $item
	    set tags($item.list) {}
	    set tags($item.attr) {}
	} {
	    regsub { } $prompt(1.result) {\ } item
	    if {[lsearch [subst $tags($seltag.list)] $item] > -1} {
		MessageBox "Extension with this name exists already!"
		return
	    }
	    # extension list
	    lappend tags($seltag.list) $item
	}
    } {
	# editing
	set sel [$lb get $ind]
	set prompt(1.result) $sel
	if {[DialogWin "Edit $str:"] == 0} {
	    # canceled
	    unset prompt
	    return
	}
	if {[string match {*tags*} $lb]} {
	    # tag list
	    if {[regexp { } $prompt(1.result)]} {
		MessageBox "Sorry, no spaces allowed!"
		return
	    }
	    if {[lsearch $tags(tags) $item] > -1} {
		MessageBox "Tag with this name exists already!"
		return
	    }
	    set oldind [lsearch $tags(tags) $sel]
	    set tags(tags) [lreplace $tags(tags) $oldind $oldind $item]
	    set tags($item.list) $tags($sel.list)
	    set tags($item.attr) $tags($sel.attr)
	    unset tags($sel.list)
	    unset tags($sel.attr)
	} {
	    # extension list
	    regsub { } $prompt(1.result) {\ } item
	    if {[lsearch [subst $tags($seltag.list)] $item] > -1} {
		MessageBox "Extension with this name exists already!"
		return
	    }
	    set oldind [lsearch $tags($seltag.list) $sel]
	    set tags($seltag.list) [lreplace $tags($seltag.list) $oldind $oldind $item]
	}
    }
    $lb delete 0 end
    if {[string match {*tags*} $lb]} {
	# tag list
	set tags(tags) [lsort $tags(tags)]
	set ind [lsearch $tags(tags) $item]
	# remember DIR and DEFAULT
	incr ind 2
	eval $lb insert end DIR DEFAULT $tags(tags)
	$lb select anchor $ind
	$lb select set anchor
	TE_TagSelect $ind
	#set sel [$lb get $ind]
	#$TAG(elist) delete 0 end
	#if {$ind > 1} {
	    # not for DIR or DEFAULT
	    #eval $TAG(elist) insert end $tags($sel.list)
	    #$TAG(elist) select anchor 0
	    #$TAG(elist) select set anchor
	#}
    } {
	# extension list
	set tags($seltag.list) [lsort $tags($seltag.list)]
	set ind [lsearch $tags($seltag.list) $item]
	#eval $lb insert end $tags($seltag.list)
	TE_TagSelect [$TAG(tlist) curselection]
	$lb selection clear 0 end
	$lb select anchor $ind
	$lb select set anchor
    }
    unset prompt
    set TAG(changed) 1
}

# Deletes the selected list item
proc TE_Del {lb} {
    global TAG tags

    set ind [$lb curselection]
    set seltag [$TAG(tlist) get [$TAG(tlist) curselection]]
    if {[string match {*tags*} $lb]} {
	# tag list
	set item [lsearch $tags(tags) $seltag]
	set tags(tags) [lreplace $tags(tags) $item $item]
	unset tags($seltag.list)
	unset tags($seltag.attr)
    } {
	# extensions list
	set tags($seltag.list) [lreplace $tags($seltag.list) $ind $ind]
    }
    $lb delete $ind
    if {$ind == [$lb size]} {
	# deleted last item
	incr ind -1
    }
    $lb select anchor $ind
    $lb select set anchor
    TE_TagSelect [$TAG(tlist) curselection]
    set TAG(changed) 1
}

# Saves the tags to configuration file
proc TE_Save {} {
    global xf tags TAG

    MakeSaveDir
    set xf(tag_file) "$xf(user_home)[file tail $xf(tag_file)]"
    set out [open $xf(tag_file).new w]

    puts $out "set tags(tags) \{$tags(tags)\}"
    foreach t $tags(tags) {
	puts $out "set tags($t.list) \{$tags($t.list)\}"
	puts $out "set tags($t.attr) \{$tags($t.attr)\}"
    }
    puts $out "set tags(DIR.attr) \{$tags(DIR.attr)\}"
    puts $out "set tags(DEFAULT.attr) \{$tags(DEFAULT.attr)\}"
    close $out

    file rename -force -- $xf(tag_file).new $xf(tag_file)
    set TAG(changed) 0
    catch {.tag_edit.d.buttons.save flash}
}

