# $Revision$ on $Date$
# The above revision line needs to be the first line for all techtk files
# Copyright (c) 2006 Ansys Inc

#----------------------------------------------------------------------------
#
# PADT---------------------------------------------------- Phoenix Analysis &
#                                                         Design Technologies
#
#----------------------------------------------------------------------------
#
#       Package: AI-Environment GUI Management
#
#
#          File: parser.tcl
#
#
#     Developer: Matt Sutton
#
#
#   Description: This file contains the implementation of the multiSelect widget
#   
#
#      09/01/02: Demo release 1. Limited/partial widget support. 
#                Limited error checking.
#
#           
#
#-----------------------------------------------------------------------------
# For support: 1-480-813-4884 ext. 125 -or- matt.sutton@padtinc.com
#-----------------------------------------------------------------------------

namespace eval ::AIEnv::GUIManagement {}

namespace eval ::AIEnv::GUIManagement::MultiSelect {
	variable Commands
	variable Options
	variable MultiSelectData
	variable UnderlineFont
	variable NormalFont
	
	set Commands {
		set
		get
		build
		clear
		query
		grey
		ungrey
		select
		unselect
		widgetgrey
		widgetungrey
	}
	
	set Options {
		title
		rowLabel
		columnLabel
		rowExclusive
		parent
		nodeID
		dirtyFlag
	}
}

proc ::AIEnv::GUIManagement::MultiSelect::RouterProc {Name Cmd args} {

	if {[catch {eval [list RouterProcImpl $Name $Cmd] $args} result] != 0} {
		::AIEnv::GUIManagement::RuntimeError $result
	} else {
		return $result
	}
}

proc ::AIEnv::GUIManagement::MultiSelect::RouterProcImpl {Name Cmd args} {
	# Check the command to see if it is valid
	variable Commands
	if { [lsearch $Commands $Cmd] != -1 } {
		return [eval [list ::AIEnv::GUIManagement::MultiSelect::_$Cmd $Name] $args]
	} else {
		set Optlist [join $Commands ", "]
		set Optlist [linsert $Optlist "end-1" "or"]
		error "Unknown command: \"Cmd\" given to multi-selector named: \"$Name\".  Valid commands are: \"$Optlist\"."
	}	
}

proc ::AIEnv::GUIManagement::MultiSelect::_set {Name args} {
	if {[catch {eval [list SetImpl $Name] $args} result] != 0} {
		::AIEnv::GUIManagement::RuntimeError $result		
	} else {
		return $result
	}
}

proc ::AIEnv::GUIManagement::MultiSelect::SetImpl {Name args} {
	variable Options
	variable MultiSelectData
	variable SelectionTypes
	if { [llength $args] == 3 } {
		set Flag [lindex $args 0]
		set Key [lindex $args 1]
		set Value [lindex $args 2]
		if { $Flag == "-key" } {
			if { [lsearch $Options $Key] != -1 } {
				if { $Key == "type" } {
					set Value [string tolower $Value]
					if { [lsearch $SelectionTypes $Value] == -1 } {
						set Optlist [join $SelectionTypes ", "]
						set Optlist [linsert $Optlist "end-1" "or"]
						error "Invalid selection type: \"$Value\" given for multi-selector: \"$Name\"\n. Valid selection types are: $Optlist."
					}
				}
                if { $Key == "title" } {
                    if {[array names MultiSelectData "$Name,MainFrame"] != ""} {
		                $MultiSelectData($Name,MainFrame) configure -text $Value
		            }
	            }

				set MultiSelectData($Name,$Key) $Value
			} else {
				set Optlist [join $Options ", "]
				set Optlist [linsert $Optlist "end-1" "or"]
				error "Invalid option: \"$Key\" for multi-selector: \"$Name\". Valid options are $Optlist."
			}
		} else {
			error "Invalid flag: \"$Flag\" for multi-selector: \"$Name\". Must be -key"
		}
	} else {
		error "Wrong number of arguments: Should be \"$Name set -key key value\""
	}
}


proc ::AIEnv::GUIManagement::MultiSelect::_get {Name args} {
	if {[catch {eval [list GetImpl $Name] $args} result] != 0} {
		::AIEnv::GUIManagement::RuntimeError $result
	} else {
		return $result
	}
}

proc ::AIEnv::GUIManagement::MultiSelect::GetImpl {Name args} {
	variable Options
	variable MultiSelectData
	if { [llength $args] == 2 } {
		set Flag [lindex $args 0]
		set Key [lindex $args 1]
		if { $Flag == "-key" } {
			if { [lsearch $Options $Key] != -1 } {
				return $MultiSelectData($Name,$Key)
			} else {
				set Optlist [join $Options ", "]
				set Optlist [linsert $Optlist "end-1" "or"]
				error "Invalid option: \"$Key\" for multi-selector: \"$Name\". Valid options are $Optlist."
			}
		} else {
			error "Invalid flag: \"$Flag\" for multi-selector: \"$Name\". Must be -key"
		}
	} else {
		error "Wrong number of arguments: Should be \"$Name get -key key\""
	}
}

proc ::AIEnv::GUIManagement::MultiSelect::_clear {Name args} {
	if {[catch {eval [list ClearImpl $Name] $args} result] != 0} {
		::AIEnv::GUIManagement::RuntimeError $result
	} else {
		return $result
	}
}

proc ::AIEnv::GUIManagement::MultiSelect::ClearImpl {Name args} {
	variable MultiSelectData
	
	# Destroy the old frame
	if {[info exists MultiSelectData($Name,MainFrame)]} {
		if {[winfo exists $MultiSelectData($Name,MainFrame)]} {
			destroy $MultiSelectData($Name,MainFrame)
			unset MultiSelectData($Name,MainFrame)
		}
	}
	
	set Indices [array names MultiSelectData $Name,Path,*]
	foreach i $Indices {
		if { [info exists MultiSelectData($i)] } {
			unset MultiSelectData($i)
		}
	}
	
	set Indices [array names MultiSelectData $Name,State,*]
	foreach i $Indices {
		if { [info exists MultiSelectData($i)] } {
			unset MultiSelectData($i)
		}
	}
	
	set Indices [array names MultiSelectData $Name,SelectData,*]
	foreach i $Indices {
		trace vdelete ::AIEnv::GUIManagement::MultiSelect::($i) "w" \
		::AIEnv::GUIManagement::MultiSelect::SetParentDirty
		if { [info exists MultiSelectData($i)] } {
			unset MultiSelectData($i)
		}
	}
	
	set Indices [array names MultiSelectData $Name,rowLabel,*]
	lappend Indices [array names MultiSelectData $Name,columnLabel]
	lappend Indices [array names MultiSelectData $Name,title]
	lappend Indices [array names MultiSelectData $Name,rowExclusive]
	
	foreach i $Indices {
		if { [info exists MultiSelectData($i)] } {
			unset MultiSelectData($i)
		}
	}
}

proc ::AIEnv::GUIManagement::MultiSelect::_build {Name args} {
	if {[catch {eval [list BuildImpl $Name] $args} result] != 0} {
		::AIEnv::GUIManagement::RuntimeError $result
	} else {
		return $result
	}
}



proc ::AIEnv::GUIManagement::MultiSelect::BuildImpl {Name args} {
	variable MultiSelectData
	variable UnderlineFont
	variable NormalFont
    variable ::AIEnv::GUIManagement::GUIDisplayData

	set RowCount 1
	set ColSpan 3

	if { [GetParentType $Name] == "DEZ" || [GetParentType $Name] == "output"} {
		if { [info exists MultiSelectData($Name,BuiltOnce)] } {
			if { $MultiSelectData($Name,BuiltOnce) == 0 } {
				set RowParent [::AIEnv::GUIManagement::DEZInsert $RowCount 1.1]
				set TopRow [lindex $RowParent 0]
				set ParentPath [lindex $RowParent 1]
				set MultiSelectData($Name,TopRow) $TopRow
				set MultiSelectData($Name,ParentPath) $ParentPath
				set MultiSelectData($Name,BuiltOnce) 1
			} else {
				set TopRow $MultiSelectData($Name,TopRow)
				set ParentPath $MultiSelectData($Name,ParentPath)
			}
		} else {
			set RowParent [::AIEnv::GUIManagement::DEZInsert $RowCount 1.1]
			set TopRow [lindex $RowParent 0]
			set ParentPath [lindex $RowParent 1]
			set MultiSelectData($Name,TopRow) $TopRow
			set MultiSelectData($Name,ParentPath) $ParentPath
			set MultiSelectData($Name,BuiltOnce) 1
		}
	} else {
		# Somehow RowParent must be set up...
		error "Currently this widget doesn't support placement in any location other than a DEZ."
	}
	
	set Title [GetTitle $Name]
	set NodeID [GetNodeID $Name]
	set ExclusiveSelector [GetExclusivity $Name]
	set ColumnLabels [GetColumnLabels $Name]
	set RowLabels [GetRowLabels $Name]
	
	
	set OuterFrame [TitleFrame $ParentPath.$NodeID-tf -text $Title -side left \
			-font $::AIEnv::GUIManagement::GUIDisplayData("DEZTitleFont")]
	set InnerFrame [$OuterFrame getframe]
	
	set MultiSelectData($Name,MainFrame) $OuterFrame
	
	set Row 0
	set Col 1
	set i 0
	grid columnconfigure $InnerFrame 0 -weight 1
	# Create the font used for the underlining process
	set NormalFont $::AIEnv::GUIManagement::GUIDisplayData("MultiSelectFont")
	set UnderlineFont [CreateUnderlineFont $NormalFont]

	# Add the column labels
	foreach ColLabel $ColumnLabels {
		set lab [label $InnerFrame.lc${Col} -text $ColLabel -wraplength 100 -width 14 -font $NormalFont]
		grid $lab -row $Row -column $Col -sticky e
		
		set MultiSelectData($Name,Path,Col${i}) $lab
		set MultiSelectData($Name,State,Col${i}) normal

		# Set up the bindings for selecting a column
		bind $lab <Enter> {
			::AIEnv::GUIManagement::MultiSelect::HighlightLabel %W 1
		}
		bind $lab <Leave> {
			::AIEnv::GUIManagement::MultiSelect::HighlightLabel %W 0
		}
		bind $lab <ButtonPress-1> "::AIEnv::GUIManagement::MultiSelect::SelectColumn $lab $Name $i"
		
		# Configure the innerframes griding
		grid columnconfigure $InnerFrame $Col -weight 1
		incr i
		incr Col
	}
	
	set NumCols [llength $ColumnLabels]
	incr NumCols
		
	set Row 1
	set Col 0
	set i 0
	
	# Add the row labels and the separators
	foreach RowLabel $RowLabels {
		set sep [Separator $InnerFrame.sep${Row} -orient horizontal]
		grid $sep -row $Row -column 0 -columnspan $NumCols -sticky ew
		incr Row
		set lab [label $InnerFrame.lr${Row} -text $RowLabel -wraplength 75 -width 13 -font $NormalFont]
		grid $lab -row $Row -column $Col -sticky e
		incr Row
		set MultiSelectData($Name,Path,Row${i}) $lab
		set MultiSelectData($Name,State,Row${i}) normal
		if { $ExclusiveSelector == 0 } {
			# Set up the bindings for selecting a row
			bind $lab <Enter> {
				::AIEnv::GUIManagement::MultiSelect::HighlightLabel %W 1
			}
			bind $lab <Leave> {
				::AIEnv::GUIManagement::MultiSelect::HighlightLabel %W 0
			}
			bind $lab <ButtonPress-1> "::AIEnv::GUIManagement::MultiSelect::SelectRow $lab $Name $i"
			
		}
		incr i
	}
	
	# Add the actual checkboxes/radiobuttons
	set Row 2
	set Col 1
	
	set i 0
	set j 0
	
	if { $ExclusiveSelector == 1 } {
		# We need to use radio buttons for this case
		foreach R1 $RowLabels {
			foreach C1 $ColumnLabels {
				set rbn [radiobutton $InnerFrame.sel-${i}-${j} \
				         -variable ::AIEnv::GUIManagement::MultiSelect::MultiSelectData($Name,SelectData,Row$i) \
				         -value $j]
				grid $rbn -row $Row -column $Col -sticky n
				set MultiSelectData($Name,Path,$i,$j) $rbn
				set MultiSelectData($Name,State,$i,$j) normal
				incr Col 1
				incr j
				trace variable ::AIEnv::GUIManagement::MultiSelect::MultiSelectData($Name,SelectData,Row$i) \
				"w" "::AIEnv::GUIManagement::MultiSelect::SetParentDirty $Name"
			}
			set Col 1
			set j 0
			incr Row 2
			incr i
		}
	} else {
		# We need to use check buttons for this case
		foreach R1 $RowLabels {
			foreach C1 $ColumnLabels {
				set chk [checkbutton $InnerFrame.sel-${i}-${j} \
				         -variable ::AIEnv::GUIManagement::MultiSelect::MultiSelectData($Name,SelectData,$i,$j) \
					 -font $GUIDisplayData("CheckButtonFont") \
				         -onvalue 1 -offvalue 0]
				grid $chk -row $Row -column $Col -sticky n
				set MultiSelectData($Name,Path,$i,$j) $chk
				set MultiSelectData($Name,State,$i,$j) normal
				incr Col 1
				incr j
				trace variable ::AIEnv::GUIManagement::MultiSelect::MultiSelectData($Name,SelectData,$i,$j) \
				"w" "::AIEnv::GUIManagement::MultiSelect::SetParentDirty &Name"
			}
			set Col 1
			set j 0
			incr Row 2
			incr i
		}
	}
	
	set RowSpan $RowCount
	grid $OuterFrame -row $TopRow -column 0 -columnspan $ColSpan -rowspan $RowSpan -sticky nsew
	
}

proc ::AIEnv::GUIManagement::MultiSelect::SetParentDirty {Name n1 n2 op} {
	set Parent [GetParent $Name]
	$Parent setdirty
}

proc ::AIEnv::GUIManagement::MultiSelect::CreateUnderlineFont {f} {
	set fam [font actual $f -family]
	set size [font actual $f -size]
	set weight [font actual $f -weight]
	
	set fnew [font create -family $fam -weight $weight -size $size -underline true]
	return $fnew
}

proc ::AIEnv::GUIManagement::MultiSelect::HighlightLabel {w Highlight} {
	variable UnderlineFont
	variable NormalFont
	set status [$w cget -state]
	if { $status == "disabled" } {
		return
	}
	if { $Highlight } {
		$w configure -font $UnderlineFont -foreground blue
	} else {
		$w configure -font $NormalFont -foreground black
	}
}

proc ::AIEnv::GUIManagement::MultiSelect::SelectRow {w Name RowNumber} {
	
	set status [$w cget -state]
	if { $status == "disabled" } {
		return
	}
	
	variable MultiSelectData
	# Look to see if all of the current row is selected.
	# If so, then unselect that row, else select all
	
	set AllSelected 1
	set NumCols [llength [GetColumnLabels $Name]]
	set RowLabel [lindex [GetRowLabels $Name] $RowNumber]
	for {set i 0} {$i < $NumCols} {incr i} {
		if { $MultiSelectData($Name,SelectData,$RowNumber,$i) == 0 } {
			if { [$MultiSelectData($Name,Path,$RowNumber,$i) cget -state] == "normal" } {
				set AllSelected 0
				break
			}
		}
	}
	
	if { $AllSelected == 1 } {
		UnSelectImpl $Name $RowLabel
	} else {
		SelectImpl $Name $RowLabel
	}
}

proc ::AIEnv::GUIManagement::MultiSelect::SelectColumn {w Name ColNumber} {

	set status [$w cget -state]
	if { $status == "disabled" } {
		return
	}
	variable MultiSelectData
	# Look to see if all of the current column is selected.
	# If so, then unselect that column, else select all
	
	set Exclusive [GetExclusivity $Name]
	set NumRows [llength [GetRowLabels $Name]]
	set ColLabel [lindex [GetColumnLabels $Name] $ColNumber]
	
	set AllSelected 1
	
	if { $Exclusive == 1 } {
		for {set i 0} {$i < $NumRows} {incr i} {
			if { $MultiSelectData($Name,SelectData,Row$i) != $ColNumber } {
				if { [$MultiSelectData($Name,Path,$i,$ColNumber) cget -state] == "normal" } {
					set AllSelected 0
					break
				}
			}
		}
	} else {
		for {set i 0} {$i < $NumRows} {incr i} {
			if { $MultiSelectData($Name,SelectData,$i,$ColNumber) == 0 } {
				if { [$MultiSelectData($Name,Path,$i,$ColNumber) cget -state] == "normal" } {
					set AllSelected 0
					break
				}
			}
		}
	}
	
	if { $AllSelected == 1 } {
		UnSelectImpl $Name $ColLabel
	} else {
		SelectImpl $Name $ColLabel
	}
}


proc ::AIEnv::GUIManagement::MultiSelect::_query {Name args} {
	if {[catch {eval [list QueryImpl $Name] $args} result] != 0} {
		::AIEnv::GUIManagement::RuntimeError $result
	} else {
		return $result
	}
}

proc ::AIEnv::GUIManagement::MultiSelect::QueryImpl {Name args} {
	# Return 0 if the requested item is not selected, or 1 if it is
	# selected
	variable MultiSelectData
	if { [llength $args] != 2 } {
		error "Wrong number of arguments passed to \"$Name query\""
	}
	
	set RowLabels [GetRowLabels $Name]
	set ColLabels [GetColumnLabels $Name]
	set Exclusive [GetExclusivity $Name]
	
	set RowLabel [lindex $args 0]
	set ColLabel [lindex $args 1]
	
	set RowIndex [lsearch $RowLabels $RowLabel]
	set ColIndex [lsearch $ColLabels $ColLabel]
	
	if { $RowIndex != -1 } {
		if { $ColIndex != -1 } {
			if { $Exclusive == 1 } {
				set val $MultiSelectData($Name,SelectData,Row${RowIndex})
				if { $val == $ColIndex } {
					return 1
				} else {
					return 0
				}
			} else {
				return $MultiSelectData($Name,SelectData,$RowIndex,$ColIndex)
			}
		} else {
			set OptList [join $ColLabels ", "]
			set OptList [linsert $OptList "end-1" "or"]
			error "The column label \"$ColLabel\" was not found in the multiSelect widget named $Name.\nMust be $OptList."
		}
	} else {
		set OptList [join $RowLabels ", "]
		set OptList [linsert $OptList "end-1" "or"]
		error "The row label \"$RowLabel\" was not found in the multiSelect widget named $Name.\nMust be $OptList."		
	}
}

proc ::AIEnv::GUIManagement::MultiSelect::_grey {Name args} {
	if {[catch {eval [list GreyImpl $Name] $args} result] != 0} {
		::AIEnv::GUIManagement::RuntimeError $result
	} else {
		return $result
	}	
}

proc ::AIEnv::GUIManagement::MultiSelect::GreyImpl {Name args} {
	variable MultiSelectData
	
	set RowLabels [GetRowLabels $Name]
	set ColumnLabels [GetColumnLabels $Name]
	
	set NumRows [llength $RowLabels]
	set NumCols [llength $ColumnLabels]
	
	switch [llength $args] {
		0 {
			# Grey everything
			for {set i 0} {$i < $NumRows} {incr i} {
				for {set j 0} {$j < $NumCols} {incr j} {
					$MultiSelectData($Name,Path,$i,$j) configure -state disabled
					set MultiSelectData($Name,State,$i,$j) disabled
				}
				$MultiSelectData($Name,Path,Row$i) configure -state disabled
				set MultiSelectData($Name,State,Row$i) disabled
			}
			for {set i 0} {$i < $NumCols} {incr i} {
				$MultiSelectData($Name,Path,Col$i) configure -state disabled
				set MultiSelectData($Name,State,Col$i) disabled
			}
		}
		1 {
			set tmp [string tolower [lindex $args 0]]
			if { $tmp == "all" } {
				# Grey everything
				for {set i 0} {$i < $NumRows} {incr i} {
					for {set j 0} {$j < $NumCols} {incr j} {
						$MultiSelectData($Name,Path,$i,$j) configure -state disabled
						set MultiSelectData($Name,State,$i,$j) disabled
					}
					$MultiSelectData($Name,Path,Row$i) configure -state disabled
					set MultiSelectData($Name,State,Row$i) disabled
				}
				for {set i 0} {$i < $NumCols} {incr i} {
					$MultiSelectData($Name,Path,Col$i) configure -state disabled
					set MultiSelectData($Name,State,Col$i) disabled
				}			
			} else {
				# We got one argument not an 'all', so find out if it is a row or a column
				set tmp [lindex $args 0]
				set RowIndex [lsearch $RowLabels $tmp]
				set ColIndex [lsearch $ColumnLabels $tmp]
				if { $RowIndex == -1 } {
					if { $ColIndex != -1 } {
						# We have a column selected, so iterate down over the rows greying out the buttons
						for {set i 0} {$i < $NumRows} {incr i} {
							$MultiSelectData($Name,Path,$i,$ColIndex) configure -state disabled
							set MultiSelectData($Name,State,$i,$ColIndex) disabled
						}
						# Grey out the column heading
						$MultiSelectData($Name,Path,Col$ColIndex) configure -state disabled
						set MultiSelectData($Name,State,Col$ColIndex) disabled
					} else {
						set OptList $RowLabels
						lappend OptList $ColumnLabels
						set OptList [join $ColumnLabels ", "]
						set OptList [linsert $OptList "end-1" "or"]
						error "The column label: \"$args\" was not found in the multiSelect widget named: \"$Name\".\nMust be $OptList"
					}
				} else {
					# We have a row selected, so iterate over the columns greying out the buttons
					for {set i 0} {$i < $NumCols} {incr i} {
						$MultiSelectData($Name,Path,$RowIndex,$i) configure -state disabled
						set MultiSelectData($Name,State,$RowIndex,$i) disabled	
					}
					$MultiSelectData($Name,Path,Row$RowIndex) configure -state disabled
					set MultiSelectData($Name,State,Row$RowIndex) disabled
				}
			}			
		}
		2 {
			set RowLabel [lindex $args 0]
			set ColLabel [lindex $args 1]

			set RowIndex [lsearch $RowLabels $RowLabel]
			set ColIndex [lsearch $ColumnLabels $ColLabel]

			if { $RowIndex != -1 } {
				if { $ColIndex != -1 } {
					$MultiSelectData($Name,Path,$RowIndex,$ColIndex) configure -state disabled
					set MultiSelectData($Name,CurState,$RowIndex,$ColIndex) disabled
				} else {
					set OptList [join $ColLabels ", "]
					set OptList [linsert $OptList "end-1" "or"]
					error "The column label \"$ColLabel\" was not found in the multiSelect widget named $Name.\nMust be $OptList."
				}
			} else {
				set OptList [join $RowLabels ", "]
				set OptList [linsert $OptList "end-1" "or"]
				error "The row label \"$RowLabel\" was not found in the multiSelect widget named $Name.\nMust be $OptList."		
			}				
		}
		default {
			error "Wrong number of arguments to \"$Name grey\""
		}
	}
}


proc ::AIEnv::GUIManagement::MultiSelect::_ungrey {Name args} {
	if {[catch {eval [list UnGreyImpl $Name] $args} result] != 0} {
		::AIEnv::GUIManagement::RuntimeError $result
	} else {
		return $result
	}	
}

proc ::AIEnv::GUIManagement::MultiSelect::UnGreyImpl {Name args} {
	variable MultiSelectData
	
	set RowLabels [GetRowLabels $Name]
	set ColumnLabels [GetColumnLabels $Name]
	
	set NumRows [llength $RowLabels]
	set NumCols [llength $ColumnLabels]
	
	switch [llength $args] {
		0 {
			# Grey everything
			for {set i 0} {$i < $NumRows} {incr i} {
				for {set j 0} {$j < $NumCols} {incr j} {
					$MultiSelectData($Name,Path,$i,$j) configure -state normal
					set MultiSelectData($Name,State,$i,$j) normal
				}
				$MultiSelectData($Name,Path,Row$i) configure -state normal
				set MultiSelectData($Name,State,Row$i) normal
			}
			for {set i 0} {$i < $NumCols} {incr i} {
				$MultiSelectData($Name,Path,Col$i) configure -state normal
				set MultiSelectData($Name,State,Col$i) normal
			}
		}
		1 {
			set tmp [string tolower [lindex $args 0]]
			if { $tmp == "all" } {
				# Grey everything
				for {set i 0} {$i < $NumRows} {incr i} {
					for {set j 0} {$j < $NumCols} {incr j} {
						$MultiSelectData($Name,Path,$i,$j) configure -state normal
						set MultiSelectData($Name,State,$i,$j) normal
					}
					$MultiSelectData($Name,Path,Row$i) configure -state normal
					set MultiSelectData($Name,State,Row$i) normal
				}
				for {set i 0} {$i < $NumCols} {incr i} {
					$MultiSelectData($Name,Path,Col$i) configure -state normal
					set MultiSelectData($Name,State,Col$i) normal
				}			
			} else {
				# We got one argument not an 'all', so find out if it is a row or a column
				set tmp [lindex $args 0]
				set RowIndex [lsearch $RowLabels $tmp]
				set ColIndex [lsearch $ColumnLabels $tmp]
				if { $RowIndex == -1 } {
					if { $ColIndex != -1 } {
						# We have a column selected, so iterate down over the rows greying out the buttons
						for {set i 0} {$i < $NumRows} {incr i} {
							$MultiSelectData($Name,Path,$i,$ColIndex) configure -state normal
							set MultiSelectData($Name,State,$i,$ColIndex) normal
						}
						# Grey out the column heading
						$MultiSelectData($Name,Path,Col$ColIndex) configure -state normal
						set MultiSelectData($Name,State,Col$ColIndex) normal
					} else {
						set OptList $RowLabels
						lappend OptList $ColumnLabels
						set OptList [join $ColumnLabels ", "]
						set OptList [linsert $OptList "end-1" "or"]
						error "The column label: \"$args\" was not found in the multiSelect widget named: \"$Name\".\nMust be $OptList"
					}
				} else {
					# We have a row selected, so iterate over the columns greying out the buttons
					for {set i 0} {$i < $NumCols} {incr i} {
						$MultiSelectData($Name,Path,$RowIndex,$i) configure -state normal
						set MultiSelectData($Name,State,$RowIndex,$i) normal	
					}
					$MultiSelectData($Name,Path,Row$RowIndex) configure -state normal
					set MultiSelectData($Name,State,Row$RowIndex) normal
				}
			}			
		}
		2 {
			set RowLabel [lindex $args 0]
			set ColLabel [lindex $args 1]

			set RowIndex [lsearch $RowLabels $RowLabel]
			set ColIndex [lsearch $ColumnLabels $ColLabel]

			if { $RowIndex != -1 } {
				if { $ColIndex != -1 } {
					$MultiSelectData($Name,Path,$RowIndex,$ColIndex) configure -state normal
					set MultiSelectData($Name,CurState,$RowIndex,$ColIndex) normal
				} else {
					set OptList [join $ColLabels ", "]
					set OptList [linsert $OptList "end-1" "or"]
					error "The column label \"$ColLabel\" was not found in the multiSelect widget named $Name.\nMust be $OptList."
				}
			} else {
				set OptList [join $RowLabels ", "]
				set OptList [linsert $OptList "end-1" "or"]
				error "The row label \"$RowLabel\" was not found in the multiSelect widget named $Name.\nMust be $OptList."		
			}				
		}
		default {
			error "Wrong number of arguments to \"$Name ungrey\""
		}
	}
}

proc ::AIEnv::GUIManagement::MultiSelect::_select {Name args} {
	if {[catch {eval [list SelectImpl $Name] $args} result] != 0} {
		::AIEnv::GUIManagement::RuntimeError $result
	} else {
		return $result
	}	
}

proc ::AIEnv::GUIManagement::MultiSelect::SelectImpl {Name args} {

	variable MultiSelectData
	set RowLabels [GetRowLabels $Name]
	set ColumnLabels [GetColumnLabels $Name]
	
	set NumRows [llength $RowLabels]
	set NumCols [llength $ColumnLabels]
	
	set Exclusive [GetExclusivity $Name]
	
	
	# No arguments are passed in
	switch [llength $args] {
		0 {
			if { $Exclusive == 1 } {
				error "This is an exclusive Multiselect widget. You must supply a column label to the selectall function for exclusive Multiselect widgets."
			} else {
				# This is a non exclusive multiselect.  So select everything
				for {set i 0} {$i < $NumRows} {incr i} {
					for {set j 0} {$j < $NumCols} {incr j} {
						if { [$MultiSelectData($Name,Path,$i,$j) cget -state] == "normal" } {
							set MultiSelectData($Name,SelectData,$i,$j) 1
						} else {
							set MultiSelectData($Name,SelectData,$i,$j) 0
						}
					}
				}
			}			
		}
		1 {
			set tmp [string tolower [lindex $args 0]]
			if { $tmp == "all" } {
				if { $Exclusive == 1 } {
					error "This is an exclusive Multiselect widget. You must supply a column label to the selectall function for exclusive Multiselect widgets."
				} else {
					# This is a non exclusive multiselect.  So select everything
					for {set i 0} {$i < $NumRows} {incr i} {
						for {set j 0} {$j < $NumCols} {incr j} {
							if { [$MultiSelectData($Name,Path,$i,$j) cget -state] == "normal" } {
								set MultiSelectData($Name,SelectData,$i,$j) 1
							} else {
								set MultiSelectData($Name,SelectData,$i,$j) 0
							}
						}
					}
				}						
			} else {
				# We've got one argument, so handle things based on whether it is exclusive
				# or not.  The value passed in should be either a row or a column
				# so look for it in both places and then go from there
				
				set tmp [lindex $args 0]
				set RowIndex [lsearch $RowLabels $tmp]
				set ColIndex [lsearch $ColumnLabels $tmp]

				if { $Exclusive == 1 } {
					# Make sure they didn't select a row within an exclusive multiselect
					if { $RowIndex == -1 } {
						if { $ColIndex != -1 } {
							# Iterate down the rows selecting all in the given column
							for {set i 0} {$i < $NumRows} {incr i} {
								if { [$MultiSelectData($Name,Path,$i,$ColIndex) cget -state] == "normal" } {
									set MultiSelectData($Name,SelectData,Row$i) $ColIndex
								}
							}
						} else {
							set OptList [join $ColumnLabels ", "]
							set OptList [linsert $OptList "end-1" "or"]
							error "The column label: \"$args\" was not found in the multiSelect widget named: \"$Name\".\nMust be $OptList"
						}
					} else {
						error "This is an exclusive multiSelect widget.  You cannot specify a row label for the selectall function."
					}
				} else {
					# This is a non exclusive multiselect widget
					if { $RowIndex == -1 } {
						if { $ColIndex != -1 } {
							# We have a column selected, so iterate down over the rows selecting the buttons
							for {set i 0} {$i < $NumRows} {incr i} {
								if { [$MultiSelectData($Name,Path,$i,$ColIndex) cget -state] == "normal" } {
									set MultiSelectData($Name,SelectData,$i,$ColIndex) 1
								}
							}
						} else {
							set OptList $RowLabels
							lappend OptList $ColumnLabels
							set OptList [join $ColumnLabels ", "]
							set OptList [linsert $OptList "end-1" "or"]
							error "The label: \"$args\" was not found in the multiSelect widget named: \"$Name\".\nMust be $OptList"
						}
					} else {
						# We have a row selected, so iterate across over the rows selecting the buttons
						for {set i 0} {$i < $NumCols} {incr i} {
							if { [$MultiSelectData($Name,Path,$RowIndex,$i) cget -state] == "normal" } {
								set MultiSelectData($Name,SelectData,$RowIndex,$i) 1
							}
						}
					}
				}
			}
		}
		2 {
			set SelectedRowLabel [lindex $args 0]
			set SelectedColLabel [lindex $args 1]

			set RowIndex [lsearch $RowLabels $SelectedRowLabel]
			set ColIndex [lsearch $ColumnLabels $SelectedColLabel]

			if { $RowIndex == -1 } {
				set OptList [join $RowLabels ", "]
				set OptList [linsert $OptList "end-1" "or"]
				error "The row label: \"$SelectedRowLabel\" was not found in the multiSelect widget named: \"$Name\".\nMust be $OptList"
			}

			if { $ColIndex == -1 } {
				set OptList [join $ColumnLabels ", "]
				set OptList [linsert $OptList "end-1" "or"]
				error "The column label: \"$SelectedColLabel\" was not found in the multiSelect widget named: \"$Name\".\nMust be $OptList"
			}
			
			if { [$MultiSelectData($Name,Path,$RowIndex,$ColIndex) cget -state] == "normal" } {
				if { $Exclusive == 1 } {
					# Since the exclusive chooser uses radio buttons we need to index
					# the row in the array and set its value equal to the chosen column.
					set MultiSelectData($Name,SelectData,Row$RowIndex) $ColIndex
				} else {
					# If we are not using an exclusive chooser, we need to set the 
					# row column index to one to signal to the checkbox that this
					# item is selected.
					set MultiSelectData($Name,SelectData,$RowIndex,$ColIndex) 1
				}
			}
		}
		default {
			error "Wrong number of arguments passed to $Name select"
		}
	}
	set Parent [GetParent $Name]
	$Parent setdirty	
}


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

proc ::AIEnv::GUIManagement::MultiSelect::_unselect {Name args} {
	if {[catch {eval [list UnSelectImpl $Name] $args} result] != 0} {
		::AIEnv::GUIManagement::RuntimeError $result
	} else {
		return $result
	}	
}

proc ::AIEnv::GUIManagement::MultiSelect::UnSelectImpl {Name args} {

	variable MultiSelectData
	set RowLabels [GetRowLabels $Name]
	set ColumnLabels [GetColumnLabels $Name]
	
	set NumRows [llength $RowLabels]
	set NumCols [llength $ColumnLabels]
	
	set Exclusive [GetExclusivity $Name]
	
	
	# No arguments are passed in
	switch [llength $args] {
		0 {
			if { $Exclusive == 1 } {
				error "This is an exclusive Multiselect widget. You must supply a column label to the selectall function for exclusive Multiselect widgets."
			} else {
				# This is a non exclusive multiselect.  So select everything
				for {set i 0} {$i < $NumRows} {incr i} {
					for {set j 0} {$j < $NumCols} {incr j} {
						set MultiSelectData($Name,SelectData,$i,$j) 0
					}
				}
			}			
		}
		1 {
			set tmp [string tolower [lindex $args 0]]
			if { $tmp == "all" } {
				if { $Exclusive == 1 } {
					error "This is an exclusive Multiselect widget. You must supply a column label to the selectall function for exclusive Multiselect widgets."
				} else {
					# This is a non exclusive multiselect.  So select everything
					for {set i 0} {$i < $NumRows} {incr i} {
						for {set j 0} {$j < $NumCols} {incr j} {
							set MultiSelectData($Name,SelectData,$i,$j) 0
						}
					}
				}						
			} else {
				# We've got one argument, so handle things based on whether it is exclusive
				# or not.  The value passed in should be either a row or a column
				# so look for it in both places and then go from there
				set tmp [lindex $args 0]
				set RowIndex [lsearch $RowLabels $tmp]
				set ColIndex [lsearch $ColumnLabels $tmp]

				if { $Exclusive == 1 } {
					# Make sure they didn't select a row within an exclusive multiselect
					if { $RowIndex == -1 } {
						if { $ColIndex != -1 } {
							# Iterate down the rows selecting all in the given column
							for {set i 0} {$i < $NumRows} {incr i} {
								set MultiSelectData($Name,SelectData,Row$i) -1
							}
						} else {
							set OptList [join $ColumnLabels ", "]
							set OptList [linsert $OptList "end-1" "or"]
							error "The column label: \"$args\" was not found in the multiSelect widget named: \"$Name\".\nMust be $OptList"
						}
					} else {
						error "This is an exclusive multiSelect widget.  You cannot specify a row label for the selectall function."
					}
				} else {
					# This is a non exclusive multiselect widget
					if { $RowIndex == -1 } {
						if { $ColIndex != -1 } {
							# We have a column selected, so iterate down over the rows selecting the buttons
							for {set i 0} {$i < $NumRows} {incr i} {
								set MultiSelectData($Name,SelectData,$i,$ColIndex) 0
							}
						} else {
							set OptList $RowLabels
							lappend OptList $ColumnLabels
							set OptList [join $ColumnLabels ", "]
							set OptList [linsert $OptList "end-1" "or"]
							error "The label: \"$args\" was not found in the multiSelect widget named: \"$Name\".\nMust be $OptList"
						}
					} else {
						# We have a row selected, so iterate across over the rows selecting the buttons
						for {set i 0} {$i < $NumCols} {incr i} {
							set MultiSelectData($Name,SelectData,$RowIndex,$i) 0
						}
					}
				}
			}
		}
		2 {
			set SelectedRowLabel [lindex $args 0]
			set SelectedColLabel [lindex $args 1]

			set RowIndex [lsearch $RowLabels $SelectedRowLabel]
			set ColIndex [lsearch $ColumnLabels $SelectedColLabel]

			if { $RowIndex == -1 } {
				set OptList [join $RowLabels ", "]
				set OptList [linsert $OptList "end-1" "or"]
				error "The row label: \"$SelectedRowLabel\" was not found in the multiSelect widget named: \"$Name\".\nMust be $OptList"
			}

			if { $ColIndex == -1 } {
				set OptList [join $ColumnLabels ", "]
				set OptList [linsert $OptList "end-1" "or"]
				error "The column label: \"$SelectedColLabel\" was not found in the multiSelect widget named: \"$Name\".\nMust be $OptList"
			}

			if { $Exclusive == 1 } {
				# Since the exclusive chooser uses radio buttons we need to index
				# the row in the array and set its value equal to the chosen column.
				set MultiSelectData($Name,SelectData,Row$RowIndex) -1
			} else {
				# If we are not using an exclusive chooser, we need to set the 
				# row column index to one to signal to the checkbox that this
				# item is selected.
				set MultiSelectData($Name,SelectData,$RowIndex,$ColIndex) 0
			}			
		}
		default {
			error "Wrong number of arguments passed to $Name unselect"
		}
	}
	
	set Parent [GetParent $Name]
	$Parent setdirty
}


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

proc ::AIEnv::GUIManagement::MultiSelect::_widgetgrey {Name args} {
	if {[catch {eval [list WidgetGreyImpl $Name] $args} result] != 0} {
		::AIEnv::GUIManagement::RuntimeError $result
	} else {
		return $result
	}		
}

proc ::AIEnv::GUIManagement::MultiSelect::WidgetGreyImpl {Name args} {
	# Grey out everything
	variable MultiSelectData
	
	set NumCols [llength [GetColumnLabels $Name]]
	set NumRows [llength [GetRowLabels $Name]]
	
	# Buttons
	for {set i 0} {$i < $NumRows} {incr i} {
		for {set j 0} {$j < $NumCols} {incr j} {
			$MultiSelectData($Name,Path,$i,$j) configure -state disable		
		}
		# Rows
		$MultiSelectData($Name,Path,Row$i) configure -state disable
	}
	# Cols
	for {set j 0} {$j < $NumCols} {incr j} {
		$MultiSelectData($Name,Path,Col$j) configure -state disable
	}
	# MainFrame
	$MultiSelectData($Name,MainFrame) configure -state disable
}

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

proc ::AIEnv::GUIManagement::MultiSelect::_widgetungrey {Name args} {
	if {[catch {eval [list WidgetUnGreyImpl $Name] $args} result] != 0} {
		::AIEnv::GUIManagement::RuntimeError $result
	} else {
		return $result
	}		
}

proc ::AIEnv::GUIManagement::MultiSelect::WidgetUnGreyImpl {Name args} {
	# Restore everything to its previous grey state
	variable MultiSelectData

	set NumCols [llength [GetColumnLabels $Name]]
	set NumRows [llength [GetRowLabels $Name]]

	# Buttons
	for {set i 0} {$i < $NumRows} {incr i} {
		for {set j 0} {$j < $NumCols} {incr j} {
			$MultiSelectData($Name,Path,$i,$j) configure -state $MultiSelectData($Name,State,$i,$j)
		}
		# Rows
		$MultiSelectData($Name,Path,Row$i) configure -state $MultiSelectData($Name,State,Row$i)
	}
	# Cols
	for {set j 0} {$j < $NumCols} {incr j} {
		$MultiSelectData($Name,Path,Col$j) configure -state $MultiSelectData($Name,State,Col$j)
	}
	# MainFrame
	$MultiSelectData($Name,MainFrame) configure -state normal
}

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

proc ::AIEnv::GUIManagement::MultiSelect::GetColumnLabels {Name} {
	variable MultiSelectData
	if { [array names MultiSelectData "$Name,columnLabel"] != "" } {
		return $MultiSelectData($Name,columnLabel)
	} else {
		error "The column labels have not been set for the multiselect widget named: \"$Name\""
	}
}

proc ::AIEnv::GUIManagement::MultiSelect::GetRowLabels {Name} {
	variable MultiSelectData
	if { [array names MultiSelectData "$Name,rowLabel"] != "" } {
		return $MultiSelectData($Name,rowLabel)
	} else {
		error "The row labels have not been set for the multiselect widget named: \"$Name\""
	}
}

proc ::AIEnv::GUIManagement::MultiSelect::GetParentType {Name} {
	variable MultiSelectData
	if { [array names MultiSelectData "$Name,parent"] != "" } {
		set Parent $MultiSelectData($Name,parent)
		return [$Parent get type]
	} else {
		error "The parent object has not been set for the multiselect widget named: \"$Name\""
	}	
}

proc ::AIEnv::GUIManagement::MultiSelect::GetParent {Name} {
	variable MultiSelectData
	if { [array names MultiSelectData "$Name,parent"] != "" } {
		return $MultiSelectData($Name,parent)
	} else {
		error "The parent object has not been set for the multiselect widget named: \"$Name\""
	}	
}

proc ::AIEnv::GUIManagement::MultiSelect::SetMainFrameTitle {Name} {
	variable MultiSelectData
	if {[array names MultiSelectData "$Name,MainFrame"] != ""} {
	    set title [array names MultiSelectData "$Name,title"]
	    if {$title != ""} {
		    $MultiSelectData($Name,MainFrame) configure -text $title
		}
	}
}

proc ::AIEnv::GUIManagement::MultiSelect::GetTitle {Name} {
	variable MultiSelectData
	if { [array names MultiSelectData "$Name,title"] != "" } {
		return $MultiSelectData($Name,title)
	} else {
		error "The parent object has not been set for the multiselect widget named: \"$Name\""
	}	
}

proc ::AIEnv::GUIManagement::MultiSelect::GetNodeID {Name} {
	variable MultiSelectData
	if { [array names MultiSelectData "$Name,nodeID"] != "" } {
		return $MultiSelectData($Name,nodeID)
	} else {
		error "The nodeID has not been set for the multiselect widget named: \"$Name\""
	}	
}

proc ::AIEnv::GUIManagement::MultiSelect::GetExclusivity {Name} {
	variable MultiSelectData
	if { [array names MultiSelectData "$Name,rowExclusive"] != "" } {
		return $MultiSelectData($Name,rowExclusive)
	} else {
		error "The exclusivity flag has not been set for the multiselect widget named: \"$Name\""
	}
}

proc ::AIEnv::GUIManagement::MultiSelect::GetDirtyFlag {Name} {
	variable MultiSelectData
	if { [array names MultiSelectData "$Name,dirtyFlag"] != "" } {
		return $MultiSelectData($Name,dirtyFlag)
	} else {
		error "The dirty flag has not been set for the multiselect widget named: \"$Name\""
	}
}

