/*==========================================================================*\
| $Id: GradeStudentSubmissionPage.java,v 1.11 2012/05/09 16:32:02 stedwar2 Exp $
|*-------------------------------------------------------------------------*|
| Copyright (C) 2006-2012 Virginia Tech
|
| This file is part of Web-CAT.
|
| Web-CAT is free software; you can redistribute it and/or modify
| it under the terms of the GNU Affero General Public License as published
| by the Free Software Foundation; either version 3 of the License, or
| (at your option) any later version.
|
| Web-CAT 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 General Public License for more details.
|
| You should have received a copy of the GNU Affero General Public License
| along with Web-CAT; if not, see <http://www.gnu.org/licenses/>.
\*==========================================================================*/
package org.webcat.grader;
import com.webobjects.appserver.*;
import com.webobjects.foundation.*;
import er.extensions.appserver.ERXDisplayGroup;
import org.apache.log4j.Logger;
import org.webcat.core.*;
import org.webcat.ui.generators.JavascriptGenerator;
// -------------------------------------------------------------------------
/**
* Allow the user to enter/edit "TA" comments for a submission.
*
* @author Stephen Edwards
* @author Last changed by $Author: stedwar2 $
* @version $Revision: 1.11 $, $Date: 2012/05/09 16:32:02 $
*/
public class GradeStudentSubmissionPage
extends GraderComponent
{
//~ Constructors ..........................................................
// ----------------------------------------------------------
/**
* Default constructor.
* @param context The page's context
*/
public GradeStudentSubmissionPage( WOContext context )
{
super( context );
}
//~ KVC Attributes (must be public) .......................................
public SubmissionResult result;
public Submission submission;
public ERXDisplayGroup<SubmissionFileStats> statsDisplayGroup;
// For iterating over display group
public SubmissionFileStats stats;
public int index;
public UserSubmissionPair selectedUserSubmissionForPickerDialog;
public NSArray<UserSubmissionPair> allUserSubmissionsForNavigationForPickerDialog;
/** true if submission file stats are recorded for this submission */
public boolean hasFileStats = false;
public String javascriptText = "<script type=\"text/javascript\">\n"
+ "var editor = null;\n"
+ "function initEditor() {\n"
+ "editor = new HTMLArea(\"source\");\n"
+ "editor.generate();\n"
+ "}\n"
+ "</script>\n";
public NSArray<Byte> formats = SubmissionResult.formats;
public byte aFormat;
public NSArray<UserSubmissionPair> availableSubmissions;
public int thisSubmissionIndex;
//~ Methods ...............................................................
// ----------------------------------------------------------
protected void beforeAppendToResponse(
WOResponse response, WOContext context)
{
if (result == null)
{
if (submission == null)
{
if ( prefs().submission() == null )
{
throw new RuntimeException( "null submission selected" );
}
submission = prefs().submission();
}
if ( submission.result() == null )
{
throw new RuntimeException( "null submission result" );
}
result = submission.result();
}
if (log.isDebugEnabled())
{
log.debug( "result = " + result);
if (result != null)
{
log.debug( "result = " + result.hashCode());
log.debug( "result EC = " + result.editingContext().hashCode());
log.debug( "snapshot = " + result.snapshot());
}
}
hasFileStats = ( result.submissionFileStats().count() > 0 );
statsDisplayGroup.setObjectArray( result.submissionFileStats() );
showCoverageData = null;
priorComments = result.comments();
super.beforeAppendToResponse( response, context );
}
// ----------------------------------------------------------
public void saveGrading()
{
result.addCommentByLineFor(user(), priorComments);
}
// ----------------------------------------------------------
public WOComponent next()
{
return applyLocalChanges()
? super.next()
: null;
}
// ----------------------------------------------------------
public WOComponent saveThenList()
{
return next();
}
// ----------------------------------------------------------
public int indexOfNextSubmission()
{
int nextIndex = thisSubmissionIndex;
do
{
nextIndex++;
} while (nextIndex < availableSubmissions.count()
&& (!availableSubmissions.objectAtIndex(
nextIndex).userHasSubmission()
|| availableSubmissions.objectAtIndex(
nextIndex).submission().result() == null));
return nextIndex;
}
// ----------------------------------------------------------
public WOComponent saveThenNextStudent()
{
int nextSub = indexOfNextSubmission();
if (availableSubmissions == null
|| nextSub >= availableSubmissions.count())
{
// If there's no place to go, then go back to the list
return saveThenList();
}
if (applyLocalChanges())
{
thisSubmissionIndex = nextSub;
submission = availableSubmissions
.objectAtIndex(nextSub).submission();
prefs().setSubmissionRelationship(submission);
prefs().setSubmissionFileStatsRelationship(null);
result = submission.result();
}
return null;
}
// ----------------------------------------------------------
public WOComponent cancel()
{
return super.cancel();
// return super.next();
}
// ----------------------------------------------------------
public WOComponent defaultAction()
{
log.debug("defaultAction()");
log.debug("form values = " + context().request().formValues());
return null;
}
// ----------------------------------------------------------
public boolean applyLocalChanges()
{
NSTimestamp now = new NSTimestamp();
saveGrading();
if (result.status() == Status.TO_DO)
{
if (result.taScoreRaw() != null
&& result.taScore() != submission
.assignmentOffering().assignment()
.submissionProfile().taPoints())
{
result.setStatus(Status.UNFINISHED);
}
else
{
for (SubmissionFileStats fs : result.submissionFileStats())
{
if (fs.comments().count() > 0)
{
result.setStatus(Status.UNFINISHED);
break;
}
}
}
}
if (result.changedProperties().size() > 0)
{
result.setLastUpdated(now);
}
log.debug("Before commiting, result = " + result.snapshot());
return super.applyLocalChanges();
}
// ----------------------------------------------------------
public WOComponent fileStatsDetails()
{
log.debug( "fileStatsDetails()" );
prefs().setSubmissionFileStatsRelationship( stats );
WCComponent statsPage = pageWithName(EditFileCommentsPage.class);
statsPage.nextPage = this;
return statsPage;
}
// ----------------------------------------------------------
public WOActionResults pickOtherSubmission()
{
saveGrading();
selectedUserSubmissionForPickerDialog =
new UserSubmissionPair(submission.user(), submission);
allUserSubmissionsForNavigationForPickerDialog = availableSubmissions;
JavascriptGenerator js = new JavascriptGenerator();
js.dijit("pickSubmissionDialog").call("show");
return js;
}
// ----------------------------------------------------------
public String coverageMeter()
{
return FinalReportPage.meter( ( (double)stats.elementsCovered() ) /
( (double)stats.elements() ) );
}
// ----------------------------------------------------------
public boolean gradingDone()
{
return result.status() == Status.CHECK;
}
// ----------------------------------------------------------
public void setGradingDone(boolean done)
{
if (done)
{
result.setStatus(Status.CHECK);
for (Submission sub : result.submissions())
{
sub.emailNotificationToStudent(
"has been updated by the course staff");
}
}
}
// ----------------------------------------------------------
public WOComponent regradeActionOk()
{
if (!applyLocalChanges()) return null;
Submission sub = prefs().submission();
sub.requeueForGrading( localContext() );
prefs().setSubmissionRelationship( null );
applyLocalChanges();
Grader.getInstance().graderQueue().enqueue( null );
return back();
}
// ----------------------------------------------------------
public WOActionResults regrade()
{
saveGrading();
if (hasMessages())
{
return displayMessages();
}
return new ConfirmingAction(this, false)
{
@Override
protected String confirmationTitle()
{
return "Confirm Regrade of This Submission?";
}
@Override
protected String confirmationMessage()
{
return "<p>This action will <b>regrade this submission</b> "
+ "for the selected student.</p><p>This will also "
+ "<b>delete all prior results</b> for the submission "
+ "and <b>delete all TA comments and scoring</b> that "
+ "have been recorded for the submission.</p><p>This "
+ "submission will be re-queued for grading, and the "
+ "student will receive an e-mail message when new "
+ "results are available.</p><p>Regrade this "
+ "submission?</p>";
}
@Override
protected WOActionResults actionWasConfirmed()
{
return regradeActionOk();
}
};
}
// ----------------------------------------------------------
public String formatLabel()
{
return SubmissionResult.formatStrings.objectAtIndex( aFormat );
}
// ----------------------------------------------------------
public Boolean showCoverageData()
{
if ( showCoverageData == null )
{
showCoverageData = Boolean.FALSE;
if ( hasFileStats )
{
for (SubmissionFileStats sfs : statsDisplayGroup.allObjects())
{
if ( sfs.elementsRaw() != null )
{
showCoverageData = Boolean.TRUE;
break;
}
}
}
}
return showCoverageData;
}
// ----------------------------------------------------------
public WOComponent fullPrintableReport()
{
FullPrintableReport report =
pageWithName(FullPrintableReport.class);
report.result = result;
report.nextPage = this;
return report;
}
// ----------------------------------------------------------
public Byte commentFormat()
{
Byte format = SubmissionResult.formats.get(0);
if (result != null)
{
format = SubmissionResult.formats.get(result.commentFormat());
}
return format;
}
// ----------------------------------------------------------
public void setCommentFormat(Byte format)
{
if (format != null && result != null)
{
result.setCommentFormat(format.byteValue());
}
}
// ----------------------------------------------------------
public Boolean showAutoGradedComments()
{
if (showAutoGradedComments == null)
{
if (submission.assignmentOffering().assignment()
.submissionProfile().toolPoints() > 0.0)
{
showAutoGradedComments = Boolean.TRUE;
}
else
{
showAutoGradedComments = Boolean.FALSE;
for (int i = 0; i < result.submissionFileStats().count(); i++)
{
SubmissionFileStats thisStats =
result.submissionFileStats().objectAtIndex(i);
if (thisStats.remarks() > 0)
{
showAutoGradedComments = Boolean.TRUE;
break;
}
}
}
}
return showAutoGradedComments;
}
//~ Instance/static variables .............................................
private Boolean showCoverageData;
private String priorComments;
private Boolean showAutoGradedComments;
static Logger log = Logger.getLogger( GradeStudentSubmissionPage.class );
}