# copyright (C) 1997-2001 Jean-Luc Fontaine (mailto:jfontain@free.fr)
# this program is free software: please read the COPYRIGHT file enclosed in this package or use the Help Copyright menu

set rcsId {$Id: modgui.tcl,v 2.15 2001/01/23 21:55:14 jfontain Exp $}


class moduleOperations {

    proc moduleOperations {this action} {                                                   ;# action can be display, load or unload
        set buttons ho
        if {![string equal $action display]} {
            append buttons c
        }
        set dialog [new dialogBox .grabber\
            -buttons $buttons -default o -die 0 -command "moduleOperations::done $this" -helpcommand "moduleOperations::help $this"\
            -x [winfo pointerx .] -y [winfo pointery .] -deletecommand "delete $this; grab release .grabber"\
        ]
        grab .grabber                                                      ;# grab siblings such as help window so that it is usable
        composite::configure $dialog help -state disabled                     ;# disable module help button until module is selected
        set frame [frame $widget::($dialog,path).frame]
        grid columnconfigure $frame 1 -weight 1
        set ($this,label) [label $frame.label -font $font::(mediumNormal)]
        grid $($this,label) -row 0 -column 0 -sticky nw
        set entry [new comboEntry $frame -font $font::(mediumBold)]
        composite::configure $entry button scroll -height 5
        grid $widget::($entry,path) -row 0 -column 1 -sticky new
        set scroller [new scroller $frame -height 100 -width 200]
        set ($this,container) [frame $widget::($scroller,path).container]
        scroller::display $scroller $($this,container)
        grid rowconfigure $frame 1 -weight 1
        grid $widget::($scroller,path) -row 1 -column 0 -columnspan 2 -sticky nsew
        dialogBox::display $dialog $frame
        set ($this,dialog) $dialog
        set ($this,frame) $frame
        set ($this,entry) $entry
        set ($this,scroller) $scroller
        set ($this,action) $action
        switch $action {
            display {
                composite::configure $dialog -title {moodss: Loaded modules}
                loaded $this 0
            }
            load {
                composite::configure $dialog -title {moodss: Load module}
                discover $this
            }
            unload {
                composite::configure $dialog -title {moodss: Unload module}
                loaded $this 1
            }
        }
        composite::configure $entry -editable 0                                      ;# user is not allowed to input an invalid name
        set ($this,module) {}                                                                                     ;# selected module
    }

    proc ~moduleOperations {this} {
        delete $($this,scroller) $($this,entry)                                              ;# delete objects other than dialog box
    }

    proc discover {this} {
        if {![info exists (discoveredModules)]} {                                                ;# cache modules and their switches
            $($this,label) configure -text {Searching for modules... Found:}
            $($this,frame) configure -cursor watch                                                     ;# show user that we are busy
            update idletasks
            set path $composite::($($this,entry),entry,path)
            modules::available "
                lappend moduleOperations::(discoveredModules) %M
                set moduleOperations::(%M,discoveredSwitches) %S                                             ;# save module switches
                $path delete 0 end
                $path insert 0 %M                                                       ;# show modules one by one for user feedback
                update idletasks
            "
            $($this,frame) configure -cursor {}
            $path delete 0 end
        }
        if {[info exists (discoveredModules)]} {
            $($this,label) configure -text {Select available module:}
            update idletasks
            set modules [lsort $(discoveredModules)]                                             ;# sort modules for easy navigation
            foreach module $modules {
                foreach {option argument} [set ($module,switches) $($module,discoveredSwitches)] {
                    if {$argument} {
                        set ($this,$module,$option) {}
                    } else {
                        set ($this,$module,$option) 0
                    }
                }
            }
            composite::configure $($this,entry) -list $modules -command "moduleOperations::selection $this"
        } else {
            $($this,label) configure -text {Found no modules:}
        }
    }

    proc loaded {this unload} {
        foreach {namespace options} [modules::loaded] {
            lappend namespaces $namespace
            set switches {}
            foreach {switch argument value} $options {
                lappend switches $switch $argument
                set ($this,$namespace,$switch) $value
            }
            set ($namespace,switches) $switches
        }
        if {[info exists namespaces]} {
            if {$unload} {
                $($this,label) configure -text {Select module to unload:}
            } else {
                $($this,label) configure -text {Select loaded module:}
            }
            composite::configure $($this,entry) -list $namespaces -command "moduleOperations::selection $this"
        } else {
            $($this,label) configure -text {No loaded modules:}
            composite::configure $($this,entry) -state disabled
        }
    }

    proc selection {this module} {
        if {[string equal $module $($this,module)]} return
        composite::configure $($this,dialog) help -state normal           ;# enable module help button now that module name is known
        set frame $($this,container)
        eval destroy [grid slaves $frame]                                                  ;# first remove existing switches display
        grid columnconfigure $frame 1 -weight 1
        if {[string equal $($this,action) display]} {                                                 ;# set parameter widgets state
            set state disabled
        } else {
            set state normal
        }
        set row 0
        foreach {option argument} $($module,switches) {
            grid [label $frame.$row,0 -font $font::(mediumBold) -text $option] -padx 5 -sticky w -row $row -column 0
            if {$argument} {
                set path [entry $frame.$row,1\
                    -font $font::(mediumNormal) -width 40 -textvariable moduleOperations::($this,$module,$option) -state $state\
                ]
            } else {
                set path [checkbutton $frame.$row,1 -variable moduleOperations::($this,$module,$option) -state $state]
            }
            grid $path -sticky w -row $row -column 1
            incr row
        }
        if {$row==0} {                                                                                 ;# no options for this module
            grid [label $frame.$row,0 -font $font::(mediumItalic) -text {no options}] -padx 5 -sticky w -row $row -column 0
        }
        set ($this,module) $module
    }

    proc done {this} {
        set delete 1
        set module $($this,module)
        if {[string length $module]>0} {
            switch $($this,action) {
                load {
                    set string $module
                    foreach {option argument} $($module,switches) {
                        if {$argument} {
                            if {[string length $($this,$module,$option)]>0} {
                                append string " $option [list $($this,$module,$option)]"              ;# properly quote option value
                            }
                        } else {
                            if {$($this,$module,$option)} {
                                append string " $option"
                            }
                        }
                    }
                    if {[catch {dynamicallyLoadModules $string} message]} {
                        tk_messageBox -title {moodss: Error loading module} -type ok -icon error -message $message
                        set delete 0
                    }
                }
                unload {
                    dynamicallyUnloadModule $module
                }
            }
        }
        if {$delete} {
            delete $($this,dialog)                                                              ;# which in turn deletes this object
        }
    }

    proc help {this} {                                                                            ;# module must be already selected
        foreach {name index} [modules::decoded $($this,module)] {}                      ;# only name is required, not eventual index
        moduleHelpWindow $name [modules::helpHTMLData $name]
    }

}
