001: /*******************************************************************************
002: * Copyright (c) 2006 The Regents of the University of California
003: *
004: * Licensed under the Educational Community License, Version 1.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.opensource.org/licenses/ecl1.php
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: ******************************************************************************/package org.sakaiproject.tool.gradebook.ui;
016:
017: import java.io.Serializable;
018: import java.math.BigDecimal;
019: import java.util.ArrayList;
020: import java.util.Collections;
021: import java.util.Comparator;
022: import java.util.HashMap;
023: import java.util.Iterator;
024: import java.util.List;
025: import java.util.Map;
026:
027: import org.apache.commons.logging.Log;
028: import org.apache.commons.logging.LogFactory;
029: import org.sakaiproject.service.gradebook.shared.UnknownUserException;
030: import org.sakaiproject.tool.gradebook.Assignment;
031: import org.sakaiproject.tool.gradebook.AssignmentGradeRecord;
032: import org.sakaiproject.tool.gradebook.Comment;
033: import org.sakaiproject.tool.gradebook.CourseGradeRecord;
034: import org.sakaiproject.tool.gradebook.Gradebook;
035:
036: /**
037: * Provides data for the student view of the gradebook.
038: *
039: * @author <a href="mailto:jholtzman@berkeley.edu">Josh Holtzman</a>
040: */
041: public class StudentViewBean extends GradebookDependentBean implements
042: Serializable {
043: private static Log logger = LogFactory
044: .getLog(StudentViewBean.class);
045:
046: // View maintenance fields - serializable.
047: private String userDisplayName;
048: private Double percent;
049: private boolean courseGradeReleased;
050: private String courseGrade;
051: private boolean assignmentsReleased;
052: private boolean anyNotCounted;
053:
054: private boolean sortAscending;
055: private String sortColumn;
056:
057: private StringBuffer rowStyles;
058: private Map commentMap;
059:
060: // Controller fields - transient.
061: private transient List assignmentGradeRows;
062:
063: private static final Map columnSortMap;
064: private static final String SORT_BY_NAME = "name";
065: private static final String SORT_BY_DATE = "dueDate";
066: private static final String SORT_BY_POINTS_POSSIBLE = "pointsPossible";
067: private static final String SORT_BY_POINTS_EARNED = "pointsEarned";
068: private static final String SORT_BY_GRADE = "grade";
069: public static Comparator nameComparator;
070: public static Comparator dateComparator;
071: public static Comparator pointsPossibleComparator;
072: public static Comparator pointsEarnedComparator;
073: public static Comparator gradeAsPercentageComparator;
074: private static Comparator doubleOrNothingComparator;
075: static {
076: nameComparator = new Comparator() {
077: public int compare(Object o1, Object o2) {
078: return Assignment.nameComparator.compare(
079: ((AssignmentGradeRow) o1).getAssignment(),
080: ((AssignmentGradeRow) o2).getAssignment());
081: }
082: };
083: dateComparator = new Comparator() {
084: public int compare(Object o1, Object o2) {
085: return Assignment.dateComparator.compare(
086: ((AssignmentGradeRow) o1).getAssignment(),
087: ((AssignmentGradeRow) o2).getAssignment());
088: }
089: };
090: pointsPossibleComparator = new Comparator() {
091: public int compare(Object o1, Object o2) {
092: return Assignment.pointsComparator.compare(
093: ((AssignmentGradeRow) o1).getAssignment(),
094: ((AssignmentGradeRow) o2).getAssignment());
095: }
096: };
097:
098: doubleOrNothingComparator = new Comparator() {
099: public int compare(Object o1, Object o2) {
100: Double double1 = (Double) o1;
101: Double double2 = (Double) o2;
102:
103: if (double1 == null && double2 == null) {
104: return 0;
105: } else if (double1 == null && double2 != null) {
106: return -1;
107: } else if (double1 != null && double2 == null) {
108: return 1;
109: } else {
110: return double1.compareTo(double2);
111: }
112: }
113: };
114:
115: pointsEarnedComparator = new Comparator() {
116: public int compare(Object o1, Object o2) {
117: int comp = doubleOrNothingComparator.compare(
118: ((AssignmentGradeRow) o1).getPointsEarned(),
119: ((AssignmentGradeRow) o2).getPointsEarned());
120: if (comp == 0) {
121: return nameComparator.compare(o1, o2);
122: } else {
123: return comp;
124: }
125: }
126: };
127: gradeAsPercentageComparator = new Comparator() {
128: public int compare(Object o1, Object o2) {
129: int comp = doubleOrNothingComparator.compare(
130: ((AssignmentGradeRow) o1)
131: .getGradeAsPercentage(),
132: ((AssignmentGradeRow) o2)
133: .getGradeAsPercentage());
134: if (comp == 0) {
135: return nameComparator.compare(o1, o2);
136: } else {
137: return comp;
138: }
139: }
140: };
141:
142: columnSortMap = new HashMap();
143: columnSortMap.put(SORT_BY_NAME, StudentViewBean.nameComparator);
144: columnSortMap.put(SORT_BY_DATE, StudentViewBean.dateComparator);
145: columnSortMap.put(SORT_BY_POINTS_POSSIBLE,
146: StudentViewBean.pointsPossibleComparator);
147: columnSortMap.put(SORT_BY_POINTS_EARNED,
148: StudentViewBean.pointsEarnedComparator);
149: columnSortMap.put(SORT_BY_GRADE,
150: StudentViewBean.gradeAsPercentageComparator);
151: }
152:
153: /**
154: * Since this bean does not use the session-scoped preferences bean to keep
155: * sort preferences, we need to define the defaults locally.
156: */
157: public StudentViewBean() {
158: sortAscending = true;
159: sortColumn = SORT_BY_DATE;
160: }
161:
162: public class AssignmentGradeRow implements Serializable {
163: private Assignment assignment;
164: private AssignmentGradeRecord gradeRecord;
165: private List comments;
166:
167: public AssignmentGradeRow(Assignment assignment) {
168: this .assignment = assignment;
169: this .comments = new ArrayList();
170: }
171:
172: public void setGradeRecord(AssignmentGradeRecord gradeRecord) {
173: this .gradeRecord = gradeRecord;
174: }
175:
176: public Assignment getAssignment() {
177: return assignment;
178: }
179:
180: public AssignmentGradeRecord getGradeRecord() {
181: return gradeRecord;
182: }
183:
184: Double getPointsEarned() {
185: if (gradeRecord == null) {
186: return null;
187: } else {
188: return gradeRecord.getPointsEarned();
189: }
190: }
191:
192: Double getGradeAsPercentage() {
193: if (gradeRecord == null) {
194: return null;
195: } else {
196: return gradeRecord.getGradeAsPercentage();
197: }
198: }
199:
200: public List getComments() {
201: return comments;
202: }
203:
204: public void setComments(List comments) {
205: this .comments = comments;
206: }
207:
208: }
209:
210: /**
211: * @see org.sakaiproject.tool.gradebook.ui.InitializableBean#init()
212: */
213: public void init() {
214: // Get the active gradebook
215: Gradebook gradebook = getGradebook();
216:
217: // Set the display name
218: try {
219: userDisplayName = getUserDirectoryService()
220: .getUserDisplayName(getUserUid());
221: } catch (UnknownUserException e) {
222: if (logger.isErrorEnabled())
223: logger
224: .error("User "
225: + getUserUid()
226: + " is unknown but logged in as student in gradebook "
227: + gradebook.getUid());
228: userDisplayName = "";
229: }
230: courseGradeReleased = gradebook.isCourseGradeDisplayed();
231: assignmentsReleased = gradebook.isAssignmentsDisplayed();
232:
233: // Reset the row styles
234: rowStyles = new StringBuffer();
235:
236: // Display course grade if we've been instructed to.
237: if (gradebook.isCourseGradeDisplayed()) {
238: CourseGradeRecord gradeRecord = getGradebookManager()
239: .getStudentCourseGradeRecord(gradebook,
240: getUserUid());
241: if (gradeRecord != null) {
242: courseGrade = gradeRecord.getDisplayGrade();
243: // Note that the percentage will be null for a manual-only grade
244: // code (such as "I" for incomplete).
245: percent = gradeRecord.getGradeAsPercentage();
246: }
247: }
248: //get grade comments and load them into a map assignmentId->comment
249: commentMap = new HashMap();
250: List assignmentComments = getGradebookManager()
251: .getStudentAssignmentComments(getUserUid(),
252: getGradebookId());
253: logger.debug("number of comments " + assignmentComments.size());
254: Iterator iteration = assignmentComments.iterator();
255: while (iteration.hasNext()) {
256: Comment comment = (Comment) iteration.next();
257: commentMap
258: .put(comment.getGradableObject().getId(), comment);
259: }
260:
261: // Don't display any assignments if they have not been released
262: if (!gradebook.isAssignmentsDisplayed()) {
263: assignmentGradeRows = new ArrayList();
264: } else {
265: List assignments = getGradebookManager().getAssignments(
266: gradebook.getId());
267: if (logger.isDebugEnabled())
268: logger.debug(assignments.size() + " total assignments");
269: List gradeRecords = getGradebookManager()
270: .getStudentGradeRecords(gradebook.getId(),
271: getUserUid());
272: if (logger.isDebugEnabled())
273: logger.debug(gradeRecords.size() + " grade records");
274:
275: // Create a map of assignments to assignment grade rows
276: Map asnMap = new HashMap();
277: for (Iterator iter = assignments.iterator(); iter.hasNext();) {
278:
279: Assignment asn = (Assignment) iter.next();
280: asnMap.put(asn, new AssignmentGradeRow(asn));
281:
282: if (asn.isNotCounted()) {
283: anyNotCounted = true;
284: }
285:
286: }
287:
288: for (Iterator iter = gradeRecords.iterator(); iter
289: .hasNext();) {
290: AssignmentGradeRecord asnGr = (AssignmentGradeRecord) iter
291: .next();
292: if (logger.isDebugEnabled())
293: logger.debug("Adding " + asnGr.getPointsEarned()
294: + " to totalPointsEarned");
295: // Update the AssignmentGradeRow in the map
296: AssignmentGradeRow asnGradeRow = (AssignmentGradeRow) asnMap
297: .get(asnGr.getAssignment());
298: asnGradeRow.setGradeRecord(asnGr);
299:
300: }
301:
302: //iterate through the assignments and update the comments
303: Iterator assignmentIterator = assignments.iterator();
304: while (assignmentIterator.hasNext()) {
305: Assignment assignment = (Assignment) assignmentIterator
306: .next();
307: AssignmentGradeRow asnGradeRow = (AssignmentGradeRow) asnMap
308: .get(assignment);
309: try {
310: Comment comment = (Comment) commentMap
311: .get(asnGradeRow.getAssignment().getId());
312: if (comment.getCommentText().length() > 0)
313: asnGradeRow.getComments().add(comment);
314: } catch (NullPointerException npe) {
315: if (logger.isDebugEnabled())
316: logger
317: .debug("assignment has no associated comment");
318: }
319: }
320:
321: assignmentGradeRows = new ArrayList(asnMap.values());
322:
323: //remove assignments that are not released
324: Iterator i = assignmentGradeRows.iterator();
325: while (i.hasNext()) {
326: AssignmentGradeRow assignmentGradeRow = (AssignmentGradeRow) i
327: .next();
328: if (!(assignmentGradeRow.getAssignment().isReleased()))
329: i.remove();
330: }
331:
332: Collections.sort(assignmentGradeRows,
333: (Comparator) columnSortMap.get(sortColumn));
334: if (!sortAscending) {
335: Collections.reverse(assignmentGradeRows);
336: }
337:
338: // Set the row css classes
339: for (Iterator iter = assignmentGradeRows.iterator(); iter
340: .hasNext();) {
341: AssignmentGradeRow gr = (AssignmentGradeRow) iter
342: .next();
343: if (gr.getAssignment().isExternallyMaintained()) {
344: rowStyles.append("external");
345: } else {
346: rowStyles.append("internal");
347: }
348: if (iter.hasNext()) {
349: rowStyles.append(",");
350: }
351: }
352: }
353: }
354:
355: /**
356: * @return Returns the assignmentGradeRows.
357: */
358: public List getAssignmentGradeRows() {
359: return assignmentGradeRows;
360: }
361:
362: /**
363: * @return Returns the courseGrade.
364: */
365: public String getCourseGrade() {
366: return courseGrade;
367: }
368:
369: /**
370: * @return Returns the courseGradeReleased.
371: */
372: public boolean isCourseGradeReleased() {
373: return courseGradeReleased;
374: }
375:
376: public boolean isCourseGradePercentageShown() {
377: return courseGradeReleased && (percent != null);
378: }
379:
380: public boolean isAssignmentsReleased() {
381: return assignmentsReleased;
382: }
383:
384: /**
385: * @return Returns the percent.
386: */
387: public Double getPercent() {
388: if (percent == null) {
389: return null;
390: }
391: double pct = 0;
392: BigDecimal bd = new BigDecimal(percent);
393: bd = bd.setScale(2, BigDecimal.ROUND_DOWN);
394: pct = bd.doubleValue();
395: return pct;
396: }
397:
398: /**
399: * @return Returns the userDisplayName.
400: */
401: public String getUserDisplayName() {
402: return userDisplayName;
403: }
404:
405: // Delegated sort methods
406: public String getAssignmentSortColumn() {
407: return getPreferencesBean().getAssignmentSortColumn();
408: }
409:
410: public void setAssignmentSortColumn(String assignmentSortColumn) {
411: getPreferencesBean().setAssignmentSortColumn(
412: assignmentSortColumn);
413: }
414:
415: public boolean isAssignmentSortAscending() {
416: return getPreferencesBean().isAssignmentSortAscending();
417: }
418:
419: public void setAssignmentSortAscending(boolean sortAscending) {
420: getPreferencesBean().setAssignmentSortAscending(sortAscending);
421: }
422:
423: // Sorting
424: public boolean isSortAscending() {
425: return sortAscending;
426: }
427:
428: public void setSortAscending(boolean sortAscending) {
429: this .sortAscending = sortAscending;
430: }
431:
432: public String getSortColumn() {
433: return sortColumn;
434: }
435:
436: public void setSortColumn(String sortColumn) {
437: this .sortColumn = sortColumn;
438: }
439:
440: /**
441: * @return The comma-separated list of css styles to use in displaying the rows
442: */
443: public String getRowStyles() {
444: if (rowStyles == null) {
445: return null;
446: } else {
447: return rowStyles.toString();
448: }
449: }
450:
451: /**
452: * @return True if the gradebook contains any assignments not counted toward
453: * the final course grade.
454: */
455: public boolean isAnyNotCounted() {
456: return anyNotCounted;
457: }
458: }
|