private void makeViewByGroupFilter(
      UIContainer tofill, ViewSubmissionsViewParams params, Assignment2 assignment) {
    List<Group> viewableGroups = permissionLogic.getViewableGroupsForAssignment(null, assignment);
    if (viewableGroups != null && !viewableGroups.isEmpty()) {
      UIForm groupFilterForm = UIForm.make(tofill, "group_filter_form", params);

      // we need to order the groups alphabetically. Group names are unique
      // per site, so let's make a map
      Map<String, String> groupNameToIdMap = new HashMap<String, String>();
      for (Group group : viewableGroups) {
        groupNameToIdMap.put(group.getTitle(), group.getId());
      }

      List<String> orderedGroupNames = new ArrayList<String>(groupNameToIdMap.keySet());
      Collections.sort(
          orderedGroupNames,
          new Comparator<String>() {
            public int compare(String groupName1, String groupName2) {
              return groupName1.compareToIgnoreCase(groupName2);
            }
          });

      String selectedValue = "";
      if (params.groupId != null && params.groupId.trim().length() > 0) {
        selectedValue = params.groupId;
      }

      int numItemsInDropDown = viewableGroups.size();
      boolean showAllOption = false;

      // if the assignment is restricted to one group, we won't add the "Show All" option
      if (assignment.getAssignmentGroupSet() == null
          || assignment.getAssignmentGroupSet().size() != 1) {
        // if there is more than one viewable group or the user has grade all perm, add the
        // "All Sections/Groups option"
        if (viewableGroups.size() > 1
            || permissionLogic.isUserAllowedToManageAllSubmissions(
                null, assignment.getContextId())) {
          showAllOption = true;
          numItemsInDropDown++;
        }
      }

      // Group Ids
      String[] view_filter_values = new String[numItemsInDropDown];
      // Group Names
      String[] view_filter_options = new String[numItemsInDropDown];

      int index = 0;

      // the first entry is "All Sections/Groups"
      if (showAllOption) {
        view_filter_values[index] = "";
        view_filter_options[index] =
            messageLocator.getMessage("assignment2.assignment_grade.filter.all_sections");
        index++;
      }

      for (String groupName : orderedGroupNames) {
        view_filter_values[index] = groupNameToIdMap.get(groupName);
        view_filter_options[index] = groupName;
        index++;
      }

      UISelect.make(
          groupFilterForm,
          "group_filter",
          view_filter_values,
          view_filter_options,
          "groupId",
          selectedValue);
    }
  }
  public void fillComponents(
      UIContainer tofill, ViewParameters viewparams, ComponentChecker checker) {
    ViewSubmissionsViewParams params = (ViewSubmissionsViewParams) viewparams;
    // make sure that we have an AssignmentID to work with
    if (params.assignmentId == null) {
      // ERROR SHOULD BE SET, OTHERWISE TAKE BACK TO ASSIGNMENT_LIST
      messages.addMessage(new TargettedMessage("GeneralActionError"));
      return;
    }
    assignmentId = params.assignmentId;
    Assignment2 assignment = assignmentLogic.getAssignmentByIdWithAssociatedData(assignmentId);

    String currUserId = externalLogic.getCurrentUserId();

    boolean contentReviewEnabled =
        assignment.isContentReviewEnabled()
            && contentReviewLogic.isContentReviewAvailable(assignment.getContextId());

    // let's double check that none of the associated groups were deleted from the site
    boolean displayGroupDeletionWarning = false;
    if (assignment.getAssignmentGroupSet() != null
        && !assignment.getAssignmentGroupSet().isEmpty()) {
      Collection<Group> siteGroups = externalLogic.getSiteGroups(assignment.getContextId());
      List<String> groupIds = new ArrayList<String>();
      if (siteGroups != null) {
        for (Group group : siteGroups) {
          groupIds.add(group.getId());
        }
      }

      for (AssignmentGroup assignGroup : assignment.getAssignmentGroupSet()) {
        if (!groupIds.contains(assignGroup.getGroupId())) {
          displayGroupDeletionWarning = true;
          break;
        }
      }
    }

    if (displayGroupDeletionWarning) {
      UIOutput.make(
          tofill,
          "deleted_group",
          messageLocator.getMessage("assignment2.assignment_grade-assignment.group_deleted"));
    }

    // Edit Permission
    boolean userMayEditAssign =
        permissionLogic.isUserAllowedToEditAssignment(currUserId, assignment);
    boolean userMayManageSubmissions =
        permissionLogic.isUserAllowedToManageSubmissionsForAssignment(currUserId, assignment);

    // get parameters
    if (params.sort_by == null) params.sort_by = DEFAULT_SORT_BY;
    if (params.sort_dir == null) params.sort_dir = DEFAULT_SORT_DIR;

    UIVerbatim.make(
        tofill, "defaultSortBy", HTMLUtil.emitJavascriptVar("defaultSortBy", DEFAULT_SORT_BY));

    // we need to retrieve the history for the release/retract feedback logic
    List<AssignmentSubmission> submissions =
        submissionLogic.getViewableSubmissionsWithHistoryForAssignmentId(
            assignmentId, params.groupId);
    List<String> studentIdList = new ArrayList<String>();
    if (submissions != null) {
      for (AssignmentSubmission submission : submissions) {
        studentIdList.add(submission.getUserId());
      }
    }

    // The following is some code to populate the sort order/page size, if
    // it's already been put in session state by the entity provider.
    Long pagesize = null;
    String orderBy = null;
    Boolean ascending = null;
    ToolSession toolSession = sessionManager.getCurrentToolSession();
    if (toolSession.getAttribute(Assignment2SubmissionEntityProvider.SUBMISSIONVIEW_SESSION_ATTR)
        != null) {
      Map attr =
          (Map)
              toolSession.getAttribute(
                  Assignment2SubmissionEntityProvider.SUBMISSIONVIEW_SESSION_ATTR);
      if (attr.containsKey(
          Assignment2SubmissionEntityProvider.SUBMISSIONVIEW_SESSION_ATTR_PAGE_SIZE)) {
        pagesize =
            (Long)
                attr.get(Assignment2SubmissionEntityProvider.SUBMISSIONVIEW_SESSION_ATTR_PAGE_SIZE);
      }
      if (attr.containsKey(
          Assignment2SubmissionEntityProvider.SUBMISSIONVIEW_SESSION_ATTR_ORDER_BY)) {
        orderBy =
            (String)
                attr.get(Assignment2SubmissionEntityProvider.SUBMISSIONVIEW_SESSION_ATTR_ORDER_BY);
      }
      if (attr.containsKey(
          Assignment2SubmissionEntityProvider.SUBMISSIONVIEW_SESSION_ATTR_ASCENDING)) {
        ascending =
            (Boolean)
                attr.get(Assignment2SubmissionEntityProvider.SUBMISSIONVIEW_SESSION_ATTR_ASCENDING);
      }
    }

    // if assign is graded, retrieve the gb details, if appropriate
    GradebookItem gbItem = null;
    boolean gbItemExists = false;
    boolean gradesReleased = false;
    // user may view the associated gradebook item
    boolean userMayViewGbItem = false;
    // user has grading privileges for this gb item
    boolean userMayGrade = false;
    boolean userMayReleaseGrades = false;

    if (assignment.isGraded() && assignment.getGradebookItemId() != null) {
      userMayViewGbItem =
          gradebookLogic.isCurrentUserAbleToViewGradebookItem(
              assignment.getContextId(), assignment.getGradebookItemId());

      if (userMayViewGbItem) {
        // user may grade if there is at least one gradable student among the submissions
        List<String> gradableStudents =
            gradebookLogic.getFilteredStudentsForGradebookItem(
                currUserId,
                assignment.getContextId(),
                assignment.getGradebookItemId(),
                AssignmentConstants.GRADE,
                studentIdList);
        userMayGrade = gradableStudents != null && !gradableStudents.isEmpty();
        userMayReleaseGrades = gradebookLogic.isCurrentUserAbleToEdit(assignment.getContextId());

        try {
          gbItem =
              gradebookLogic.getGradebookItemById(
                  assignment.getContextId(), assignment.getGradebookItemId());
          gbItemExists = true;
          gradesReleased = gbItem.isReleased();
        } catch (GradebookItemNotFoundException ginfe) {
          if (log.isDebugEnabled())
            log.debug("Gb item with id: " + assignment.getGradebookItemId() + " no longer exists!");
          gbItem = null;
        }
      }
    }

    // if user has grading privileges but item no longer exists, display warning
    // to user
    if (assignment.isGraded() && userMayViewGbItem && !gbItemExists) {
      UIOutput.make(
          tofill,
          "no_gb_item",
          messageLocator.getMessage("assignment2.assignment_grade-assignment.gb_item_deleted"));
    }

    // We need to check if it's a non electronic submission.  If it is, we don't want to have
    // the submitted columns appear (Submitted and Submission Status).
    // We pass in the boolean parameter nonElectronicSubmission to viewSubmission.js (specifically
    // snn2subview.init()),
    // where logic is there to use this parameter.
    boolean nonElectronicSubmission = false;

    if (assignment.getSubmissionType() == AssignmentConstants.SUBMIT_NON_ELECTRONIC) {
      nonElectronicSubmission = true;
    }

    UIInitBlock.make(
        tofill,
        "asnn2subview-init",
        "asnn2subview.init",
        new Object[] {
          assignmentId,
          externalLogic.getCurrentContextId(),
          placement.getId(),
          submissions.size(),
          assignment.isGraded(),
          contentReviewEnabled,
          nonElectronicSubmission,
          pagesize,
          orderBy,
          ascending,
          gradesReleased,
          params.pageIndex
        });

    // Breadcrumbs
    UIInternalLink.make(
        tofill,
        "breadcrumb",
        messageLocator.getMessage("assignment2.assignment_list-sortview.heading"),
        new SimpleViewParameters(ListProducer.VIEW_ID));
    UIMessage.make(
        tofill,
        "last_breadcrumb",
        "assignment2.assignment_grade-assignment.heading",
        new Object[] {assignment.getTitle()});

    // ACTION BAR
    boolean displayReleaseGrades = false;
    boolean displayReleaseFB = false;
    boolean displayDownloadAll = false;
    boolean displayUploadAll = false;

    if (userMayEditAssign || userMayManageSubmissions) {
      UIOutput.make(tofill, "navIntraTool");
    }

    // RELEASE GRADES
    // don't display this option if the gb item doesn't exist anymore
    if (userMayReleaseGrades && assignment.isGraded() && gbItemExists) {
      displayReleaseGrades = true;

      // determine if grades have been released yet
      String releaseLinkText =
          messageLocator.getMessage("assignment2.assignment_grade-assignment.grades.release");
      if (gradesReleased) {
        releaseLinkText =
            messageLocator.getMessage("assignment2.assignment_grade-assignment.grades.retract");
      }

      UIForm releaseGradesForm = UIForm.make(tofill, "release_grades_form");
      UICommand releaseGradesButton = UICommand.make(releaseGradesForm, "release_grades");

      UIOutput.make(tofill, "release_grades_li");
      UIInternalLink releaseGradesLink =
          UIInternalLink.make(tofill, "release_grades_link", releaseLinkText, viewparams);
      Map<String, String> idmap = new HashMap<String, String>();
      idmap.put(
          "onclick",
          "asnn2.releaseGradesDialog('"
              + releaseGradesButton.getFullID()
              + "', '"
              + assignment.getContextId()
              + "', '"
              + assignment.getGradebookItemId()
              + "', '"
              + !gradesReleased
              + "'); return false;");
      releaseGradesLink.decorate(new UIFreeAttributeDecorator(idmap));

      makeReleaseGradesDialog(gradesReleased, assignment, tofill);
    }

    // RELEASE FEEDBACK
    if (userMayManageSubmissions) {
      displayReleaseFB = true;
      makeReleaseFeedbackLink(tofill, params, submissions);
    }

    // DOWNLOAD ALL
    if (userMayManageSubmissions) {
      displayDownloadAll = true;

      ZipViewParams zvp = new ZipViewParams("zipSubmissions", assignmentId);
      UIInternalLink.make(
          tofill,
          "downloadall",
          UIMessage.make("assignment2.assignment_grade-assignment.downloadall.button"),
          zvp);
    }

    // UPLOAD GRADES & FEEDBACK
    if (userMayManageSubmissions) {
      displayUploadAll = true;

      AssignmentViewParams avp = new AssignmentViewParams("uploadall", assignmentId);
      if (assignment.isGraded() && gbItemExists && userMayGrade) {
        UIInternalLink.make(
            tofill,
            "uploadall",
            UIMessage.make("assignment2.uploadall.breadcrumb.upload.graded"),
            avp);
      } else {
        UIInternalLink.make(
            tofill,
            "uploadall",
            UIMessage.make("assignment2.uploadall.breadcrumb.upload.ungraded"),
            avp);
      }
    }

    // handle those pesky separators
    if (displayReleaseGrades && (displayReleaseFB || displayUploadAll || displayDownloadAll)) {
      UIOutput.make(tofill, "release_grades_sep");
    }

    if (displayReleaseFB && (displayUploadAll || displayDownloadAll)) {
      UIOutput.make(tofill, "release_feedback_sep");
    }

    if (displayDownloadAll && displayUploadAll) {
      UIOutput.make(tofill, "downloadall_sep");
    }

    UIMessage.make(tofill, "page-title", "assignment2.assignment_grade-assignment.title");

    // now make the "View By Sections/Groups" filter
    makeViewByGroupFilter(tofill, params, assignment);

    /*
     * Form for assigning a grade to all submissions without a grade.
     * Do not allow grading if gbItem is null - it must have been deleted
     */
    if (submissions != null
        && !submissions.isEmpty()
        && userMayGrade
        && assignment.isGraded()
        && gbItemExists) {
      createApplyToUngradedWidget(assignment, tofill, params, "unassigned-apply-form0:");
      createApplyToUngradedWidget(assignment, tofill, params, "unassigned-apply-form1:");
    }

    // Confirmation Dialogs
    // These are only added here for internationalization. They are not part
    // of a real form.
    UICommand.make(
        tofill,
        "release-feedback-confirm",
        UIMessage.make("assignment2.dialogs.release_all_feedback.confirm"));
    UICommand.make(
        tofill,
        "release-feedback-cancel",
        UIMessage.make("assignment2.dialogs.release_all_feedback.cancel"));

    UICommand.make(
        tofill,
        "retract-feedback-confirm",
        UIMessage.make("assignment2.dialogs.retract_all_feedback.confirm"));
    UICommand.make(
        tofill,
        "retract-feedback-cancel",
        UIMessage.make("assignment2.dialogs.retract_all_feedback.cancel"));
  }