001: /**********************************************************************************
002: *
003: * $Id: CourseGradeDetailsBean.java 22226 2007-03-06 17:42:53Z ray@media.berkeley.edu $
004: *
005: ***********************************************************************************
006: *
007: * Copyright (c) 2005 The Regents of the University of California, The MIT Corporation
008: *
009: * Licensed under the Educational Community License, Version 1.0 (the "License");
010: * you may not use this file except in compliance with the License.
011: * You may obtain a copy of the License at
012: *
013: * http://www.opensource.org/licenses/ecl1.php
014: *
015: * Unless required by applicable law or agreed to in writing, software
016: * distributed under the License is distributed on an "AS IS" BASIS,
017: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
018: * See the License for the specific language governing permissions and
019: * limitations under the License.
020: *
021: **********************************************************************************/package org.sakaiproject.tool.gradebook.ui;
022:
023: import java.io.Serializable;
024: import java.util.ArrayList;
025: import java.util.Collections;
026: import java.util.Comparator;
027: import java.util.HashMap;
028: import java.util.HashSet;
029: import java.util.Iterator;
030: import java.util.List;
031: import java.util.Map;
032: import java.util.Set;
033:
034: import javax.faces.event.ActionEvent;
035:
036: import org.apache.commons.lang.StringUtils;
037: import org.apache.commons.logging.Log;
038: import org.apache.commons.logging.LogFactory;
039: import org.sakaiproject.jsf.spreadsheet.SpreadsheetDataFileWriterCsv;
040: import org.sakaiproject.jsf.spreadsheet.SpreadsheetDataFileWriterXls;
041: import org.sakaiproject.jsf.spreadsheet.SpreadsheetUtil;
042: import org.sakaiproject.section.api.coursemanagement.EnrollmentRecord;
043: import org.sakaiproject.service.gradebook.shared.StaleObjectModificationException;
044: import org.sakaiproject.tool.gradebook.CourseGrade;
045: import org.sakaiproject.tool.gradebook.CourseGradeRecord;
046: import org.sakaiproject.tool.gradebook.CourseGradesToSpreadsheetConverter;
047: import org.sakaiproject.tool.gradebook.GradeMapping;
048: import org.sakaiproject.tool.gradebook.GradingEvent;
049: import org.sakaiproject.tool.gradebook.GradingEvents;
050: import org.sakaiproject.tool.gradebook.jsf.FacesUtil;
051:
052: public class CourseGradeDetailsBean extends EnrollmentTableBean {
053: private static final Log logger = LogFactory
054: .getLog(CourseGradeDetailsBean.class);
055:
056: // View maintenance fields - serializable.
057: private List scoreRows;
058: private CourseGrade courseGrade;
059: private List updatedGradeRecords;
060: private GradeMapping gradeMapping;
061: private double totalPoints;
062: private String courseGradesConverterPlugin;
063:
064: public class ScoreRow implements Serializable {
065: private EnrollmentRecord enrollment;
066: private CourseGradeRecord courseGradeRecord;
067: private List eventRows;
068:
069: public ScoreRow() {
070: }
071:
072: public ScoreRow(EnrollmentRecord enrollment,
073: CourseGradeRecord courseGradeRecord, List gradingEvents) {
074: this .enrollment = enrollment;
075: this .courseGradeRecord = courseGradeRecord;
076:
077: eventRows = new ArrayList();
078: for (Iterator iter = gradingEvents.iterator(); iter
079: .hasNext();) {
080: GradingEvent gradingEvent = (GradingEvent) iter.next();
081: eventRows.add(new GradingEventRow(gradingEvent));
082: }
083: }
084:
085: public String getCalculatedLetterGrade() {
086: return gradeMapping.getGrade(courseGradeRecord
087: .getNonNullAutoCalculatedGrade());
088: }
089:
090: public Double getCalculatedPercentGrade() {
091: return new Double(
092: courseGradeRecord.getNonNullAutoCalculatedGrade()
093: .doubleValue() / 100.);
094: }
095:
096: public CourseGradeRecord getCourseGradeRecord() {
097: return courseGradeRecord;
098: }
099:
100: public void setCourseGradeRecord(
101: CourseGradeRecord courseGradeRecord) {
102: this .courseGradeRecord = courseGradeRecord;
103: }
104:
105: public String getEnteredGrade() {
106: return courseGradeRecord.getEnteredGrade();
107: }
108:
109: public void setEnteredGrade(String enteredGrade) {
110: String originalEnteredGrade = courseGradeRecord
111: .getEnteredGrade();
112: if (!StringUtils.equals(enteredGrade, originalEnteredGrade)) {
113: courseGradeRecord.setEnteredGrade(enteredGrade);
114: updatedGradeRecords.add(courseGradeRecord);
115: }
116: }
117:
118: public EnrollmentRecord getEnrollment() {
119: return enrollment;
120: }
121:
122: public List getEventRows() {
123: return eventRows;
124: }
125:
126: public String getEventsLogTitle() {
127: return FacesUtil.getLocalizedString(
128: "course_grade_details_log_title",
129: new String[] { enrollment.getUser()
130: .getDisplayName() });
131: }
132: }
133:
134: protected void init() {
135: super .init();
136:
137: // Clear view state.
138: scoreRows = new ArrayList();
139: courseGrade = getGradebookManager().getCourseGrade(
140: getGradebookId());
141: updatedGradeRecords = new ArrayList();
142:
143: gradeMapping = getGradebook().getSelectedGradeMapping();
144: totalPoints = getGradebookManager().getTotalPoints(
145: getGradebookId());
146:
147: // Set up score rows.
148: Map enrollmentMap = getOrderedEnrollmentMap();
149: List studentUids = new ArrayList(enrollmentMap.keySet());
150: List gradeRecords = getGradebookManager()
151: .getPointsEarnedCourseGradeRecordsWithStats(
152: courseGrade, studentUids);
153:
154: if (!isEnrollmentSort()) {
155: // Need to sort and page based on a scores column.
156: String sortColumn = getSortColumn();
157: Comparator comparator = null;
158: if (sortColumn.equals(CourseGrade.SORT_BY_CALCULATED_GRADE)
159: || sortColumn
160: .equals(CourseGrade.SORT_BY_POINTS_EARNED)) {
161: comparator = CourseGradeRecord.calcComparator;
162: } else if (sortColumn
163: .equals(CourseGrade.SORT_BY_OVERRIDE_GRADE)) {
164: comparator = CourseGradeRecord
165: .getOverrideComparator(courseGrade
166: .getGradebook()
167: .getSelectedGradeMapping());
168: }
169: if (comparator != null) {
170: Collections.sort(gradeRecords, comparator);
171: }
172:
173: List scoreSortedStudentUids = new ArrayList();
174: for (Iterator iter = gradeRecords.iterator(); iter
175: .hasNext();) {
176: CourseGradeRecord cgr = (CourseGradeRecord) iter.next();
177: scoreSortedStudentUids.add(cgr.getStudentId());
178: }
179:
180: // Put enrollments with no scores at the beginning of the final list.
181: studentUids.removeAll(scoreSortedStudentUids);
182:
183: // Add all sorted enrollments with scores into the final list
184: studentUids.addAll(scoreSortedStudentUids);
185:
186: studentUids = finalizeSortingAndPaging(studentUids);
187: }
188:
189: // Get all of the grading events for these enrollments on this assignment
190: GradingEvents allEvents = getGradebookManager()
191: .getGradingEvents(courseGrade, studentUids);
192:
193: Map gradeRecordMap = new HashMap();
194: for (Iterator iter = gradeRecords.iterator(); iter.hasNext();) {
195: CourseGradeRecord gradeRecord = (CourseGradeRecord) iter
196: .next();
197: if (studentUids.contains(gradeRecord.getStudentId())) {
198: gradeRecordMap.put(gradeRecord.getStudentId(),
199: gradeRecord);
200: }
201: }
202:
203: // If the table is not being sorted by enrollment information, then
204: // we had to gather grade records for all students to set up the
205: // current page. In that case, eliminate the undisplayed grade records
206: // to reduce data contention.
207: if (!isEnrollmentSort()) {
208: gradeRecords = new ArrayList(gradeRecordMap.values());
209: }
210:
211: for (Iterator iter = studentUids.iterator(); iter.hasNext();) {
212: String studentUid = (String) iter.next();
213: EnrollmentRecord enrollment = (EnrollmentRecord) enrollmentMap
214: .get(studentUid);
215: CourseGradeRecord gradeRecord = (CourseGradeRecord) gradeRecordMap
216: .get(studentUid);
217: if (gradeRecord == null) {
218: gradeRecord = new CourseGradeRecord(courseGrade,
219: studentUid);
220: gradeRecords.add(gradeRecord);
221: }
222:
223: scoreRows.add(new ScoreRow(enrollment, gradeRecord,
224: allEvents.getEvents(studentUid)));
225: }
226: }
227:
228: public CourseGrade getCourseGrade() {
229: return courseGrade;
230: }
231:
232: public double getTotalPoints() {
233: return totalPoints;
234: }
235:
236: /**
237: * Action listener to update grades.
238: * NOTE: No transient fields are available yet.
239: */
240: public void processUpdateGrades(ActionEvent event) {
241: try {
242: saveGrades();
243: } catch (StaleObjectModificationException e) {
244: logger.error(e);
245: FacesUtil
246: .addErrorMessage(getLocalizedString("course_grade_details_locking_failure"));
247: }
248: }
249:
250: private void saveGrades() throws StaleObjectModificationException {
251: getGradebookManager().updateCourseGradeRecords(courseGrade,
252: updatedGradeRecords);
253: getGradebookBean().getEventTrackingService().postEvent(
254: "gradebook.updateCourseGrades",
255: "/gradebook/" + getGradebookId() + "/"
256: + updatedGradeRecords.size() + "/"
257: + getAuthzLevel());
258: // Let the user know.
259: FacesUtil
260: .addMessage(getLocalizedString("course_grade_details_grades_saved"));
261: }
262:
263: // Download spreadsheet of course grades. It's very likely that insitutions will
264: // want to customize this somewhere along the way.
265:
266: public void exportCsv(ActionEvent event) {
267: if (logger.isInfoEnabled())
268: logger.info("exporting course grade as CSV for gradebook "
269: + getGradebookUid());
270: getGradebookBean().getEventTrackingService().postEvent(
271: "gradebook.downloadCourseGrade",
272: "/gradebook/" + getGradebookId() + "/"
273: + getAuthzLevel());
274: SpreadsheetUtil
275: .downloadSpreadsheetData(
276: getSpreadsheetData(),
277: getDownloadFileName(getLocalizedString("export_course_grade_prefix")),
278: new SpreadsheetDataFileWriterCsv());
279: }
280:
281: public void exportExcel(ActionEvent event) {
282: if (logger.isInfoEnabled())
283: logger
284: .info("exporting course grade as Excel for gradebook "
285: + getGradebookUid());
286: getGradebookBean().getEventTrackingService().postEvent(
287: "gradebook.downloadCourseGrade",
288: "/gradebook/" + getGradebookId() + "/"
289: + getAuthzLevel());
290: SpreadsheetUtil
291: .downloadSpreadsheetData(
292: getSpreadsheetData(),
293: getDownloadFileName(getLocalizedString("export_course_grade_prefix")),
294: new SpreadsheetDataFileWriterXls());
295: }
296:
297: private List<List<Object>> getSpreadsheetData() {
298: // Get the full list of filtered enrollments and scores (not just the current page's worth).
299: List<EnrollmentRecord> filteredEnrollments = getWorkingEnrollments();
300: Collections.sort(filteredEnrollments,
301: ENROLLMENT_NAME_COMPARATOR);
302: Set<String> studentUids = new HashSet<String>();
303: for (EnrollmentRecord enrollment : filteredEnrollments) {
304: studentUids.add(enrollment.getUser().getUserUid());
305: }
306:
307: CourseGrade courseGrade = getGradebookManager().getCourseGrade(
308: getGradebookId());
309: List<CourseGradeRecord> courseGradeRecords = getGradebookManager()
310: .getPointsEarnedCourseGradeRecords(courseGrade,
311: studentUids);
312: Map<String, CourseGradeRecord> filteredGradesMap = new HashMap<String, CourseGradeRecord>();
313: getGradebookManager().addToGradeRecordMap(filteredGradesMap,
314: courseGradeRecords);
315: CourseGradesToSpreadsheetConverter converter = (CourseGradesToSpreadsheetConverter) getGradebookBean()
316: .getConfigurationBean().getPlugin(
317: courseGradesConverterPlugin);
318: return converter.getSpreadsheetData(filteredEnrollments,
319: courseGrade, filteredGradesMap);
320: }
321:
322: public List getScoreRows() {
323: return scoreRows;
324: }
325:
326: public void setScoreRows(List scoreRows) {
327: this .scoreRows = scoreRows;
328: }
329:
330: public String getEventsLogType() {
331: return FacesUtil
332: .getLocalizedString("course_grade_details_log_type");
333: }
334:
335: // Sorting
336: public boolean isSortAscending() {
337: return getPreferencesBean()
338: .isCourseGradeDetailsTableSortAscending();
339: }
340:
341: public void setSortAscending(boolean sortAscending) {
342: getPreferencesBean().setCourseGradeDetailsTableSortAscending(
343: sortAscending);
344: }
345:
346: public String getSortColumn() {
347: return getPreferencesBean()
348: .getCourseGradeDetailsTableSortColumn();
349: }
350:
351: public void setSortColumn(String sortColumn) {
352: getPreferencesBean().setCourseGradeDetailsTableSortColumn(
353: sortColumn);
354: }
355:
356: public void setCourseGradesConverterPlugin(
357: String courseGradesConverterPlugin) {
358: this.courseGradesConverterPlugin = courseGradesConverterPlugin;
359: }
360: }
|