# -*- tcl -*-
# Main installation script for ActiveTcl
# --------------------------------------
#
# Copyright 2001, ActiveState Corp.
# All Rights Reserved.

package require ActiveTcl 8.3.3.3
package require Tk
package require BWidget

option add *Button.highlightthickness 1
option add *Scrollbar.highlightthickness 1
option add *Text.highlightthickness 1
option add *Label.highlightthickness 0
option add *Label.borderWidth 0



proc main {} {
    wm protocol . WM_DELETE_WINDOW cancel

    if {$::AT(DEBUG)} {
	wm title . "$::AT(Company) $::AT(NAME) $::AT(VERSION) (Debug) Installer"
    } else {
	wm title . "$::AT(Company) $::AT(NAME) $::AT(VERSION) Installer"
    }

    # Read the logo and create an image from it.
    # FIX: We need the version of the Tcl that we are installing, not
    # that of the installer, which may differ.
    #set inst_version [string range $::AT(VERSION) 0 2]
    foreach file [list [file join $::SCRIPT_DIR lib tk$::tcl_version \
			    images ActiveTclSplash.gif] \
		      [file join $::tk_library images ActiveTclSplash.gif]] {
	if {[file exists $file]} {
	    set logo [image create photo -file $file]
	    break
	}
    }

    set left [frame .left]
    set ::BASE [PagesManager .right]
    set sep  [frame .sep -height 2 -bd 2 -relief sunken]
    set ::BTNS [frame .btns]

    label $left.logo -image $logo
    pack  $left.logo -expand 0 -fill both -side top

    grid $left $::BASE -sticky news
    grid $sep -columnspan 2 -sticky ew
    grid $::BTNS -columnspan 2 -sticky ew
    grid columnconfigure $::BTNS 0 -weight 1
    grid columnconfigure . 1 -weight 1
    grid rowconfigure    . 0 -weight 1

    set pady [expr {($::tcl_version > 8.3) ? 2 : 0}]
    set ::CANCEL [button $::BTNS.cncl -text "Cancel" -width 8 -pady $pady \
		      -command { cancel }]
    set ::NEXT   [button $::BTNS.next -text "Next >" -width 8 -pady $pady \
		      -command {set ::WAIT 1}]
    set ::BACK   [button $::BTNS.back -text "< Back" -width 8 -pady $pady \
		      -command {set ::WAIT -1}]

    grid $::BACK $::NEXT $::CANCEL -sticky e -padx 6 -pady 8

    # By default, invoke the Next button on <Return>
    bind . <Key-Return> { next }

    # Magic debug console invocation
    bind . <Triple-3> { catch {console show} }

    # Initial license acceptance parameter
    set ::ACCEPT 0
    # Default install directory
    set ::INSTALL_DIR [default_installdir]
    # Default install error message
    set ::ERRMSG ""

    if {0} {
	# Bugzilla 19731 ... 
	if {[string equal "windows" $::tcl_platform(platform)]} {
	    set ::ADMIN [has_admin_permissions]
	} else {
	    set ::ADMIN 1 ; # Fake for unix
	}
    }

    # Note: The procedures open and manipulate the user interface.
    # They use [vwait] to enter the eventloop where needed so that
    # sequencing control is not taken from [main].

    set state 1
    while {$state} {
	#puts =$state
	switch -exact $state {
	    1 { incr state [intro $::BASE] }
	    2 { incr state [license $::BASE] }
	    3 {
		# This page is always skipped when backstepping
		# from get_installdir.
		if {[string equal $::AT(MODE) lite]} {
		    # Just skip this. A similar check was done
		    # as part of the intro page.
		    incr state
		} else {
		    incr state [check_previous_install $::BASE]
		}
	    }
	    4 { incr state [get_installdir $::BASE] }
	    5 { incr state [overinstall $::BASE] }
	    6 { incr state [get_demodir $::BASE] }
	    7 {
		# This page is always skipped when backstepping from [install_ready]
		if {[string equal $::tcl_platform(platform) windows]} {
		    # This is not relevant for windows. Therefore skip the page.
		    incr state
		} else {
		    incr state [get_runtimedir $::BASE]
		}
	    }
	    8 { incr state [plugin_setup  $::BASE]}
	    9 {	incr state [install_ready $::BASE] }
	    10 {
		#puts Done
		exit 0
	    }
	    default {
		return -code error "Unknown run state \"$state\""
	    }
	}
    }
    #puts =$state
}

# ----------------------------------------------

proc intro {pages} {
    set pname intro
    set page [$pages getframe $pname]

    set welcome_msg $::WELCOME
    set next 1
    
    if {![winfo exists $page]} {
	# This check has to be done only once.
	# And if there is trouble there is neither next nor
	# backstepping from a later page.

	if {[string equal $::AT(MODE) lite]} {
	    foreach {ok msg} [lookfor_previous_install $::BASE] break
	    if {!$ok} {
		set welcome_msg $msg
		set fg red
		set next 0
	    } elseif {$msg != {}} {
		append welcome_msg \n $msg
	    }
	}

	set page [$pages add $pname]

	text $page.msg \
	    -wrap word -tabs {5m 10m 28m 40m 55m 65m 80m} \
	    -width 80 \
	    -bg [$::CANCEL cget -bg] \
	    -relief flat

	$page.msg insert end $welcome_msg
	$page.msg configure -state disabled

	grid $page.msg -sticky news -padx 8 -pady 4
	grid rowconfigure    $page 0 -weight 1
	grid columnconfigure $page 0 -weight 1

	#$pages compute_size
    }
    $pages raise $pname

    # Return value to move to next state, no BACK button for this one

    if {$next} {
	return [wait_next 0]
    } else {
	return [wait_next 0 0 "Exit"]
    }
}

proc license_ok {} {
    $::NEXT configure -state [expr {$::ACCEPT ? "normal" : "disabled"}]
}

proc disable_next {} {
    $::NEXT configure -state disabled
}

proc license {pages} {
    set pname license
    set page [$pages getframe $pname]
    if {![winfo exists $page]} {
	set page [$pages add $pname]
	grid [ScrolledWindow $page.s -auto both] -sticky news -padx 4 -pady 4
	set tw [text $page.s.t -height 5 -wrap word]
	$page.s setwidget $tw

	radiobutton $page.ok -variable ::ACCEPT -value 1 -anchor w \
		-command license_ok \
		-text "I accept the terms in the License Agreement"
	radiobutton $page.no -variable ::ACCEPT -value 0 -anchor w \
		-command license_ok \
		-text "I do not accept the terms in the License Agreement"
	grid $page.ok -stick we
	grid $page.no -stick we

	grid columnconfigure $page 0 -weight 1
	grid rowconfigure    $page 0 -weight 1

	$tw insert end [license_text]
	$tw configure -state disabled

	# Accept focus even when disabled
	bind $tw <1>		{ focus %W }
	bind $tw <Key-Return>	{ next }

	# On windows this resizes the installer window, causing a gap
	# between the bottom of the logo and the separator, seemingly
	# because of different vertical sizes for the scroll window
	# and the radio buttons.

	#$pages compute_size
    }
    after idle license_ok
    $pages raise $pname

    # Return value to move to next state
    return [wait_next]
}

# ----------------------------------------------
# INSTALLATION CHECK ROUTINES
# ----------------------------------------------

proc lookfor_previous_install {pages} {
    # This procedure is similar to ''check_previous_install'' (see
    # after this proc). Instead of asking to uninstall a previous
    # installation it wants to have such. This is used by the
    # 'lite'  distribution to find the ActiveTcl installation to
    # upgrade.

    # Note that in contrast to ''check_previous_install'' this
    # procedure does not constitute its own page. It is called
    # by the ''intro'' page procedure and returns an error code
    # (0 = error, 1 = ok) and a message. The message can be set
    # even if there are no problems.

    # We can't do this for Unix. For these platforms the check is
    # done after querying the user for a directory.

    if {![string equal "windows" $::tcl_platform(platform)]} { return {1 ""} }

    package require registry

    set next 1
    set msg ""
    set keyp {HKEY_LOCAL_MACHINE\SOFTWARE\ActiveState\TclDevKit}
    set keya {HKEY_LOCAL_MACHINE\SOFTWARE\ActiveState\ActiveTcl}

    if {![catch {registry get $keyp "CurrentVersion"} ver_dummy]} {
	# We have Tcl/DevKit already, no need to install it.

	set msg "$::AT(PGROUP) $ver_dummy is already installed. \
		\nIt is not possible to install $::AT(PGROUP) $::AT(VERSION)."
	set next 0

    } elseif {[catch {registry get $keya "CurrentVersion"} ver]} {
	# There is no ActiveTcl installed. Lite cannot be installed.

	# FIXME: We might want to check for an installation
	# of Tcl/DevKit to give a more accurate error message.

	set msg "No installation of ActiveTcl found. \
		\nIt is not possible to install $::AT(NAME)."
	set next 0
    } else {
	# ActiveTcl found, but is it ok too ?

	if {[catch {registry get "$keya\\$ver" ""} verdir]} {
	    # This means that Lite should not be installed, it
	    # would mean trouble.

	    set msg "Previously installed version \"$ver\"\
		    partially uninstalled.\
		    It is not possible to use \"$::AT(NAME)\"."
	    set next 0
	} elseif {[string match "8.3.3.2" $ver]} {
	    set msg "You are currently using ActiveTcl $ver.\
		    \n\t(installed in $verdir)\
		    \n\n$::AT(NAME) $::AT(VERSION) cannot be used\
		    with this installation.\nPlease install\
		    ActiveTcl 8.3.4.1 or higher."
	    set next 0
	} elseif {
	    ([regexp -all {\.} $ver] == 3) &&
	    [package vsatisfies $ver 8.3.3.2]
	} {
	    # It is of type M.m.p.build and is >= 8.3.3.2
	    # If it satisfies 8.3.4.1. installation may proceed

	    if {[package vsatisfies $ver 8.3.4.1]} {
		set msg "Upgrading ActiveTcl $ver \
			(installed in $verdir)\nusing\
			$::AT(NAME) $::AT(VERSION)"
		# Use the location of ActiveTcl for our installation too.
		set ::INSTALL_DIR $verdir
	    } else {
		set msg "You are currently using ActiveTcl $ver.\
			\n\t(installed in $verdir)\
			\n\n$::AT(NAME) $::AT(VERSION) cannot be used\
			with this installation. Please install\
			ActiveTcl 8.3.4.1 or higher."
		set next 0
	    }
	} else {
	    set msg "Unrecognized installed ActiveTcl version \"$ver\".\
		    \n\n$::AT(NAME) $::AT(VERSION) cannot be used\
		    with this installation."
	    set next 0
	}
    }

    ## The checking is done, now show the results.

    if {![string length $msg]} {
	set msg "Internal error, no message was set"
	set next 0
    }

    return [list $next $msg]
}

proc check_previous_install {pages} {
    # The purpose of this is to verify how we will interact with
    # previous installations.  At this point, it only helps uninstall
    # ActiveTcl 8.3.3.2 since that had no uninstaller.

    if {![string equal "windows" $::tcl_platform(platform)]} { return 1 }

    package require registry

    set msg ""
    set key "HKEY_LOCAL_MACHINE\\SOFTWARE\\ActiveState\\$::AT(PGROUP)"

    if {![catch {registry get $key "CurrentVersion"} ver]} {
	if {[catch {registry get "$key\\$ver" ""} verdir]} {
	    set msg "Previously installed version \"$ver\"\
		    partially uninstalled."
	} elseif {[string equal $::AT(MODE) normal] && [string match "8.3.3.2" $ver]} {
	    set msg "You are currently using a previous install\
		    of $::AT(PGROUP) $ver.\
		    \n\t(installed in $verdir)\
		    \n\nDo you want to uninstall this before continuing?"

	    button $::BTNS.unst -text "Uninstall 8.3.3.2" \
		    -command [subst {
		uninstall-8.3.3.2 [list [file join $verdir]]
		# We restart this screen to start the process over.
		destroy $::BTNS.unst
		# The value one means continue after finishing uninstall
		set ::WAIT 1
	    }
	    ]
	    grid $::BTNS.unst -row 0
	} elseif {[regexp -all {\.} $ver] == 3} {
	    if {[string equal $::AT(MODE) normal] && [package vsatisfies $ver 8.3.3.2]} {
		# It is of type M.m.p.build and is >= 8.3.3.2
		#
		set msg "You are currently using a previous install\
			of $::AT(PGROUP) $ver.\
			\n\t(installed in $verdir)\
			\n\It is recommended that you uninstall this before\
			continuing."
	    } elseif {[string equal $::AT(MODE) pro] && [package vsatisfies $ver 1.5.0.1]} {
		# It is of type M.m.p.build and is >= 1.5.0.1
		#
		set msg "You are currently using a previous install\
			of $::AT(PGROUP) $ver.\
			\n\t(installed in $verdir)\
			\n\It is recommended that you uninstall this before\
			continuing."
	    } else {
		set msg "Unrecognized installed $::AT(PGROUP) version \"$ver\"."
	    }
	} elseif {[regexp -all {\.} $ver] == 1} {
	    # Bugzilla 19735 ...
	    # Version is of type M.n . First product with that number of dots so "TclDevKit 2.0"

	    if {[string equal $::AT(MODE) pro] && [package vsatisfies $ver 2.0]} {
		# It is of type M.n and is >= 2.0
		#
		set msg "You are currently using a previous install\
			of $::AT(PGROUP) $ver.\
			\n\t(installed in $verdir)\
			\n\It is recommended that you uninstall this before\
			continuing."
	    } else {
		set msg "Unrecognized installed $::AT(PGROUP) version \"$ver\"."
	    }
	} else {
	    set msg "Unrecognized installed $::AT(PGROUP) version \"$ver\"."
	}
    }

    if {[string length $msg]} {
	set page [$pages getframe cinst]
	if {![winfo exists $page]} {
	    set page [$pages add cinst]
	    label $page.msg -anchor nw -justify left -width 70
	    grid $page.msg -sticky new -padx 8 -pady 4
	    grid rowconfigure $page 0 -weight 1
	    grid columnconfig $page 0 -weight 1
	}
	$page.msg configure -text $msg
	$pages raise cinst

	set res [wait_next]
	catch {destroy $::BTNS.unst}
	return $res
    }

    return 1
}

# ----------------------------------------------

proc browse_dir {e} {
    set dir [tk_chooseDirectory]
    if {[string length $dir]} {
	$e delete 0 end
	$e insert end $dir
    }
}

proc install_ok {dir} {
    $::NEXT configure -state [expr {($dir == "")?"disabled":"normal"}]
    return 1
}

proc get_installdir {pages} {
    set pname query
    set page [$pages getframe $pname]
    if {![winfo exists $page]} {
	set page [$pages add $pname]

	# Bugzilla 19731 ... Depending on whether the installing user
	# has admin privileges are not he is either notified that a
	# personal installation is performed, or given the choice
	# between common and personal installations. Default is a
	# personal installation.

	if {[string equal "windows" $::tcl_platform(platform)]} {
	    set ::INSTALL_MODE user
	    set ::INSTALL_PATHEXT 1
	    set ::INSTALL_REG_TCL 1
	    set ::INSTALL_REG_TBC 1

	    label $page.msg -anchor nw -justify left -width 70 \
		-text "Please specify installation directory and mode."

	    TitleFrame::use
	    TitleFrame $page.imode -text "Installation mode"
	    set area [$page.imode getframe]

	    if {[string equal "Windows 95" $::tcl_platform(os)]} {
		set ::INSTALL_MODE admin
	    }

	    radiobutton $area.personal -anchor w -variable ::INSTALL_MODE \
		-value user  -text "Install for current user only"
	    radiobutton $area.common   -anchor w -variable ::INSTALL_MODE \
		-value admin -text \
		"Install for all users (requires Administrative privileges)"

	    if {[string equal "Windows 95" $::tcl_platform(os)]} {
		$area.personal configure -state disabled
	    }

	    TitleFrame $page.rmode -text "Registry Settings"
	    set rarea [$page.rmode getframe]

	    checkbutton $rarea.pext -anchor nw -variable ::INSTALL_PATHEXT \
		-text "Add '.tcl' to your executable path extensions (PATHEXT)"
	    checkbutton $rarea.rtbc -anchor nw -variable ::INSTALL_REG_TBC \
		-text "Associate '.tbc' extension to ActiveTcl\
		\n('.tcl' is automatically associated)" \
		-justify left

	    grid $area.personal -sticky new -padx 4
	    grid $area.common   -sticky new -padx 4

	    grid columnconfigure $area 0 -weight 1

	    grid $rarea.pext -sticky new -padx 4
	    grid $rarea.rtbc -sticky new -padx 4

	    grid columnconfigure $rarea 0 -weight 1

	    grid $page.msg   -sticky new -padx 4 -pady 4
	    grid $page.imode -sticky new -padx 4 -pady 4
	    grid $page.rmode -sticky new -padx 4 -pady 4
	} else {
	    label $page.msg -anchor nw -justify left -width 70 \
		    -text "Please specify the installation directory."
	    grid $page.msg -sticky new -padx 4 -pady 4
	}

	label $page.errmsg -anchor nw -justify left -fg red
	frame $page.dir
	entry  $page.ent -width 40 -validate key -vcmd { install_ok %P }
	button $page.browse -image [Bitmap::get open] \
		-command [list browse_dir $page.ent]

	grid $page.errmsg -sticky new -padx 8
	grid $page.dir -sticky news -padx 4 -pady 2

	grid $page.ent $page.browse -in $page.dir -sticky news
	grid columnconfigure $page.dir 0 -weight 1

	set expandRow [expr {[lindex [grid size $page] 1] - 2}]
	grid rowconfigure    $page $expandRow -weight 1
	grid columnconfigure $page 0    -weight 1

	bind $page.ent <Key-Return> { next }
    }
    $pages raise $pname
    focus $page.ent

    $page.ent delete 0 end
    $page.ent insert end $::INSTALL_DIR
    after idle [list $page.ent validate]

    if {[string length $::ERRMSG]} {
	$page.errmsg configure -text $::ERRMSG
    }

    # -2 means skip over check_previous_install when going back
    set res [wait_next -2]
    set ::INSTALL_DIR [$page.ent get]

    set ::DEMO_DIR    [default_demodir $::INSTALL_DIR]
    set ::RUNTIME_DIR $::INSTALL_DIR
    if {$res < 0} { return $res }

    ## Here is the place where the entered directory is verified.

    if {[string equal $::AT(MODE) lite]} {
	foreach {::INSTALL_DIR ::ERRMSG} [check_installdir_lite $::INSTALL_DIR] {break}
	if {[string length $::ERRMSG]} {
	    # Something wrong with dir, do this again
	    return 0
	} else {
	    # Skip the overinstall check and demo dir
	    set ::ERRMSG ""
	    return 3
	}
    } else {
	foreach {::INSTALL_DIR ::ERRMSG} [check_installdir $::INSTALL_DIR] {break}
	if {[string length $::ERRMSG]} {
	    # Something wrong with dir, do this again
	    return 0
	} elseif {[string length $::AT(InstVersion)]} {
	    # That we are here means that overinstallation was/is allowed.
	    # Moved to next step (overinstall check).
	    set ::ERRMSG ""
	    return 1
	} else {
	    # Skip the overinstall check
	    set ::ERRMSG ""
	    return 2
	}
    }
}

# ----------------------------------------------

proc overinstall {pages} {
    set page [$pages getframe overinstall]
    if {![winfo exists $page]} {
	set page [$pages add overinstall]
	label $page.msg -anchor nw -justify left -width 70 \
		-text [overinstall_warning]
	grid $page.msg -sticky new -padx 8 -pady 4
	grid rowconfigure $page 0 -weight 1
	grid columnconfig $page 0 -weight 1
    }
    $pages raise overinstall

    return [wait_next]
}

# ----------------------------------------------

proc get_demodir {pages} {
    set pname demos
    set page [$pages getframe $pname]
    if {![winfo exists $page]} {
	set page [$pages add $pname]
	label $page.msg -anchor nw -justify left -width 70 \
		-text "Please specify the demos directory."
	label $page.errmsg -anchor nw -justify left -fg red

	grid $page.msg    -sticky new -padx 4 -pady 4
	grid $page.errmsg -sticky new -padx 8

	frame $page.dir
	entry  $page.ent -width 40 -validate key -vcmd { install_ok %P }
	button $page.browse -image [Bitmap::get open] \
		-command [list browse_dir $page.ent]

	grid $page.dir -sticky news -padx 4 -pady 2

	grid $page.ent $page.browse -in $page.dir -sticky news
	grid columnconfigure $page.dir 0 -weight 1

	grid rowconfigure $page 0 -weight 1
	grid columnconfig $page 0 -weight 1

	bind $page.ent <Key-Return> { next }
    }
    $pages raise $pname
    focus $page.ent

    $page.ent delete 0 end
    $page.ent insert end $::DEMO_DIR
    after idle [list $page.ent validate]

    if {[string length $::ERRMSG]} {
	$page.errmsg configure -text $::ERRMSG
    }

    # -2 means skip over overinstall warning when going back
    set res [wait_next -2]
    set ::DEMO_DIR [$page.ent get]
    if {$res < 0} { return $res }

    foreach {::DEMO_DIR ::ERRMSG} [check_demodir $::DEMO_DIR] {break}
    if {[string length $::ERRMSG]} {
	# Something wrong with dir, do this again
	return 0
    } else {
	return 1
    }
}

# ----------------------------------------------

proc get_runtimedir {pages} {
    set pname runtime
    set page [$pages getframe $pname]
    if {![winfo exists $page]} {
	set page [$pages add $pname]
	label $page.msg -anchor nw -justify left -width 70 \
		-text "Please specify the runtime installation directory.\n
	This is the directory the applications will see as their
	installation directory when searching for packages and
	libraries, instead of the directory the files were copied
	to. In most circumstances this is the same as the
	installation directory chosen before."

	label $page.errmsg -anchor nw -justify left -fg red
	grid $page.msg -columnspan 2 -sticky new -padx 4 -pady 4
	grid $page.errmsg -columnspan 2 -sticky new -padx 8

	entry  $page.ent -width 40 -validate key -vcmd { install_ok %P }
	button $page.browse -image [Bitmap::get open] \
		-command [list browse_dir $page.ent]
	grid $page.ent $page.browse -sticky news

	grid rowconfigure $page 0 -weight 1
	grid columnconfig $page 0 -weight 1

	bind $page.ent <Key-Return> { next }
    }
    $pages raise $pname
    focus $page.ent

    $page.ent delete 0 end
    $page.ent insert end $::RUNTIME_DIR
    after idle [list $page.ent validate]

    if {[string length $::ERRMSG]} {
	$page.errmsg configure -text $::ERRMSG
    }

    set res [wait_next]
    set ::RUNTIME_DIR [$page.ent get]
    if {$res < 0} { return $res }

    foreach {::RUNTIME_DIR ::ERRMSG} [check_runtimedir $::RUNTIME_DIR] {break}
    if {[string length $::ERRMSG]} {
	# Something wrong with dir, do this again
	return 0
    } else {
	return 1
    }
}

# ----------------------------------------------

array set ::BROWSELABEL {
    netscape  Netscape
    mozilla   Mozilla
    iexplorer {Internet Explorer}
}

proc plugin_browse {area bcode} {
    global  BROWSEDIR BROWSELABEL
    upvar 0 BROWSEDIR($bcode) plugdir

    set initialdir {}
    if {![string equal $plugdir "<< Not found >>"]} {
	set initialdir $plugdir
    }
    set newdir [tk_chooseDirectory \
	    -initialdir $initialdir \
	    -title "Choose plugin directory for $::BROWSELABEL($bcode)" \
	    ]
    if {$newdir != {}} {
	$area.$bcode configure -state normal
	set plugdir $newdir

	# Bugzilla 23375.
	if {![file writable $plugdir]} {
	    $area.$bcode configure -state disabled
	    $area.c_$bcode configure \
		    -text "$::BROWSELABEL($bcode)\n\
		    No permissions to write into the chosen directory"
	} else {
	    $area.c_$bcode configure -text $::BROWSELABEL($bcode)
	}
    }
    # Bugzilla 23133.
    # Ignore empty return value => Cancel
    
    return
}


proc plugin_setup {pages} {
    global tw HAVE_TCLAPP

    # Skip over plugin for distributions without it.
    if {!$HAVE_TCLAPP} {return 1}

    set pname plugin
    set page [$pages getframe $pname]
    set firsttime 0
    if {![winfo exists $page]} {
	set firsttime 1
	set page [$pages add $pname]

	TitleFrame::use
	TitleFrame $page.brw -text "Install the tcl plugin for ..."
	set area [$page.brw getframe]

	if {[string equal "windows" $::tcl_platform(platform)]} {
	    set browsers {mozilla iexplorer}
	} else {
	    # Future: Opera, ...
	    set browsers {netscape mozilla}
	}
	set row 0
	foreach bcode $browsers {
	    set ::BROWSE($bcode)    0
	    set ::BROWSEDIR($bcode) [set plugdir [get_plugin_dir $bcode]]

	    checkbutton $area.$bcode -anchor nw -variable ::BROWSE($bcode) \
		    -text {} -justify left
	    label  $area.c_$bcode -anchor w -justify left -text $::BROWSELABEL($bcode)
	    label  $area.l_$bcode -anchor w -textvariable ::BROWSEDIR($bcode)
	    button $area.b_$bcode -anchor w -text ... -command [list plugin_browse $area $bcode]

	    grid $area.$bcode   -sticky w  -padx 4 -row $row -column 0
	    grid $area.c_$bcode -sticky ew -padx 4 -row $row -column 1
	    incr row
	    grid $area.l_$bcode -sticky ew -padx 4 -row $row -column 1
	    grid $area.b_$bcode -sticky ew -padx 4 -row $row -column 2

	    if {![file exists $plugdir] || ![file isdirectory $plugdir]} {
		$area.$bcode configure -state disabled
		set ::BROWSEDIR($bcode) "<< Not found >>"
	    } elseif {![file writable $plugdir]} {
		# Bugzilla 23375
		$area.$bcode configure -state disabled
		$area.c_$bcode configure \
			-text "$::BROWSELABEL($bcode)\n\
			No permissions to write into the chosen directory"
	    }

	    grid rowconfigure $area $row -weight 1
	    incr row
	}

	set ::BROWSE_PHC  0
	set ::BROWSE_MIME 0
	if {[string equal "windows" $::tcl_platform(platform)]} {
	    checkbutton $area.regphc -anchor w -variable ::BROWSE_PHC \
		    -justify left \
		    -text "Register the ActiveX Plugin Host Control\n\
		    (requires Administrative privileges)"
	    checkbutton $area.regmime -anchor w -variable ::BROWSE_MIME \
		    -justify left \
		    -text "Register tcl plugin for MIME-type application/x-tcl\n\
		    (requires Administrative privileges)"

	    grid $area.regphc  -sticky nw -padx 4 -columnspan 3
	    grid $area.regmime -sticky nw -padx 4 -columnspan 3
	}

	if {[string equal "Windows 95" $::tcl_platform(os)]} {
	    # Windows 95/98/ME needs path added to AUTOEXEC.BAT

	    set bindir [file nativename  $::INSTALL_DIR]\\bin

	    message $area.notice \
		    -justify left -width 8c \
		    -text "NOTE: If you wish to use the plugin,\
		    you must add \"$bindir\" to the PATH environment\
		    variable in C:\\AUTOEXEC.BAT (takes effect upon restart)."

	    grid $area.notice -sticky new -padx 4 -pady 4 -columnspan 2
	}

	grid columnconfigure $area 0    -weight 0
	grid columnconfigure $area 1    -weight 1
	grid columnconfigure $area 2    -weight 0

	grid $page.brw -sticky new -padx 4 -pady 4

	grid rowconfigure    $page 0 -weight 1
	grid columnconfigure $page 0 -weight 1
    }
    $pages raise $pname

    set res [wait_next]
    if {$res < 0} {return -2}
    return $res
}

# ----------------------------------------------

proc install_ready {pages} {
    global tw
    set pname ready
    set page [$pages getframe $pname]
    set firsttime 0
    if {![winfo exists $page]} {
	set firsttime 1
	set page [$pages add $pname]
	grid [ScrolledWindow $page.s -auto both] -sticky news -padx 4 -pady 4
	# make this word wrap to avoid ScrolledWindow infinite loop
	# scrollbar bug
	set tw [text $page.s.t -width 20 -height 8 -wrap word \
		    -bg [$page cget -bg] -relief flat -bd 0]
	$page.s setwidget $tw

	grid columnconfigure $page 0 -weight 1
	grid rowconfigure $page 0 -weight 1

	$tw tag configure error   -background #CC4444
	$tw tag configure warning -background yellow

	if {$::tcl_platform(platform) == "windows"} {
	    $tw tag configure hype \
		-background #edeadb -borderwidth 2 -relief sunken
	} else {
	    $tw tag configure hype \
		-background white   -borderwidth 2 -relief sunken
	}
	$tw tag configure url      -background lightblue -relief flat
	$tw tag configure heading  -font {helvetica 12 bold}
	$tw tag configure emphasis -font {helvetica  8 bold}

	# Accept focus even when disabled
	bind $tw <1>		{ focus %W }
	bind $tw <Key-Return>	{ next }
    }

    $tw configure -state normal

    $tw delete 1.0 end
    $tw insert 1.0 "Press 'Next' to begin installation\n" "" \
	    "     Installation Directory:\t$::INSTALL_DIR\n"

    if {[string equal $::AT(MODE) lite]} {
	set ::DEMO_DIR {}
    } else {
	$tw insert end    "     Demos Directory:\t$::DEMO_DIR\n"
    }
    if {![string equal $::tcl_platform(platform) windows]} {
	if {[string equal $::INSTALL_DIR $::RUNTIME_DIR]} {
	    $tw insert end    "     Runtime Directory:\tSee Installation Directory\n"
	} else {
	    $tw insert end    "     Runtime Directory:\t$::RUNTIME_DIR\n"
	}
    }
    $tw insert end "\n"

    $tw configure -state disabled

    after idle license_ok
    $pages raise $pname
    set ::LOGWIN $page.s.t

    set res [wait_next]
    if {$res < 0} {
	# The exact target depends on the current combination of
	# lite/platform: No lite => Standard behaviour

	if {![string equal $::AT(MODE) lite]} {
	    return -3 ; # skip state 7, get_runtimedir
	    #return $res ; # We are state 9
	}
	if {[string equal "windows" $::tcl_platform(platform)]} {
	    return -6 ; # We are state 9, target is 3 (lookfor_previous)
	} else {
	    return -5 ; # Target state is 4 (get_installdir)
	}
    }

    # At this point, there is no going back
    grid remove $::BACK $::NEXT
    bind . <Key-Return> { cancel }

    # Install all the files
    do_install_modules $::SCRIPT_DIR $::INSTALL_DIR $::DEMO_DIR
    # Patch files or add registry stuff
    do_finish $::SCRIPT_DIR $::INSTALL_DIR $::RUNTIME_DIR

    hype_message
    log "\n[parting_message]"

    # This only allows exit
    wait_next 0 0 "Finish"
}

# ----------------------------------------------
# LOGGING ROUTINE
# ----------------------------------------------

proc log {msg {typelist ok}} {
    if {[string length $msg]} {
	$::LOGWIN configure -state normal
	$::LOGWIN insert end "$msg\n" $typelist
	$::LOGWIN see end
	$::LOGWIN configure -state disabled
	update
    }
}

proc log* {msg {typelist ok}} {
    if {[string length $msg]} {
	$::LOGWIN configure -state normal
	$::LOGWIN insert end "$msg" $typelist
	$::LOGWIN configure -state disabled
	update
    }
}

proc log_debug {msg} {
    ## No output of debugging stuff.
    ## log $msg hype
}


# ----------------------------------------------
# WAIT ROUTINES
# ----------------------------------------------

proc next {} { $::NEXT invoke }
proc cancel {} { exit 0 }

proc wait_next {{back -1} {next 1} {cancel "Cancel"}} {
    if {$back} { grid $::BACK } else { grid remove $::BACK }
    if {$next} { grid $::NEXT } else { grid remove $::NEXT }
    $::BACK configure -state normal -command [list set ::WAIT $back]
    $::NEXT configure -state normal -command [list set ::WAIT $next]
    $::CANCEL configure -text $cancel -state normal -command cancel

    vwait ::WAIT
    return $::WAIT
}

# ----------------------------------------------
# SPECIAL UNINSTALLER FOR 8.3.3.2
# ----------------------------------------------

proc uninstall-8.3.3.2 {dir} {
    # This version came without an INSTALL.LOG
    # Just be a little brutal in getting rid of it
    foreach file [list \
	    $dir/bin/itcl32.dll \
	    $dir/bin/itk32.dll \
	    $dir/bin/tcl83.dll \
	    $dir/bin/tclpip83.dll \
	    $dir/bin/tclsh83.exe \
	    $dir/bin/tclx83.dll \
	    $dir/bin/tk83.dll \
	    $dir/bin/tkcon.tcl \
	    $dir/bin/tkx83.dll \
	    $dir/bin/wish83.exe \
	    $dir/doc/ActiveTclHelp.chm \
	    $dir/include \
	    $dir/lib/bwidget1.3.0 \
	    $dir/lib/dde1.1 \
	    $dir/lib/itcl3.2 \
	    $dir/lib/itk3.2 \
	    $dir/lib/iwidgets \
	    $dir/lib/iwidgets3.0.2 \
	    $dir/lib/reg1.0 \
	    $dir/lib/tcl8.3 \
	    $dir/lib/tcllib1.0 \
	    $dir/lib/tclX8.3 \
	    $dir/lib/tk8.3 \
	    $dir/lib/Tktable2.7 \
	    $dir/lib/tkX8.3 \
	    $dir/license.terms \
	    $dir/README.txt \
	    ] {
	file delete -force $file
    }
    catch {eval file delete -force [glob -nocomplain $dir/lib/*.{sh,lib}]}
    foreach subdir {bin doc include lib} {
	if {[llength [glob -nocomplain $dir/$subdir/*]] == 0} {
	    file delete -force $dir/$subdir
	}
    }
    if {[llength [glob -nocomplain $dir/*]] == 0} {
	file delete -force $dir
    }
    package require registry
    catch {
	registry delete \
		{HKEY_LOCAL_MACHINE\SOFTWARE\ActiveState\ActiveTcl} \
		"CurrentVersion"
    }
    catch {
	registry delete \
		{HKEY_LOCAL_MACHINE\SOFTWARE\ActiveState\ActiveTcl\8.3.3.2}
    }
    catch {
	package require dde
	dde execute progman progman {[DeleteGroup(ActiveState ActiveTcl)]}
    }
}

# ----------------------------------------------
# GO TO IT
# ----------------------------------------------

set ::SCRIPT_DIR [file dirname [info script]]
set here [pwd] ; cd $::SCRIPT_DIR ; set ::SCRIPT_DIR [pwd] ; cd $here

if {[catch {
    source [file join $SCRIPT_DIR install_lib.tcl]
    main
} err]} {
puts $err
    catch {bgerror $err}
}
#puts Exiting
exit
