/**********************************************************************************
*
* $Id: AssignmentBean.java $
*
***********************************************************************************
*
* Copyright (c) 2005, 2006, 2007, 2008, 2009 The Sakai Foundation, The MIT Corporation
*
* Licensed under the Educational Community License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.opensource.org/licenses/ECL-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
**********************************************************************************/
package org.sakaiproject.tool.gradebook.ui;
import java.io.Serializable;
import java.math.BigDecimal;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
import javax.faces.application.FacesMessage;
import javax.faces.event.ValueChangeEvent;
import javax.faces.model.SelectItem;
import javax.faces.validator.ValidatorException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.sakaiproject.section.api.coursemanagement.EnrollmentRecord;
import org.sakaiproject.section.api.facade.Role;
import org.sakaiproject.service.gradebook.shared.ConflictingAssignmentNameException;
import org.sakaiproject.service.gradebook.shared.StaleObjectModificationException;
import org.sakaiproject.tool.cover.SessionManager;
import org.sakaiproject.tool.gradebook.Assignment;
import org.sakaiproject.tool.gradebook.Category;
import org.sakaiproject.tool.gradebook.Gradebook;
import org.sakaiproject.tool.gradebook.jsf.FacesUtil;
import org.sakaiproject.util.ResourceLoader;
import org.sakaiproject.service.gradebook.shared.MultipleAssignmentSavingException;
import org.sakaiproject.service.gradebook.shared.GradebookService;
public class AssignmentBean extends GradebookDependentBean implements Serializable {
private static final Log logger = LogFactory.getLog(AssignmentBean.class);
private Long assignmentId;
private Assignment assignment;
private List categoriesSelectList;
private String assignmentCategory;
// these 2 used to determine whether to zero-out the point value in applyPointsPossibleForDropScoreCategories
private boolean categoryChanged;
public boolean gradeEntryTypeChanged;
private Category selectedCategory;
private boolean selectedCategoryDropsScores;
private boolean selectedAssignmentIsOnlyOne;
private List<Category> categories;
// added to support bulk gradebook item creation
public List newBulkItems;
public int numTotalItems = 1;
public List addItemSelectList;
public String gradeEntryType;
public static final String UNASSIGNED_CATEGORY = "unassigned";
public static final String GB_ADJUSTMENT_ENTRY = "Adjustment";
private static final String GB_EDIT_ASSIGNMENT_PAGE = "editAssignment";
/**
* To add the proper number of blank gradebook item objects for bulk creation
*/
private static final int NUM_EXTRA_ASSIGNMENT_ENTRIES = 50;
protected void init() {
if (logger.isDebugEnabled()) logger.debug("init assignment=" + assignment);
if (assignment == null) {
if (assignmentId != null) {
assignment = getGradebookManager().getAssignment(assignmentId);
}
if (assignment == null) {
// it is a new assignment
assignment = new Assignment();
assignment.setReleased(true);
}
}
// initialization; shouldn't enter here after category drop down changes
if(selectedCategory == null && !getLocalizedString("cat_unassigned").equalsIgnoreCase(assignmentCategory)) {
Category assignCategory = assignment.getCategory();
if (assignCategory != null) {
assignmentCategory = assignCategory.getId().toString();
selectedCategoryDropsScores = assignCategory.isDropScores();
assignCategory.setAssignmentList(retrieveCategoryAssignmentList(assignCategory));
selectedAssignmentIsOnlyOne = isAssignmentTheOnlyOne(assignment, assignCategory);
selectedCategory = assignCategory;
}
else {
assignmentCategory = getLocalizedString("cat_unassigned");
}
}
categoriesSelectList = new ArrayList();
// The first choice is always "Unassigned"
categoriesSelectList.add(new SelectItem(UNASSIGNED_CATEGORY, FacesUtil.getLocalizedString("cat_unassigned")));
List gbCategories = getGradebookManager().getCategories(getGradebookId());
if (gbCategories != null && gbCategories.size() > 0)
{
Iterator catIter = gbCategories.iterator();
while (catIter.hasNext()) {
Category cat = (Category) catIter.next();
categoriesSelectList.add(new SelectItem(cat.getId().toString(), cat.getName()));
}
}
// To support bulk creation of assignments
if (newBulkItems == null) {
newBulkItems = new ArrayList();
}
// initialize the number of items to add dropdown
addItemSelectList = new ArrayList();
addItemSelectList.add(new SelectItem("0", ""));
for (int i = 1; i < NUM_EXTRA_ASSIGNMENT_ENTRIES; i++) {
addItemSelectList.add(new SelectItem(new Integer(i).toString(), new Integer(i).toString()));
}
if(newBulkItems.size() == NUM_EXTRA_ASSIGNMENT_ENTRIES) {
applyPointsPossibleForDropScoreCategories(newBulkItems);
} else {
for (int i = newBulkItems.size(); i < NUM_EXTRA_ASSIGNMENT_ENTRIES; i++) {
BulkAssignmentDecoratedBean item = getNewAssignment();
if (i == 0) {
item.setSaveThisItem("true");
}
newBulkItems.add(item);
}
}
}
private boolean isAssignmentTheOnlyOne(Assignment assignment, Category category){
if(assignment != null && category != null && category.getAssignmentList() != null){
if(category.getAssignmentList().size() == 1)
return ((Assignment)category.getAssignmentList().get(0)).getId().equals(assignment.getId());
else if(category.getAssignmentList().size() == 0)
return true;
else
return false;
}else{
return false;
}
}
/*
* sets pointsPossible for items in categories that drop scores
* and sets the assignment's category, so that the ui can read item.assignment.category.dropScores
*/
private void applyPointsPossibleForDropScoreCategories(List items) {
categories = getCategories();
Map<String, Category> categoryCache = new HashMap<String, Category>();
for(int i=0; i<items.size(); i++) {
BulkAssignmentDecoratedBean bulkAssignment = (BulkAssignmentDecoratedBean)items.get(i);
String assignmentCategory = bulkAssignment.getCategory();
if(getLocalizedString("cat_unassigned").equalsIgnoreCase(assignmentCategory)) {
Category unassigned = new Category();
bulkAssignment.getAssignment().setCategory(unassigned); // set this unassigned category, so that in the ui, item.assignment.category.dropScores will return false
if(categoryChanged || gradeEntryTypeChanged) {
//bulkAssignment.setPointsPossible(null);
bulkAssignment.getAssignment().setPointsPossible(null);
}
} else {
for(int j=0; j<categories.size(); j++) {
Category category = (Category)categories.get(j);
if(assignmentCategory.equals(category.getId().toString())) {
if(categoryCache.containsKey(category.getId().toString())){
category = categoryCache.get(category.getId().toString());
}else{
category = retrieveSelectedCategory(category.getId().toString(), true);
categoryCache.put(category.getId().toString(), category);
}
bulkAssignment.getAssignment().setCategory(category); // set here, because need to read item.assignment.category.dropScores in the ui
if(category.getAssignmentList() != null && category.getAssignmentList().size() > 0
&& category.isDropScores() && !GB_ADJUSTMENT_ENTRY.equals(bulkAssignment.getSelectedGradeEntryValue())) {
bulkAssignment.setPointsPossible(category.getItemValue().toString());
bulkAssignment.getAssignment().setPointsPossible(category.getItemValue());
} else if(categoryChanged || gradeEntryTypeChanged) {
if (category.isDropScores()) {
bulkAssignment.setPointsPossible(null);
}
bulkAssignment.getAssignment().setPointsPossible(null);
}
continue;
}
}
}
}
}
private Category getCategoryById(String categoryId) {
if(categoryId == null) {
return null;
}
Category category = null;
for(int i=0; i<categories.size(); i++) {
category = (Category)categories.get(i);
String id = category.getId().toString();
if(id != null && categoryId.trim().equals(id)) {
break;
}
}
return category;
}
private BulkAssignmentDecoratedBean getNewAssignment() {
Assignment assignment = new Assignment();
assignment.setReleased(true);
if(selectedCategory != null && selectedCategory.isDropScores()) {
assignment.setPointsPossible(selectedCategory.getItemValue());
}
BulkAssignmentDecoratedBean bulkAssignmentDecoBean = new BulkAssignmentDecoratedBean(assignment, getItemCategoryString(assignment));
return bulkAssignmentDecoBean;
}
private String getItemCategoryString(Assignment assignment) {
String assignmentCategory;
Category assignCategory = assignment.getCategory();
if (assignCategory != null) {
assignmentCategory = assignCategory.getId().toString();
}
else {
assignmentCategory = getLocalizedString("cat_unassigned");
}
return assignmentCategory;
}
/**
* Used to check if all gradebook items are valid before saving. Due to the way JSF works, had to turn off
* validators for bulk assignments so had to perform checks here.
* This is an all-or-nothing save, ie, either all items are OK and we save them all, or return to add page
* and highlight errors.
*/
public String saveNewAssignment() {
String resultString = "overview";
boolean saveAll = true;
// keep list of new assignment names just in case
// duplicates entered on screen
List newAssignmentNameList = new ArrayList();
// used to hold assignments that are OK since we
// need to determine if all are correct before saving
List itemsToSave = new ArrayList();
Iterator assignIter = newBulkItems.iterator();
int i = 0;
Map<String, Category> categoryCache = new HashMap<String, Category>();
while (i < numTotalItems && assignIter.hasNext()) {
BulkAssignmentDecoratedBean bulkAssignDecoBean = (BulkAssignmentDecoratedBean) assignIter.next();
if (bulkAssignDecoBean.getBlnSaveThisItem()) {
Assignment bulkAssignment = bulkAssignDecoBean.getAssignment();
// Check for blank entry else check if duplicate within items to be
// added or with item currently in gradebook.
if ("".equals(bulkAssignment.getName().toString().trim())) {
bulkAssignDecoBean.setBulkNoTitleError("blank");
saveAll = false;
resultString = "failure";
}
else if (newAssignmentNameList.contains(bulkAssignment.getName().trim()) ||
! getGradebookManager().checkValidName(getGradebookId(), bulkAssignment)){
bulkAssignDecoBean.setBulkNoTitleError("dup");
saveAll = false;
resultString = "failure";
}
else {
bulkAssignDecoBean.setBulkNoTitleError("OK");
newAssignmentNameList.add(bulkAssignment.getName().trim());
}
Category selectedCategory;
if(categoryCache.containsKey(bulkAssignDecoBean.getCategory())){
selectedCategory = categoryCache.get(bulkAssignDecoBean.getCategory());
}else{
selectedCategory = retrieveSelectedCategory(bulkAssignDecoBean.getCategory(), true);
categoryCache.put(bulkAssignDecoBean.getCategory(), selectedCategory);
}
boolean categoryDropsScores = false;
if(selectedCategory != null && selectedCategory.isDropScores()
&& selectedCategory.getAssignmentList() != null && selectedCategory.getAssignmentList().size() > 0 ) {
categoryDropsScores = true;
if(!GB_ADJUSTMENT_ENTRY.equals(bulkAssignDecoBean.getSelectedGradeEntryValue())) {
bulkAssignDecoBean.setPointsPossible(selectedCategory.getItemValue().toString()); // if category drops scores and is not adjustment, point value will come from the category level
}
}
// Check if points possible is blank else convert to double. Exception at else point
// means non-numeric value entered.
if (bulkAssignDecoBean.getPointsPossible() == null || ("".equals(bulkAssignDecoBean.getPointsPossible().trim()))) {
bulkAssignDecoBean.setBulkNoPointsError("blank");
saveAll = false;
resultString = "failure";
}
else {
try {
// Check if PointsPossible uses local number format
String strPointsPossible = bulkAssignDecoBean.getPointsPossible();
NumberFormat nf = NumberFormat.getInstance(new ResourceLoader().getLocale());
double dblPointsPossible = new Double (nf.parse(strPointsPossible).doubleValue());
// Added per SAK-13459: did not validate if point value was valid (> zero)
if (dblPointsPossible > 0) {
// No more than 2 decimal places can be entered.
BigDecimal bd = new BigDecimal(dblPointsPossible);
bd = bd.setScale(2, BigDecimal.ROUND_HALF_UP); // Two decimal places
double roundedVal = bd.doubleValue();
double diff = dblPointsPossible - roundedVal;
if(diff != 0) {
saveAll = false;
resultString = "failure";
bulkAssignDecoBean.setBulkNoPointsError("precision");
}
else {
bulkAssignDecoBean.setBulkNoPointsError("OK");
bulkAssignDecoBean.getAssignment().setPointsPossible(new Double(bulkAssignDecoBean.getPointsPossible()));
}
}
else {
saveAll = false;
resultString = "failure";
bulkAssignDecoBean.setBulkNoPointsError("invalid");
}
}
catch (Exception e) {
bulkAssignDecoBean.setBulkNoPointsError("NaN");
saveAll = false;
resultString = "failure";
}
}
if (saveAll) {
bulkAssignDecoBean.getAssignment().setCategory(retrieveSelectedCategory(bulkAssignDecoBean.getCategory(), false));
// if points possible is still 0 at this point, set it to null to avoid Division By Zero exceptions. These should never be allowed in the database.
if (null != bulkAssignDecoBean.getAssignment().getPointsPossible() && bulkAssignDecoBean.getAssignment().getPointsPossible()==0)
bulkAssignDecoBean.getAssignment().setPointsPossible(null);
itemsToSave.add(bulkAssignDecoBean.getAssignment());
}
// Even if errors increment since we need to go back to add page
i++;
}
}
// Now ready to save, the only problem is due to duplicate names.
if (saveAll) {
try {
getGradebookManager().createAssignments(getGradebookId(), itemsToSave);
String authzLevel = (getGradebookBean().getAuthzService().isUserAbleToGradeAll(getGradebookUid())) ?"instructor" : "TA";
for (Iterator gbItemIter = itemsToSave.iterator(); gbItemIter.hasNext();) {
String itemName = ((Assignment) gbItemIter.next()).getName();
FacesUtil.addRedirectSafeMessage(getLocalizedString("add_assignment_save",
new String[] {itemName}));
getGradebookBean().getEventTrackingService().postEvent("gradebook.newItem","/gradebook/"+getGradebookId()+"/"+itemName+"/"+authzLevel);
}
}
catch (MultipleAssignmentSavingException e) {
FacesUtil.addErrorMessage(FacesUtil.getLocalizedString("validation_messages_present"));
resultString = "failure";
}
}
else {
// There are errors so need to put an error message at top
FacesUtil.addErrorMessage(FacesUtil.getLocalizedString("validation_messages_present"));
}
return resultString;
}
public String updateAssignment() {
try {
Category category = retrieveSelectedCategory();
assignment.setCategory(category);
if(!GB_ADJUSTMENT_ENTRY.equals(assignment.getSelectedGradeEntryValue()) && category != null && category.isDropScores() && !isAssignmentTheOnlyOne(assignment, category)) {
assignment.setPointsPossible(category.getItemValue()); // if category drops scores, point value will come from the category level
}
Assignment originalAssignment = getGradebookManager().getAssignment(assignmentId);
Double origPointsPossible = originalAssignment.getPointsPossible();
Double newPointsPossible = assignment.getPointsPossible();
boolean scoresEnteredForAssignment = getGradebookManager().isEnteredAssignmentScores(assignmentId);
/* If grade entry by percentage or letter and the points possible has changed for this assignment,
* we need to convert all of the stored point values to retain the same value
*/
if ((getGradeEntryByPercent() || getGradeEntryByLetter()) && scoresEnteredForAssignment) {
if (!newPointsPossible.equals(origPointsPossible)) {
List enrollments = getSectionAwareness().getSiteMembersInRole(getGradebookUid(), Role.STUDENT);
List studentUids = new ArrayList();
for(Iterator iter = enrollments.iterator(); iter.hasNext();) {
studentUids.add(((EnrollmentRecord)iter.next()).getUser().getUserUid());
}
getGradebookManager().convertGradePointsForUpdatedTotalPoints(getGradebook(), originalAssignment, assignment.getPointsPossible(), studentUids);
}
}
getGradebookManager().updateAssignment(assignment);
long dueDateMillis = -1;
Date dueDate = assignment.getDueDate();
if (dueDate != null) dueDateMillis = dueDate.getTime();
getGradebookBean().getEventTrackingService().postEvent("gradebook.updateAssignment","/gradebook/"+getGradebookUid()+"/"+assignment.getName()+"/"+assignment.getPointsPossible()+"/"+dueDateMillis+"/"+assignment.isReleased()+"/"+assignment.isCounted()+"/"+getAuthzLevel());
if ((!origPointsPossible.equals(newPointsPossible)) && scoresEnteredForAssignment) {
if (getGradeEntryByPercent())
FacesUtil.addRedirectSafeMessage(getLocalizedString("edit_assignment_save_percentage", new String[] {assignment.getName()}));
else if (getGradeEntryByLetter())
FacesUtil.addRedirectSafeMessage(getLocalizedString("edit_assignment_save_converted", new String[] {assignment.getName()}));
else
FacesUtil.addRedirectSafeMessage(getLocalizedString("edit_assignment_save_scored", new String[] {assignment.getName()}));
} else {
FacesUtil.addRedirectSafeMessage(getLocalizedString("edit_assignment_save", new String[] {assignment.getName()}));
}
} catch (ConflictingAssignmentNameException e) {
logger.error(e);
FacesUtil.addErrorMessage(getLocalizedString("edit_assignment_name_conflict_failure"));
return "failure";
} catch (StaleObjectModificationException e) {
logger.error(e);
FacesUtil.addErrorMessage(getLocalizedString("edit_assignment_locking_failure"));
return "failure";
}
return navigateBack();
}
public String navigateToAssignmentDetails() {
return navigateBack();
}
/**
* Go to assignment details page. InstructorViewBean contains duplicate
* of this method, cannot migrate up to GradebookDependentBean since
* needs assignmentId, which is defined here.
*/
public String navigateBack() {
String breadcrumbPage = getBreadcrumbPage();
final Boolean middle = new Boolean((String) SessionManager.getCurrentToolSession().getAttribute("middle"));
if (breadcrumbPage == null || middle) {
AssignmentDetailsBean assignmentDetailsBean = (AssignmentDetailsBean)FacesUtil.resolveVariable("assignmentDetailsBean");
assignmentDetailsBean.setAssignmentId(assignmentId);
assignmentDetailsBean.setBreadcrumbPage(breadcrumbPage);
breadcrumbPage = "assignmentDetails";
}
// wherever we go, we're not editing, and middle section
// does not need to be shown.
setNav(null, "false", null, "false", null);
return breadcrumbPage;
}
/**
* View maintenance methods.
*/
public Long getAssignmentId() {
if (logger.isDebugEnabled()) logger.debug("getAssignmentId " + assignmentId);
return assignmentId;
}
public void setAssignmentId(Long assignmentId) {
if (logger.isDebugEnabled()) logger.debug("setAssignmentId " + assignmentId);
if (assignmentId != null) {
this.assignmentId = assignmentId;
}
}
public Assignment getAssignment() {
if (logger.isDebugEnabled()) logger.debug("getAssignment " + assignment);
if (assignment == null) {
if (assignmentId != null) {
assignment = getGradebookManager().getAssignment(assignmentId);
}
if (assignment == null) {
// it is a new assignment
assignment = new Assignment();
assignment.setReleased(true);
}
}
return assignment;
}
public List getCategoriesSelectList() {
return categoriesSelectList;
}
public List getAddItemSelectList() {
return addItemSelectList;
}
public String getAssignmentCategory() {
return assignmentCategory;
}
public void setAssignmentCategory(String assignmentCategory) {
this.assignmentCategory = assignmentCategory;
}
/**
* getNewBulkItems
*
* Generates and returns a List of blank Assignment objects.
* Used to support bulk gradebook item creation.
*/
public List getNewBulkItems() {
if (newBulkItems == null) {
newBulkItems = new ArrayList();
}
for (int i = newBulkItems.size(); i < NUM_EXTRA_ASSIGNMENT_ENTRIES; i++) {
newBulkItems.add(getNewAssignment());
}
return newBulkItems;
}
public void setNewBulkItems(List newBulkItems) {
this.newBulkItems = newBulkItems;
}
public List getCategories() {
if(categories == null) {
categories = getGradebookManager().getCategories(getGradebookId());
}
return categories;
}
public int getNumTotalItems() {
return numTotalItems;
}
public void setNumTotalItems(int numTotalItems) {
this.numTotalItems = numTotalItems;
}
public Gradebook getLocalGradebook()
{
return getGradebook();
}
/**
* Returns the Category associated with assignmentCategory
* If unassigned or not found, returns null
*
* added parameterized version to support bulk gradebook item creation
*/
private Category retrieveSelectedCategory()
{
return retrieveSelectedCategory(assignmentCategory, true);
}
private Category retrieveSelectedCategory(String assignmentCategory, boolean includeAssignments)
{
Long catId = null;
Category category = null;
if (assignmentCategory != null && !assignmentCategory.equals(UNASSIGNED_CATEGORY)) {
try {
catId = new Long(assignmentCategory);
}
catch (Exception e) {
catId = null;
}
if (catId != null)
{
// check to make sure there is a corresponding category
category = getGradebookManager().getCategory(catId);
if(includeAssignments){
//populate assignments list
category.setAssignmentList(retrieveCategoryAssignmentList(category));
}
}
}
return category;
}
private List retrieveCategoryAssignmentList(Category cat){
List assignmentsToUpdate = new ArrayList();
if(cat != null){
List assignments = cat.getAssignmentList();
if(cat.isDropScores() && (assignments == null || assignments.size() == 0)) { // don't populate, if assignments are already in category (to improve performance)
assignments = getGradebookManager().getAssignmentsForCategory(cat.getId());
// only include assignments which are not adjustments must not update adjustment item pointsPossible
for(Object o : assignments) {
if(o instanceof Assignment) {
Assignment assignment = (Assignment)o;
if(!Assignment.item_type_adjustment.equals(assignment.getItemType())) {
assignmentsToUpdate.add(assignment);
}
}
}
}
}
return assignmentsToUpdate;
}
public boolean isSelectedCategoryDropsScores() {
return selectedCategoryDropsScores;
}
public void setSelectedCategoryDropsScores(boolean selectedCategoryDropsScores) {
this.selectedCategoryDropsScores = selectedCategoryDropsScores;
}
public Category getSelectedCategory() {
return selectedCategory;
}
public void setSelectedCategory(Category selectedCategory) {
this.selectedCategory = selectedCategory;
}
public String processCategoryChangeInEditAssignment(ValueChangeEvent vce)
{
String changeCategory = (String) vce.getNewValue();
assignmentCategory = changeCategory;
if(vce.getOldValue() != null && vce.getNewValue() != null && !vce.getOldValue().equals(vce.getNewValue()))
{
if(changeCategory.equals(UNASSIGNED_CATEGORY)) {
selectedCategoryDropsScores = false;
selectedAssignmentIsOnlyOne = false;
selectedCategory = null;
assignmentCategory = getLocalizedString("cat_unassigned");
} else {
List<Category> categories = getGradebookManager().getCategories(getGradebookId());
if (categories != null && categories.size() > 0)
{
for (Category category : categories) {
if(changeCategory.equals(category.getId().toString())) {
selectedCategoryDropsScores = category.isDropScores();
category.setAssignmentList(retrieveCategoryAssignmentList(category));
selectedCategory = category;
selectedAssignmentIsOnlyOne = isAssignmentTheOnlyOne(assignment, selectedCategory);
assignmentCategory = category.getId().toString();
break;
}
}
}
}
}
return GB_EDIT_ASSIGNMENT_PAGE;
}
/**
* For bulk assignments, need to set the proper classes as a string
*/
public String getRowClasses()
{
StringBuffer rowClasses = new StringBuffer();
if (newBulkItems == null) {
newBulkItems = getNewBulkItems();
}
//if shown in UI, set class to 'bogus show' otherwise 'bogus hide'
for (int i=0; i< newBulkItems.size(); i++){
Object obj = newBulkItems.get(i);
if(obj instanceof BulkAssignmentDecoratedBean){
BulkAssignmentDecoratedBean assignment = (BulkAssignmentDecoratedBean) newBulkItems.get(i);
if (i != 0) rowClasses.append(",");
if (assignment.getBlnSaveThisItem() || i == 0) {
rowClasses.append("show bogus");
}
else {
rowClasses.append("hide bogus");
}
}
}
return rowClasses.toString();
}
public boolean isSelectedAssignmentIsOnlyOne() {
return selectedAssignmentIsOnlyOne;
}
public void setSelectedAssignmentIsOnlyOne(boolean selectedAssignmentIsOnlyOne) {
this.selectedAssignmentIsOnlyOne = selectedAssignmentIsOnlyOne;
}
}