# GUI to changing student's grades # Copyright (C) 1992-2000 Michigan State University # # The CAPA system is free software; you can redistribute it and/or # modify it under the terms of the GNU Library General Public License as # published by the Free Software Foundation; either version 2 of the # License, or (at your option) any later version. # # The CAPA system is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Library General Public License for more details. # # You should have received a copy of the GNU Library General Public # License along with the CAPA system; see the file COPYING. If not, # write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, # Boston, MA 02111-1307, USA. # # As a special exception, you have permission to link this program # with the TtH/TtM library and distribute executables, as long as you # follow the requirements of the GNU GPL in regard to all of the # software in the executable aside from TtH/TtM. ########################################################### # grader.tcl - # Created Guy Albertelli II 1996 ########################################################### set gTclVer 2.0 ########################################################### # createControlWindow ########################################################### # Creates the menu window ########################################################### # Arguments: none # Returns: nothing # Globals: gWindowMenu - set to the name of Menu for the windows # menu ########################################################### proc createControlWindow {} { global gWindowMenu gParseMode gParseModeButton gLprCommand gCapaConfig after 500 { dateUpdate } after 1000 { cleanWindowList } set gCapaConfig(Printer_selected) "0" set gCapaConfig(lprOneSided_command) "lpr " set gCapaConfig(lprTwoSided_command) "" set gCapaConfig(printer_option) "" wm withdraw . set menuFrame [menu .main -tearoff 0 -type tearoff -font 8x13bold \ -disabledforeground grey85 ] wm title $menuFrame "Grader" $menuFrame post 0 0 wm geometry $menuFrame "+0+20" $menuFrame add command -label "Grader" -foreground grey85 -background \ black -state disabled $menuFrame add command -label "Info..." -command { createInfoWindow } $menuFrame add command -label "Specify Class" -command { specifyClass } $menuFrame add command -label "Create Class Report" -command { \ createSummaryWindow } $menuFrame add command -label "Grade Subjective" -command { gradeSubjective } # $menuFrame add cascade -label "File" -menu $menuFrame.file $menuFrame add command -label "Excuse Problem" -command { \ createExcuseWindow } $menuFrame add cascade -label "Windows" -menu $menuFrame.windows $menuFrame add cascade -label "Print" -menu $menuFrame.print $menuFrame add command -label "Remap..." -command { createRemapWindow } $menuFrame add command -label "Quit" -command { quit } # set file [menu $menuFrame.file -tearoff 1 -font 8x13bold ] set windows [menu $menuFrame.windows -tearoff 1 -font 8x13bold] set print [menu $menuFrame.print -tearoff 1 -font 8x13bold] set gWindowMenu $windows $print add command -label "Set Summary" -command { printSetSummary } $print add command -label "Term Summary" -command { printTermSummary } set gParseMode 2 set gParseModeButton "Both, Questions Answers" } ########################################################### # createInfoWindow ########################################################### # creates the Information window ########################################################### # Arguments: None # Returns: Nothing # Globals: gDate - the variable containg the current date # gWindowMenu - used to register the new window in the # windows menu # gVer - Stores the current version of Grader (set in # C init code ########################################################### proc createInfoWindow {} { global gDate gWindowMenu gVer gTclVer gCmd gCompileDate if { [winfo exists .about] } { capaRaise .about return } set about [toplevel .about] $gWindowMenu add command -label "About" -command "capaRaise $about" wm title $about "About" label $about.l1 -font 12x24 -text "Grader $gVer" -pady 20 label $about.l4 -font 8x13 -text "Grader.tcl Version $gTclVer" -pady 20 label $about.l6 -font 8x13 -text "$gCompileDate" message $about.l2 -font 8x13 -text "Code by: Y. Tsai, G. Albertelli II Copyright Michigan State University Board of Trustees, 1992-2000, CAPA is released under to GNU GPL v2, and comes WITHOUT ANY WARRENTY, see COPYING for details." \ -pady 20 -aspect 300 label $about.l3 -font 8x13 -textvariable gDate label $about.l5 -font 8x13 -textvariable gCmd button $about.close -text "Close" -command "destroy $about removeWindowEntry About" pack $about.l1 $about.l4 $about.l6 $about.l2 $about.l3 $about.l5 \ $about.close -side top Centre_Dialog $about default } ########################################################### # quit ########################################################### # called when the quit option is selected on the menu, unmaps # all keys. ########################################################### # Arguments: None # Returns: Nothing # Globals: None ########################################################### proc quit {} { if { [makeSure "Are you sure you wish to quit?"] == "Cancel" } { return } if { [winfo exists .gradesubjective] } { subjDone } catch { rm -f [file join / tmp gkc[pid]]} catch { rm -f [file join / tmp g[pid]]} unmapAllKeys exit } ########################################################### # createExcuseWindow ########################################################### # runs capa_excuse for a set and section, creates a window to # get the information from, requires that the user has already # selected a class. ########################################################### # Arguments: None # Returns: Nothing # Globals: gPrompt - used to detect when to take the modal dialog away # gSetLoad - global var containg the current set being graded # gSectionLoad - global var containg the current section # being graded # gExcuseSet - Contains the number of the set to be excused # gExcuseProblem - number of the problem to be excused # gExcuseSection - Section number to excuse the problem for # gExcuseWho - contains either : Section or All, and is # whether to excuse an entire class or a specific # section ########################################################### proc createExcuseWindow { } { global gPrompt gSetLoad gSectionLoad gExcuseSet gExcuseProblem \ gExcuseSection gExcuseWho if {![winfo exists .grader]} { displayError "You must first specify a class" return } if { $gSetLoad == "" } { set gExcuseSet 1 } else { set gExcuseSet $gSetLoad } if { $gSectionLoad == "" } { set gExcuseSection 1 } else { set gExcuseSection $gSectionLoad } set excuse [toplevel .excuse -borderwidth 10] set whichFrame [frame $excuse.whichFrame -borderwidth 4 -relief groove] set whoFrame [frame $excuse.whoFrame -borderwidth 10] set buttonFrame [frame $excuse.buttonFrame] pack $whichFrame $whoFrame $buttonFrame -side top -anchor w set setFrame [frame $whichFrame.setFrame] set problemFrame [frame $whichFrame.problemFrame] pack $setFrame $problemFrame -side top -anchor e label $setFrame.label -text Set entry $setFrame.entry -textvariable gExcuseSet -width 3 pack $setFrame.label $setFrame.entry -side left set gExcuseProblem 1 label $problemFrame.label -text "Problem Number" entry $problemFrame.entry -textvariable gExcuseProblem -width 3 pack $problemFrame.label $problemFrame.entry -side left set sectionFrame [frame $whoFrame.sectionFrame] set allFrame [frame $whoFrame.allFrame] pack $sectionFrame $allFrame -side top -anchor w set gExcuseWho Section radiobutton $sectionFrame.radio -text "For students in section:" \ -variable gExcuseWho -value Section entry $sectionFrame.entry -textvariable gExcuseSection -width 3 pack $sectionFrame.radio $sectionFrame.entry -side left radiobutton $allFrame.radio -text "For all students in the class." \ -variable gExcuseWho -value All pack $allFrame.radio set gPrompt(result) "" button $buttonFrame.excuse -text Excuse -command { set gPrompt(yes) 1 } \ -underline 0 button $buttonFrame.cancel -text Cancel -command { set gPrompt(yes) 0 } \ -underline 0 pack $buttonFrame.excuse $buttonFrame.cancel -side left bind $excuse break Centre_Dialog $excuse default update focus $excuse raise $excuse capaGrab $excuse vwait gPrompt(yes) capaGrab release $excuse destroy $excuse if {$gPrompt(yes)} { switch $gExcuseWho { All { capaExcuse $gExcuseSet $gExcuseProblem 0 } Section { capaExcuse $gExcuseSet $gExcuseProblem $gExcuseSection } } loadScores } else { return } } ########################################################### # createSummaryWindow ########################################################### # creates a dialog to craft a summary report with ########################################################### # Arguments: None # Returns: Nothing # Globals: gWindowMenu - name of the window menu widget, used to # register the dialog box # gSetLoad - current set being graded # gSectionLoad - current section being graded # gSummaryFile - filename to save report to # gSummary - array with fields # (section) - section to create the summary for # (set) - set to creat the summary for # (who) - two possible values: section (create a section # summary), all (create a class summary) # (which) - 2 possible values: specific (summary report # for a specific set), upto (summary report upto # and including a specific set) # (first) - first field to sort by, four values:name # (student name), number (student number), # section (section), grade (grade on the sets) # (second) - second field to sort by, same four values as # above # (filename) - either default, grader picks it or specified, # user specified a name to be found in gSummaryFile ########################################################### proc createSummaryWindow {} { global gWindowMenu gSetLoad gSectionLoad gSummary gSummaryFile if { [winfo exists .summary] } { raise .summary return } if {![winfo exists .grader]} { displayError "You must first specify a class" return } if { $gSetLoad == "" } { set gSummary(set) 1 } else { set gSummary(set) $gSetLoad } if { $gSectionLoad == "" } { set gSummary(section) 1 } else { set gSummary(section) $gSectionLoad } set summary [toplevel .summary] $gWindowMenu add command -label "Summary" -command "capaRaise $summary" set whoFrame [frame $summary.whoFrame -borderwidth 4 -relief groove] set whichFrame [frame $summary.whichFrame -borderwidth 4 -relief groove] set sortFrame [frame $summary.sortFrame] set file2Frame [frame $summary.file2Frame] set buttonFrame [frame $summary.buttonFrame] pack $whoFrame $whichFrame $sortFrame $file2Frame $buttonFrame -side top pack configure $whoFrame $whichFrame -padx 10 -pady 10 set sectionFrame [frame $whoFrame.section] set allFrame [frame $whoFrame.all] pack $sectionFrame $allFrame -side top set gSummary(who) section radiobutton $sectionFrame.section -text \ "For students in default section:" -variable gSummary(who) \ -value section entry $sectionFrame.entry -textvariable gSummary(section) -width 3 pack $sectionFrame.section $sectionFrame.entry -side left radiobutton $allFrame.all -text "For all students in the class" \ -variable gSummary(who) -value all pack $allFrame.all set sectionFrame [frame $whichFrame.section] set allFrame [frame $whichFrame.all] pack $sectionFrame $allFrame -side top set gSummary(which) specific radiobutton $sectionFrame.section -text "For set:" \ -variable gSummary(which) -value specific entry $sectionFrame.entry -textvariable gSummary(set) -width 3 pack $sectionFrame.section $sectionFrame.entry -side left radiobutton $allFrame.all -text "For all sets up to:" -variable \ gSummary(which) -value upto entry $allFrame.entry -textvariable gSummary(set) -width 3 pack $allFrame.all $allFrame.entry -side left set firstFrame [frame $sortFrame.firstFrame -borderwidth 4 -relief groove] set secondFrame [frame $sortFrame.secondFrame -borderwidth 4 \ -relief groove] pack $firstFrame $secondFrame -side left set gSummary(first) name label $firstFrame.label -text "Sorting Order - Primary" radiobutton $firstFrame.name -text "Student Name" -variable \ gSummary(first) -value name radiobutton $firstFrame.number -text "Student Number" -variable \ gSummary(first) -value number radiobutton $firstFrame.section -text "Section" -variable \ gSummary(first) -value section radiobutton $firstFrame.grade -text "Grade" -variable gSummary(first) \ -value grade pack $firstFrame.label $firstFrame.name $firstFrame.number \ $firstFrame.section $firstFrame.grade -side top -anchor w set gSummary(second) number label $secondFrame.label -text "Sorting Order - Secondary" radiobutton $secondFrame.name -text "Student Name" -variable \ gSummary(second) -value name radiobutton $secondFrame.number -text "Student Number" -variable \ gSummary(second) -value number radiobutton $secondFrame.section -text "Section" -variable \ gSummary(second) -value section radiobutton $secondFrame.grade -text "Grade" -variable gSummary(second) \ -value grade pack $secondFrame.label $secondFrame.name $secondFrame.number \ $secondFrame.section $secondFrame.grade -side top -anchor w set defaultFrame [frame $file2Frame.defaultFrame] set fileFrame [frame $file2Frame.fileFrame] pack $defaultFrame $fileFrame -side top if {[catch {set gSummary(filename)}]} { set gSummary(filename) default } radiobutton $defaultFrame.default -text "Grader Chooses File Name" \ -variable gSummary(filename) -value default pack $defaultFrame.default radiobutton $fileFrame.label -text "Specified Output File:" \ -variable gSummary(filename) -value specified set entryFrame [frame $fileFrame.entryFrame] button $fileFrame.select -text "Select File" \ -command "selectOutputFile" pack $fileFrame.label $entryFrame $fileFrame.select -side left entry $entryFrame.entry -textvariable gSummaryFile \ -xscrollcommand "$entryFrame.scroll set" scrollbar $entryFrame.scroll -orient h -command \ "$entryFrame.entry xview" pack $entryFrame.entry $entryFrame.scroll pack configure $entryFrame.scroll -fill x button $buttonFrame.create -text "Create" -command \ "removeWindowEntry Summary destroy $summary createSummaryReport" button $buttonFrame.cancel -text "Cancel" -command \ "removeWindowEntry Summary destroy $summary" pack $buttonFrame.create $buttonFrame.cancel -side left Centre_Dialog $summary default } ########################################################### # selectOutputFile ########################################################### ########################################################### ########################################################### proc selectOutputFile {} { global gSummaryFile gSummary set gSummary(filename) specified if { "" != [ set temp [tk_getSaveFile] ] } {set gSummaryFile $temp} } ########################################################### # createSummaryReport ########################################################### # creates the summary report ########################################################### # Argumnets: None # Returns: Nothing # Globals: gSummary - the report generation information is in here # gClassDir - the directory the class is in # Files: gClassDir/ClassSet.rpt - summary report created if for the # entire class (created) # gClassDir/SecSet.rpt - summarry report created if for only a # section (created) ########################################################### proc createSummaryReport {} { global gSummary gClassDir gUniqueNumber gSummaryFile displayStatus "Opening File" both switch $gSummary(who) { all { set file [file join $gClassDir ClassSet$gSummary(set).rpt ] } section { set file [file join $gClassDir \ Sec$gSummary(section)Set$gSummary(set).rpt ] } default { displayError "An error has occurred while creating a summary \ report $gSummary(section)" return } } if { $gSummary(filename) == "specified" } { set file $gSummaryFile } if { $file == "" } { removeStatus displayError "Must specify a valid filename" return } updateStatusMessage "Creating Summary" set error [ catch {createSummary $file} ] removeStatus if {!$error && "Yes" == [makeSure "Created summary file $file, would you like to see it?"]} { set fileId [open $file r] set num [incr gUniqueNumber] set num2 [incr gUniqueNumber] winputs $num [read $fileId] winoutput $num2 $num {} } } ########################################################### # specifyClass ########################################################### # runs tk_getOpenFile and creates the class window if a directory is chosen ########################################################### # Arguments: None # Returns: Nothing # Globals: gClassDir - remembers the directory the class is in ########################################################### proc specifyClass {} { global gClassDir if { [winfo exists .grader] } { return } set var [tk_getOpenFile -title "Please select a capa.config file" -filetypes \ { { {Capa Config} {capa.config} } }] if { $var != "" } { set gClassDir [file dirname $var] cd $gClassDir } else { return } createClassWindow } ########################################################### # changeClass ########################################################### # called when the change class button is pressed, if another class # is chosen the class window is updated ########################################################### # Arguments: None # Returns: Nothing # Globals: gClassDir - remembers the directory the class is in # gClass - just the name of the directory, and therefore # the class # gLoaded - reset to zero since we are unloading the class ########################################################### proc changeClass {} { global gClassDir gClass gLoaded set var [tk_getOpenFile -title "Please select a capa.config file" -filetypes \ { { {Capa Config} {capa.config} } }] if { $var != "" } { removeWindowEntry $gClassDir set gClassDir [file dirname $var] cd $gClassDir set gClass [file tail $gClassDir] } else { return } set gLoaded 0 clearClassWindow parseCapaConfig } ########################################################### # createClassWindow ########################################################### # creates the rather complicated class window ########################################################### # Arguments: None # Returns: Nothing # Globals: gClassDir - remembers the directory the class is in # gWindowMenu - the name of the window menu widget # gOpenDate - the label linked var the date the set opens is in # gOpenTime - the label linked var the time the set opens is in # gDueDate - the label linked var the due date for the set is in # gDueTime - the label linked var the due time for the set is in # gAnswerDate - the label linked var the date the set answer # open date is in # gAnswerTime - the label linked var the time the set answer # open time is in # gSectionLoad - the current section being graded # gSetLoad - the current set being graded # gFindNumber - linked var that stores the string to search # through student numbers for # gFindName - linked var that stores the string to search # through student names for # gButtonFrame - stores the widget name of the button frame, so # the buttons' state can be changed elsewhere # gNameFrame - stores the widget name of the name entry frame, so # the entry widget's state can be changed elsewhere # gNumberFrame - stores the widget name of the number entry # frame, so the entry widget' state can be # changed elsewhere # gStudentList - the widget name of the listbox containing the # list of students # gClass - the name of the class currently being graded # gLoaded - keeps track of whether a class has been loaded yet # set to zero here ########################################################### proc createClassWindow {} { global gClassDir gWindowMenu gOpenDate gOpenTime gDueDate gDueTime \ gAnswerDate gAnswerTime gSectionLoad gSetLoad gFindNumber \ gFindName gButtonFrame gNameFrame gNumberFrame gStudentList \ gClass gLoaded set gLoaded 0 set grader [toplevel .grader] $gWindowMenu add command -label "$gClassDir" -command "capaRaise $grader" set labelFrame [frame $grader.labelFrame] set dataFrame [frame $grader.dataFrame] set columnFrame [frame $grader.columnFrame] set infoFrame [frame $grader.infoFrame] pack $labelFrame $dataFrame $columnFrame $infoFrame -side top -anchor w pack configure $infoFrame -expand 1 -fill both set gClass [file tail $gClassDir] label $labelFrame.label -background black -foreground grey85 \ -textvariable gClass -width 51 button $labelFrame.button -text "Change Class" -command { changeClass } pack $labelFrame.label $labelFrame.button -side left set dateFrame [frame $dataFrame.date -relief sunken -borderwidth 2] set actionsFrame [frame $dataFrame.actions ] pack $dateFrame $actionsFrame -side left set openDateFrame [frame $dateFrame.openDate] set openTimeFrame [frame $dateFrame.openTime] set dueDateFrame [frame $dateFrame.dueDate] set dueTimeFrame [frame $dateFrame.dueTime] set answerDateFrame [frame $dateFrame.answerDate] set answerTimeFrame [frame $dateFrame.answerTime] pack $openDateFrame $openTimeFrame $dueDateFrame $dueTimeFrame \ $answerDateFrame $answerTimeFrame -side top label $openDateFrame.text -text "Open Date:" -width 13 label $openDateFrame.date -textvariable gOpenDate -width 10 -relief sunken \ -background white pack $openDateFrame.text $openDateFrame.date -side left label $openTimeFrame.text -text "Open Time:" -width 13 label $openTimeFrame.time -textvariable gOpenTime -width 10 -relief sunken \ -background white pack $openTimeFrame.text $openTimeFrame.time -side left label $dueDateFrame.text -text "Due Date:" -width 13 label $dueDateFrame.date -textvariable gDueDate -width 10 -relief sunken \ -background white pack $dueDateFrame.text $dueDateFrame.date -side left label $dueTimeFrame.text -text "Due Time:" -width 13 label $dueTimeFrame.time -textvariable gDueTime -width 10 -relief sunken \ -background white pack $dueTimeFrame.text $dueTimeFrame.time -side left label $answerDateFrame.text -text "Answer Date:" -width 13 label $answerDateFrame.date -textvariable gAnswerDate -width 10 -relief \ sunken -background white pack $answerDateFrame.text $answerDateFrame.date -side left label $answerTimeFrame.text -text "Answer Time:" -width 13 label $answerTimeFrame.time -textvariable gAnswerTime -width 10 -relief \ sunken -background white pack $answerTimeFrame.text $answerTimeFrame.time -side left set loadFrame [frame $actionsFrame.load] set findFrame [frame $actionsFrame.find] set buttonFrame [frame $actionsFrame.buttons] set gButtonFrame $buttonFrame pack $loadFrame $findFrame $buttonFrame -side top pack configure $loadFrame -anchor e set sectionFrame [frame $loadFrame.section] set setFrame [frame $loadFrame.set] pack $sectionFrame $setFrame -side top -anchor w label $sectionFrame.label -text " Section:" entry $sectionFrame.entry -textvariable gSectionLoad -width 3 pack $sectionFrame.label $sectionFrame.entry -side left label $setFrame.label -text "Problem Set:" entry $setFrame.entry -textvariable gSetLoad -width 3 bind $setFrame.entry loadScores button $setFrame.button -text "Load Scores" -command loadScores pack $setFrame.label $setFrame.entry $setFrame.button -side left set nameFrame [frame $findFrame.name] set gNameFrame $nameFrame set numberFrame [frame $findFrame.number] set gNumberFrame $numberFrame pack $nameFrame $numberFrame -side top entry $nameFrame.name -textvariable gFindName button $nameFrame.button -text "Find By Name " -command findByName bind $nameFrame.name findByName pack $nameFrame.name $nameFrame.button -side left entry $numberFrame.name -textvariable gFindNumber button $numberFrame.button -text "Find By StudentNumber" -command findByNumber bind $numberFrame.name findByNumber pack $numberFrame.name $numberFrame.button -side left button $buttonFrame.report -text "Student Report" -command studentReport \ -state disabled button $buttonFrame.grading -text "Grading" -command createGradingWindow \ -state disabled pack $buttonFrame.report $buttonFrame.grading -side left label $columnFrame.space -text " " label $columnFrame.name -text "Student Name" -width 30 label $columnFrame.number -text "Number" -width 11 message $columnFrame.score -text "Current Set Score" -aspect 250 message $columnFrame.pin -text "Current Pin" -aspect 200 pack $columnFrame.space $columnFrame.name $columnFrame.number \ $columnFrame.score $columnFrame.pin -side left scrollbar $infoFrame.scroll -orient vertical -command \ "$infoFrame.listbox yview" set gStudentList [listbox $infoFrame.listbox -yscrollcommand \ "$infoFrame.scroll set" -height 30] pack $infoFrame.scroll $infoFrame.listbox -side left pack configure $infoFrame.scroll -expand false -fill y pack configure $infoFrame.listbox -expand true -fill both Centre_Dialog $grader default parseCapaConfig } ########################################################### # clearClassWindow ########################################################### # empties the class window of all data ########################################################### # Arguments: none # Returns: Nothing # Globals: gClassDir - remembers the directory the class is in # gWindowMenu - the name of the window menu widget # gOpenDate - the label linked var the date the set opens is in # gOpenTime - the label linked var the time the set opens is in # gDueDate - the label linked var the due date for the set is in # gDueTime - the label linked var the due time for the set is in # gAnswerDate - the label linked var the date the set answer # open date is in # gAnswerTime - the label linked var the time the set answer # open time is in # gSectionLoad - the current section being graded # gSetLoad - the current set being graded # gStudentList - the widget name of the listbox containing the # list of students # gClass - the name of the class currently being graded ########################################################### proc clearClassWindow {} { global gWindowMenu gOpenDate gOpenTime gDueDate gDueTime gAnswerDate \ gAnswerTime gStudentList gSectionLoad gSetLoad gClassDir $gWindowMenu add command -label "$gClassDir" -command "capaRaise .grader" set gOpenDate "" set gOpenTime "" set gDueDate "" set gDueTime "" set gAnswerDate "" set gAnswerTime "" set gSectionLoad "" set gSetLoad "" $gStudentList delete 0 end } ########################################################### # loadScores ########################################################### # load in a new set of scores ########################################################### # Arguments: None # Returns: Nothing # Globals: gSectionLoad - the current section being graded # gSetLoad - the current set being graded # gButtonFrame - stores the widget name of the button frame, so # the buttons' state can be changed elsewhere # gNameFrame - stores the widget name of the name entry frame, so # the entry widget's state can be changed elsewhere # gNumberFrame - stores the widget name of the number entry # frame, so the entry widget' state can be # changed elsewhere # gStudentList - the widget name of the listbox containing the # list of students # gLoaded - 1 if a section has been loaded ########################################################### proc loadScores {} { global gNumberFrame gNameFrame gButtonFrame gSectionLoad gSetLoad \ gStudentList gLoaded $gStudentList delete 0 end if { $gSectionLoad == "" } { displayError "The Section field must be completed before \ continuing." return } elseif { $gSetLoad == "" } { displayError "The Set field must be completed before \ continuing." return } set result [getHeader] switch -- $result { 0 { displayError "The Set and Section selected do not appear to exist"; return } -1 { #displayMessage "No date information is available for this set" } 1 { #break } } $gButtonFrame.report configure -state normal $gButtonFrame.grading configure -state normal ## $gButtonFrame.log configure -state normal getStudents gStudentList set gLoaded 1 } ########################################################### # findByName ########################################################### # preforms a search for a student by name, findSection returns # the section the student is in, then the correct element in the # Student ListBox is highlighted. ########################################################### # Arguments: None # Returns: Nothing # Globals: gSectionLoad - the current section being graded # gFindName - linked var that stores the string to search # through student names for # gStudentList - the widget name of the listbox containing the # list of students # gLoaded - keeps track of whther scores have been loaded yet ########################################################### proc findByName {} { global gFindName gFindNumber gStudentList gSectionLoad gLoaded fillInStudent gFindName gFindNumber 1 if { $gFindNumber == "" } { return } set section [findSection name $gFindName] if { $section == "0" } { displayError "Name not found in classl file" return } if { !(($gSectionLoad == $section) && $gLoaded) } { set gSectionLoad $section loadScores } set size [$gStudentList size] set search [string tolower $gFindName] while { $size != 0 } { incr size -1 set tempString [string tolower [$gStudentList get $size]] switch -- [string first $search $tempString] { 0 { $gStudentList selection set $size $gStudentList activate $size $gStudentList see $size } } } } ########################################################### # studentReport ########################################################### # creates a window containg a report for the current student ########################################################### # Arguments: None # Returns: Nothing # Globals: gSectionLoad - the current section being graded # gStudentList - the widget name of the listbox containing the # list of students # gWindoMenu - the name of the window menu widget ########################################################### proc studentReport {} { global gStudentList gSectionLoad gWindowMenu set string [$gStudentList get active] set studentNumber [string range $string 31 39] set text [getReportInfo $studentNumber] if {![winfo exists .a$studentNumber]} { set report [toplevel .a$studentNumber] $gWindowMenu add command -label "$studentNumber" -command \ "capaRaise $report" set labelFrame [frame $report.labelFrame] set textFrame [frame $report.textFrame] set buttonFrame [frame $report.buttonFrame] pack $buttonFrame $labelFrame $textFrame -side top pack configure $buttonFrame -anchor e label $labelFrame.namel -text "Student Name: " label $labelFrame.namet -text [string range $string 0 30] label $labelFrame.numberl -text "Number: " label $labelFrame.numbert -text [string range $string 31 39] label $labelFrame.sectionl -text "Section: " label $labelFrame.sectiont -text $gSectionLoad pack $labelFrame.namel $labelFrame.namet $labelFrame.numberl \ $labelFrame.numbert $labelFrame.sectionl $labelFrame.sectiont \ -side left scrollbar $textFrame.scrollbar -orient vertical -command \ "$textFrame.text yview" text $textFrame.text -yscrollcommand "$textFrame.scrollbar set" \ -height 30 -width 80 pack $textFrame.scrollbar $textFrame.text -side left pack configure $textFrame.scrollbar -expand false -fill y pack configure $textFrame.text -expand true -fill both button $buttonFrame.close -text "Close" -command \ "destroy $report removeWindowEntry $studentNumber" pack $buttonFrame.close Centre_Dialog $report default } else { .a$studentNumber.textFrame.text delete 0.0 end } .a$studentNumber.textFrame.text insert end $text .a$studentNumber.textFrame.text configure -state disabled } ########################################################### # findByNumber ########################################################### # finds a student based on a complete student number, once again # findSection finds the correct section and then it searches through the # list box looking for the correct student ########################################################### # Arguments: None # Returns: Nothing # Globals: gSectionLoad - the current section being graded # gFindNumber - linked var that stores the string to search # through student numbers for # gStudentList - the widget name of the listbox containing the # list of students # gLoaded - whether or not the data for the set/section has # actually been loaded ########################################################### proc findByNumber {} { global gFindName gFindNumber gStudentList gSectionLoad gLoaded fillInStudent gFindName gFindNumber 0 if { $gFindNumber == "" } { return } set section [findSection number $gFindNumber] if { $section == "0" } { displayError "Name not found in classl file" return } if { ! (($gSectionLoad == $section ) && $gLoaded) } { set gSectionLoad $section loadScores } set size [$gStudentList size] set search [string tolower $gFindNumber] while { $size != 0 } { incr size -1 set tempString [string range [string tolower \ [$gStudentList get $size]] 31 39] switch -- [string first $search $tempString] { 0 { $gStudentList selection set $size $gStudentList activate $size $gStudentList see $size } } } } ########################################################### # printBody ########################################################### # sends the file quiztemp.ps to the printer through lpr using # the option foud in gLprCommand ########################################################### # Arguments: none # Returns: Nothing # Files: /tmp/g[pid] - file containg info to print (removed) ########################################################### proc printBody { lprCommand } { set errorMsg "" set error [catch {set returnMessage [eval "exec $lprCommand"] } errorMsg ] exec /bin/rm -f /tmp/g[pid] if { $error == 1 } { displayError "When attempting to print an error occurred : $errorMsg" return 1 } else { displayMessage "Print job sent to the printer.\n $returnMessage" } return 0 } ########################################################### # printSetSummary ########################################################### # prints a set summary for the currently grading set and section ########################################################### # Arguments: None # Returns: Nothing # Globals: gSetLoad - currently being graded set # gWindowMenu - the widget name of the window menu # gSectionLoad - currently being graded section # Files: /tmp/g[pid] - file containg info to print (created) ########################################################### proc printSetSummary {} { global gSetLoad gWindowMenu gSectionLoad if { $gSetLoad == "" } { displayError "Please enter a Set number." return } if { $gSectionLoad == "" } { displayError "Please enter a Section number." return } set lprCommand [getLprCommand [file join / tmp g[pid] ] ] if { $lprCommand == "" } { displayError "Print command was empty, unable to print." return 1 } if {$lprCommand == "Cancel" } { return 1 } getSetSummary [file join / tmp g[pid]] printBody $lprCommand } ########################################################### # printTermSummary ########################################################### # creates a termsummary file and send it to the printer ########################################################### # Arguments: None # Returns: Nothing # Globals: gSetLoad - currently being graded set # gWindowMenu - the widget name of the window menu # gSectionLoad - currently being graded section # Files: /tmp/g[pid] - file containg info to print (created) ########################################################### proc printTermSummary {} { global gSetLoad gWindowMenu gSectionLoad if { $gSetLoad == "" } { displayError "Please enter a Set number." return } if { $gSectionLoad == "" } { displayError "Please enter a Section number." return } set lprCommand [getLprCommand [file join / tmp g[pid] ] ] if { $lprCommand == "" } { displayError "Print command was empty, unable to print." return 1 } if {$lprCommand == "Cancel" } { return 1 } displayStatus "Getting Term Summary" bar getTermSummary [file join / tmp g[pid] ] removeStatus printBody $lprCommand } ########################################################### # createGradingWindow ########################################################### # create the window in which the user can change the grades in ########################################################### # Arguments: None # Returns: Nothing # Globals: gStudentList - the widget name of the list box the list # of students is in. # gSectionLoad - currently being graded section # gWindowMenu - widget name of the window menu # gProblemText - stores the results of the parse of the set # gParseMode - stores either 1 (Both, Questions Answers) or # 2 (Answer Only) # gSetLoad - currently being graded set # gGrading - an array containg # (name) - Name of the student # (number) - student number # gGradeCanvas - widget name of the canvas used to contain all # of the radiobuttons when grading # gAnswer - an array containg the score for the student # ($i) - i contains the current problem number and the entry # has one of Y, N, E, or - # (max$i) - i is the problem number, these entries exist only # for handgraded questions, and is the maximum # score for that question # gQuestionType - stores whether a quetion is handgraded or not # ($i) - i contains the current problem number and the entry # has one of handGrade, or autoGrade # gParseModeButton - the text that will be displayed on # the button that switches parse modes, # either "Answer Only" or # "Both, Questions Answers" ########################################################### proc createGradingWindow {} { global gStudentList gSectionLoad gWindowMenu gProblemText gParseMode \ gSetLoad gGrading gGradeCanvas gAnswer gQuestionType \ gParseModeButton if { [winfo exists .grading] } { capaRaise .grading return } catch {unset gAnswer} set grading [toplevel .grading] $gWindowMenu add command -label "Grading" -command "capaRaise $grading" set labelFrame [frame $grading.labelFrame] set buttonFrame [frame $grading.buttonFrame] set winFrame [frame $grading.winFrame] pack $labelFrame $buttonFrame $winFrame -side top pack configure $buttonFrame -anchor e set string [$gStudentList get active] set gGrading(name) [string range $string 0 30] set gGrading(number) [string range $string 31 39] set gGrading(parsenum) $gGrading(number) label $labelFrame.namel -text "Student Name: " label $labelFrame.namet -text $gGrading(name) label $labelFrame.numberl -text "Number: " entry $labelFrame.numbert -width 9 -textvariable gGrading(parsenum) button $labelFrame.reparse -text "Parse" -command "updateGradingWindow 0" label $labelFrame.sectionl -text "Section: " label $labelFrame.sectiont -text $gSectionLoad pack $labelFrame.namel $labelFrame.namet $labelFrame.numberl \ $labelFrame.numbert $labelFrame.reparse $labelFrame.sectionl \ $labelFrame.sectiont -side left button $buttonFrame.button -textvariable gParseModeButton \ -command updateGradingWindow button $buttonFrame.save -text SAVE button $buttonFrame.close -text Close -command "removeWindowEntry Grading destroy $grading" pack $buttonFrame.button $buttonFrame.save $buttonFrame.close \ -side left set assignmentFrame [frame $winFrame.assignmentFrame] set gradingFrame [frame $winFrame.gradingFrame] pack $gradingFrame $assignmentFrame -side left scrollbar $assignmentFrame.scroll -orient vertical -command \ "$assignmentFrame.text yview" set gProblemText [text $assignmentFrame.text -yscrollcommand \ "$assignmentFrame.scroll set" -height 44 -width 80] pack $assignmentFrame.scroll $assignmentFrame.text -side left pack configure $assignmentFrame.scroll -expand false -fill y pack configure $assignmentFrame.text -expand true -fill both set numQuestions [enscriptParse $gParseMode $gSetLoad Specific 0 \ $gGrading(parsenum) $gGrading(name) gProblemText] $buttonFrame.save configure -command " saveGrading $numQuestions $grading " set setAllFrame [frame $gradingFrame.setallFrame ] set gradeFrame [frame $gradingFrame.gradeFrame ] pack $gradingFrame.setallFrame $gradeFrame -side top frame $setAllFrame.space0 -width 55 button $setAllFrame.dash -text "-" -padx -1 \ -command "gradeSetAll - $numQuestions" frame $setAllFrame.space1 -width 8 button $setAllFrame.y -text "y" -padx -1 \ -command "gradeSetAll y $numQuestions" frame $setAllFrame.space2 -width 8 button $setAllFrame.n -text "n" -padx -1 \ -command "gradeSetAll n $numQuestions" frame $setAllFrame.space3 -width 8 button $setAllFrame.e -text "E" -padx -1 \ -command "gradeSetAll E $numQuestions" frame $setAllFrame.space4 -width 8 label $setAllFrame.state -text "stat" label $setAllFrame.tries -text "tries" pack $setAllFrame.space0 $setAllFrame.dash \ $setAllFrame.space1 $setAllFrame.y \ $setAllFrame.space2 $setAllFrame.n \ $setAllFrame.space3 $setAllFrame.e \ $setAllFrame.space4 $setAllFrame.state \ $setAllFrame.tries -side left scrollbar $gradeFrame.scroll -orient vertical -command \ "$gradeFrame.canvas yview" set gGradeCanvas [canvas $gradeFrame.canvas -yscrollcommand \ "$gradeFrame.scroll set" -height 600 -width 200] pack $gradeFrame.scroll $gGradeCanvas -side left pack configure $gradeFrame.scroll -expand false -fill y pack configure $gGradeCanvas -expand true -fill both Centre_Dialog $grading default catch {unset gAnswer} catch {unset gQuestionType} getQuestionTypes $numQuestions set vSize 26 set offset 9 set todo "" for { set i 1 } { $i <= $numQuestions } { incr i } { label $gGradeCanvas.prob$i -text "$i" $gGradeCanvas create window 10 [expr $offset + $vSize * ($i-1)] \ -window $gGradeCanvas.prob$i switch $gQuestionType($i) { autoGrade { radiobutton $gGradeCanvas.dash$i -variable gAnswer($i) \ -value - $gGradeCanvas create window 40 [expr $offset+ $vSize * ($i-1)] -window \ $gGradeCanvas.dash$i radiobutton $gGradeCanvas.y$i -variable gAnswer($i) -value y $gGradeCanvas create window 64 [expr $offset+ $vSize * ($i-1)] -window \ $gGradeCanvas.y$i radiobutton $gGradeCanvas.n$i -variable gAnswer($i) -value n $gGradeCanvas create window 88 [expr $offset+ $vSize * ($i-1)] -window \ $gGradeCanvas.n$i radiobutton $gGradeCanvas.e$i -variable gAnswer($i) -value E $gGradeCanvas create window 112 [expr $offset+ $vSize * ($i-1)] -window \ $gGradeCanvas.e$i label $gGradeCanvas.state$i -textvariable gAnswer($i) $gGradeCanvas create window 136 [expr $offset+ $vSize * ($i-1)] -window \ $gGradeCanvas.state$i } handGrade { radiobutton $gGradeCanvas.e$i -variable gAnswer($i) -value E $gGradeCanvas create window 112 [expr $offset+ $vSize * ($i-1)] -window \ $gGradeCanvas.e$i scale $gGradeCanvas.hand$i -from 0 -to $gAnswer(max$i) -orient h \ -variable gAnswer(hand$i) -showvalue 0 -length 80 $gGradeCanvas create window 60 [expr $offset+ $vSize * ($i-1)] -window \ $gGradeCanvas.hand$i label $gGradeCanvas.current$i -textvariable gAnswer($i) $gGradeCanvas create window 136 [expr $offset+ $vSize * ($i-1)] -window \ $gGradeCanvas.current$i # label $gGradeCanvas.max$i -textvariable gAnswer(max$i) # $gGradeCanvas create window 112 [expr $offset+ $vSize * ($i-1)] -window \ $gGradeCanvas.max$i trace variable gAnswer(hand$i) w handGradeExcuse lappend todo $i } } entry $gGradeCanvas.tries$i -textvariable gAnswer($i.tries) -width 2 $gGradeCanvas create window 170 [expr $offset+ $vSize * ($i - 1)] \ -window $gGradeCanvas.tries$i } $gGradeCanvas configure -scrollregion "0 0 150 \ [ expr ( $vSize * $numQuestions ) + $vSize ]" setupGAnswer $numQuestions foreach item $todo { if { $gAnswer($item) != "E" && $gAnswer($item) != "-" } { set gAnswer(hand$item) $gAnswer($item) } } } ########################################################### # handGradeExcuse ########################################################### ########################################################### ########################################################### proc handGradeExcuse { name1 name2 op } { global gAnswer scan $name2 "hand%d" num if { $gAnswer($name2) != "E" && $gAnswer($name2) != "-" } { set gAnswer($num) $gAnswer($name2) } } ########################################################### # gradeSetAll ########################################################### ########################################################### ########################################################### proc gradeSetAll { type numQuestions } { global gAnswer gQuestionType for { set i 1 } { $i <= $numQuestions } { incr i } { switch $gQuestionType($i) { autoGrade { if { $gAnswer($i) != "Y" } { set gAnswer($i) $type } } handGrade { switch -- $type { y { set gAnswer($i) $gAnswer(max$i) } n { set gAnswer($i) "0" } E - - { set gAnswer($i) $type } } } } } } ########################################################### # saveGrading ########################################################### # saves all changes, and updates the main window ########################################################### # Arguments: the number of questions, and the name of the grading # window # Returns: None # Globals: None ########################################################### proc saveGrading { numQuestions grading } { if { [makeSure "You have pressed the SAVE button, Please confirm."] != \ "Cancel" } { saveGAnswer $numQuestions removeWindowEntry Grading destroy $grading loadScores } } ########################################################### # updateGradingWindow ########################################################### # reparses the file and updates the parsemode button ########################################################### # Arguments: None # Returns: Nothing # Globals: gProblemText - stores the results of the parse of the set # gParseMode - stores either 1 (Both, Questions Answers) or # 2 (Answer Only) # gSetLoad - currently being graded set # gGrading - an array containg # (name) - Name of the student # (number) - student number # gParseModeButton - the text that will be displayed on # the button that switches parse modes, # either "Answer Only" or # "Both, Questions Answers" ########################################################### proc updateGradingWindow { { changeMode 1 } } { global gParseMode gSetLoad gGrading gProblemText gParseModeButton $gProblemText delete 0.0 end displayStatus "Updating Window . . ." message if { $changeMode } { switch $gParseMode { 1 { set gParseModeButton "Both, Questions Answers" set gParseMode 2 } 2 { set gParseModeButton "Answer Only" set gParseMode 1 } } } enscriptParse $gParseMode $gSetLoad Specific 0 $gGrading(parsenum) \ $gGrading(name) gProblemText removeStatus } ########################################################### # handGrade ########################################################### # creates a dialog to get the new score for a problem from the # user for a hand graded question ########################################################### # Arguments: the number of the problem # Returns: nothing # Globals: gGradeCanvas - the name of the canvas widget that has all # of the radio buttons for grading on # gNewHandGrade - the variable the new grade will be in # gAnswer - an array containg the score for the student # ($i) - i contains the current problem number and the entry # has one of Y, N, E, or - # (max$i) - i is the problem number, these entries exist only # for handgraded questions, and is the maximum # score for that question ########################################################### proc handGrade { problemNumber } { global gGradeCanvas gNewHandGrade gAnswer set handGrade [toplevel .handGrade] set gradeFrame [frame $handGrade.gradeFrame] set buttonFrame [frame $handGrade.buttonFrame] pack $gradeFrame $buttonFrame -side top label $gradeFrame.grade -text "Grade: " entry $gradeFrame.entry -textvariable gNewHandGrade # set gNewHandGrade $gAnswer($problemNumber) set gNewHandGrade $gAnswer(max$problemNumber) label $gradeFrame.maxGrade -textvariable gAnswer(max$problemNumber) pack $gradeFrame.grade $gradeFrame.entry $gradeFrame.maxGrade -side left button $buttonFrame.cancel -text Cancel -command "set gPrompt(ok) 0" button $buttonFrame.ok -text Ok -command \ "setHandGrade $problemNumber;set gPrompt(ok) 1" pack $buttonFrame.cancel $buttonFrame.ok -side left Centre_Dialog $handGrade default capaRaise $handGrade capaGrab $handGrade vwait gPrompt(ok) capaGrab release $handGrade destroy $handGrade $gGradeCanvas.hand$problemNumber deselect } ########################################################### # main ########################################################### # sets up the auto_path variable, some globals and adds some # options then calls createControlWindow to give the user something # to do ########################################################### # Arguments: None # Returns: Nothing # Globals: None ########################################################### if { [lindex $auto_path 0] == "./lib/tcl7.5" } { set auto_path "" lappend auto_path [pwd]/lib/tcl7.5 lappend auto_path [pwd]/lib/tk4.1 } lappend auto_path /usr/local/lib/CAPA45/Grader lappend auto_path [pwd] source gradesubjective.tcl option add *font 8x13bold set gUniqueNumber 1 createControlWindow