org.dspace.app.xmlui.aspect.administrative.group.EditGroupForm.java Source code

Java tutorial

Introduction

Here is the source code for org.dspace.app.xmlui.aspect.administrative.group.EditGroupForm.java

Source

/**
 * The contents of this file are subject to the license and copyright
 * detailed in the LICENSE and NOTICE files at the root of the source
 * tree and available online at
 *
 * http://www.dspace.org/license/
 */
package org.dspace.app.xmlui.aspect.administrative.group;

import org.apache.commons.lang.StringUtils;
import org.dspace.app.xmlui.aspect.administrative.FlowGroupUtils;
import org.dspace.app.xmlui.cocoon.AbstractDSpaceTransformer;
import org.dspace.app.xmlui.wing.Message;
import org.dspace.app.xmlui.wing.WingException;
import org.dspace.app.xmlui.wing.element.*;
import org.dspace.authorize.factory.AuthorizeServiceFactory;
import org.dspace.authorize.service.AuthorizeService;
import org.dspace.content.Collection;
import org.dspace.content.Community;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.CollectionService;
import org.dspace.content.service.CommunityService;
import org.dspace.eperson.EPerson;
import org.dspace.eperson.Group;
import org.dspace.eperson.factory.EPersonServiceFactory;
import org.dspace.eperson.service.EPersonService;
import org.dspace.eperson.service.GroupService;

import java.sql.SQLException;
import java.util.*;
import java.util.List;

/**
 * Present the user with the group's current state. The user may select to
 * change the group's name, OR search for new epeople / groups to add, OR select
 * current group members for removal.
 *
 * @author Alexey Maslov
 * @author Scott Phillips
 * @author Oriol Oliv - DS-3205
 */
public class EditGroupForm extends AbstractDSpaceTransformer {
    /** Language Strings */
    private static final Message T_dspace_home = message("xmlui.general.dspace_home");

    private static final Message T_group_trail = message("xmlui.administrative.group.general.group_trail");

    private static final Message T_title = message("xmlui.administrative.group.EditGroupForm.title");

    private static final Message T_trail = message("xmlui.administrative.group.EditGroupForm.trail");

    private static final Message T_main_head = message("xmlui.administrative.group.EditGroupForm.main_head");

    private static final Message T_collection_para = message(
            "xmlui.administrative.group.EditGroupForm.collection_para");

    private static final Message T_community_para = message(
            "xmlui.administrative.group.EditGroupForm.community_para");

    private static final Message T_label_name = message("xmlui.administrative.group.EditGroupForm.label_name");

    private static final Message T_label_instructions = message(
            "xmlui.administrative.group.EditGroupForm.label_instructions");

    private static final Message T_label_search = message("xmlui.administrative.group.EditGroupForm.label_search");

    private static final Message T_submit_search_people = message(
            "xmlui.administrative.group.EditGroupForm.submit_search_people");

    private static final Message T_submit_search_groups = message(
            "xmlui.administrative.group.EditGroupForm.submit_search_groups");

    private static final Message T_no_results = message("xmlui.administrative.group.EditGroupForm.no_results");

    private static final Message T_main_head_new = message(
            "xmlui.administrative.group.EditGroupForm.main_head_new");

    private static final Message T_submit_clear = message("xmlui.administrative.group.EditGroupForm.submit_clear");

    private static final Message T_submit_save = message("xmlui.general.save");

    private static final Message T_submit_cancel = message("xmlui.general.cancel");

    private static final Message T_member = message("xmlui.administrative.group.EditGroupForm.member");

    private static final Message T_cycle = message("xmlui.administrative.group.EditGroupForm.cycle");

    private static final Message T_pending = message("xmlui.administrative.group.EditGroupForm.pending");

    private static final Message T_pending_warn = message("xmlui.administrative.group.EditGroupForm.pending_warn");

    private static final Message T_submit_add = message("xmlui.administrative.group.EditGroupForm.submit_add");

    private static final Message T_submit_remove = message(
            "xmlui.administrative.group.EditGroupForm.submit_remove");

    // EPeople Search
    private static final Message T_epeople_column1 = message(
            "xmlui.administrative.group.EditGroupForm.epeople_column1");

    private static final Message T_epeople_column2 = message(
            "xmlui.administrative.group.EditGroupForm.epeople_column2");

    private static final Message T_epeople_column3 = message(
            "xmlui.administrative.group.EditGroupForm.epeople_column3");

    private static final Message T_epeople_column4 = message(
            "xmlui.administrative.group.EditGroupForm.epeople_column4");

    // Group Search
    private static final Message T_groups_column1 = message(
            "xmlui.administrative.group.EditGroupForm.groups_column1");

    private static final Message T_groups_column2 = message(
            "xmlui.administrative.group.EditGroupForm.groups_column2");

    private static final Message T_groups_column3 = message(
            "xmlui.administrative.group.EditGroupForm.groups_column3");

    private static final Message T_groups_column4 = message(
            "xmlui.administrative.group.EditGroupForm.groups_column4");

    private static final Message T_groups_column5 = message(
            "xmlui.administrative.group.EditGroupForm.groups_column5");

    private static final Message T_groups_collection_link = message(
            "xmlui.administrative.group.ManageGroupsMain.groups_collection_link");

    // Members
    private static final Message T_members_head = message("xmlui.administrative.group.EditGroupForm.members_head");

    private static final Message T_members_column1 = message(
            "xmlui.administrative.group.EditGroupForm.members_column1");

    private static final Message T_members_column2 = message(
            "xmlui.administrative.group.EditGroupForm.members_column2");

    private static final Message T_members_column3 = message(
            "xmlui.administrative.group.EditGroupForm.members_column3");

    private static final Message T_members_column4 = message(
            "xmlui.administrative.group.EditGroupForm.members_column4");

    private static final Message T_members_group_name = message(
            "xmlui.administrative.group.EditGroupForm.members_group_name");

    private static final Message T_members_pending = message(
            "xmlui.administrative.group.EditGroupForm.members_pending");

    private static final Message T_members_none = message("xmlui.administrative.group.EditGroupForm.members_none");

    // How many results to show on a page.
    private static final int RESULTS_PER_PAGE = 5;

    /** The maximum size of a collection name allowed */
    private static final int MAX_COLLECTION_NAME = 25;

    protected AuthorizeService authorizeService = AuthorizeServiceFactory.getInstance().getAuthorizeService();
    protected EPersonService ePersonService = EPersonServiceFactory.getInstance().getEPersonService();
    protected GroupService groupService = EPersonServiceFactory.getInstance().getGroupService();
    protected CollectionService collectionService = ContentServiceFactory.getInstance().getCollectionService();
    protected CommunityService communityService = ContentServiceFactory.getInstance().getCommunityService();

    public void addPageMeta(PageMeta pageMeta) throws WingException {
        pageMeta.addMetadata("title").addContent(T_title);
        pageMeta.addTrailLink(contextPath + "/", T_dspace_home);
        pageMeta.addTrailLink(contextPath + "/admin/groups", T_group_trail);
        pageMeta.addTrail().addContent(T_trail);
    }

    public void addBody(Body body) throws WingException, SQLException {
        // Find the group in question
        UUID groupID = null;
        if (StringUtils.isNotBlank(parameters.getParameter("groupID", null))) {
            groupID = UUID.fromString(parameters.getParameter("groupID", null));
        }
        String currentName = decodeFromURL(parameters.getParameter("groupName", null));
        if (currentName == null || currentName.length() == 0) {
            currentName = FlowGroupUtils.getName(context, groupID);
        }

        Group group = null;
        if (groupID != null) {
            group = groupService.find(context, groupID);
        }

        // Find the collection or community if applicable
        Collection collection = null;
        Community community = null;
        if (group != null) {
            UUID collectionID = FlowGroupUtils.getCollectionId(context, group.getName());
            if (collectionID != null) {
                collection = collectionService.find(context, collectionID);
            } else {
                UUID communityID = FlowGroupUtils.getCommunityId(context, group.getName());
                if (communityID != null) {
                    community = communityService.find(context, communityID);
                }
            }
        }

        // Get list of member groups
        String memberGroupIDsString = parameters.getParameter("memberGroupIDs", null);
        List<UUID> memberGroupIDs = new ArrayList<UUID>();
        if (memberGroupIDsString != null) {
            for (String id : memberGroupIDsString.split(",")) {
                if (id.length() > 0) {
                    memberGroupIDs.add(UUID.fromString(id));
                }
            }
        }

        // Get list of member epeople
        String memberEPeopleIDsString = parameters.getParameter("memberEPeopleIDs", null);
        List<UUID> memberEPeopleIDs = new ArrayList<UUID>();
        if (memberEPeopleIDsString != null) {
            for (String id : memberEPeopleIDsString.split(",")) {
                if (id.length() > 0) {
                    memberEPeopleIDs.add(UUID.fromString(id));
                }
            }
        }

        // Get highlight parameters
        String highlightEPersonID = parameters.getParameter("highlightEPersonID", null);
        String highlightGroupID = parameters.getParameter("highlightGroupID", null);

        // Get search parameters
        String query = decodeFromURL(parameters.getParameter("query", null));
        int page = parameters.getParameterAsInteger("page", 0);
        String type = parameters.getParameter("type", null);

        // Get any errors
        String errorString = parameters.getParameter("errors", null);
        List<String> errors = new ArrayList<String>();
        if (errorString != null) {
            for (String error : errorString.split(",")) {
                errors.add(error);
            }
        }

        //DIVISION: group-edit
        Division main = body.addInteractiveDivision("group-edit", contextPath + "/admin/groups",
                Division.METHOD_POST, "primary administrative groups");
        if (group == null) {
            main.setHead(T_main_head_new);
        } else {
            main.setHead(T_main_head.parameterize(group.getName(), groupID));
        }

        if (collection != null) {
            Para para = main.addPara();
            para.addContent(T_collection_para);
            para.addXref(contextPath + "/handle/" + collection.getHandle(),
                    collectionService.getMetadata(collection, "name"));
        } else if (community != null) {
            Para para = main.addPara();
            para.addContent(T_community_para);
            para.addXref(contextPath + "/handle/" + community.getHandle(),
                    communityService.getMetadata(community, "name"));
        }

        // DIVISION: group-actions
        Division actions = main.addDivision("group-edit-actions");
        Para groupName = actions.addPara();
        groupName.addContent(T_label_name);
        Text groupText = groupName.addText("group_name");
        groupText.setValue(currentName);
        if (collection != null || community != null) {
            // If this group is associated with a collection or community then it is special,
            // thus they shouldn't be able to update it.
            groupText.setDisabled();
            groupText.setHelp(T_label_instructions);
        } else if (errors.contains("group_name") || errors.contains("group_name_duplicate")) {
            groupText.addError("");
        }

        Para searchBoxes = actions.addPara();
        searchBoxes.addContent(T_label_search);
        Text queryField = searchBoxes.addText("query");
        queryField.setValue(query);
        queryField.setSize(15);
        searchBoxes.addButton("submit_search_epeople").setValue(T_submit_search_people);
        searchBoxes.addButton("submit_search_groups").setValue(T_submit_search_groups);

        if (query != null) {
            if ("eperson".equals(type)) {
                searchBoxes.addButton("submit_clear").setValue(T_submit_clear);
                addEPeopleSearch(main, query, page, group, memberEPeopleIDs);
            } else if ("group".equals(type)) {
                searchBoxes.addButton("submit_clear").setValue(T_submit_clear);
                addGroupSearch(main, group, query, page, group, memberGroupIDs);
            }
        }

        boolean changes = false;
        if (group != null) {
            changes = addMemberList(main, group, memberGroupIDs, memberEPeopleIDs, highlightEPersonID,
                    highlightGroupID);
        }

        Para buttons = main.addPara();
        buttons.addButton("submit_save").setValue(T_submit_save);
        buttons.addButton("submit_cancel").setValue(T_submit_cancel);

        if (changes) {
            main.addPara().addHighlight("warn").addContent(T_pending_warn);
        }

        main.addHidden("administrative-continue").setValue(knot.getId());
    }

    /**
     * Search for epeople to add to this group.
     */
    private void addEPeopleSearch(Division div, String query, int page, Group group, List<UUID> memberEPeopleIDs)
            throws SQLException, WingException {
        int resultCount = ePersonService.searchResultCount(context, query);
        java.util.List<EPerson> epeople = ePersonService.search(context, query, page * RESULTS_PER_PAGE,
                RESULTS_PER_PAGE);

        Division results = div.addDivision("results");

        if (resultCount > RESULTS_PER_PAGE) {
            // If there are enough results then paginate the results
            String baseURL = contextPath + "/admin/groups?administrative-continue=" + knot.getId();
            int firstIndex = page * RESULTS_PER_PAGE + 1;
            int lastIndex = page * RESULTS_PER_PAGE + epeople.size();

            String nextURL = null, prevURL = null;
            if (page < (resultCount / RESULTS_PER_PAGE)) {
                nextURL = baseURL + "&page=" + (page + 1);
            }
            if (page > 0) {
                prevURL = baseURL + "&page=" + (page - 1);
            }

            results.setSimplePagination(resultCount, firstIndex, lastIndex, prevURL, nextURL);
        }

        /* Set up a table with search results (if there are any). */
        Table table = results.addTable("group-edit-search-eperson", epeople.size() + 1, 1);
        Row header = table.addRow(Row.ROLE_HEADER);
        header.addCell().addContent(T_epeople_column1);
        header.addCell().addContent(T_epeople_column2);
        header.addCell().addContent(T_epeople_column3);
        header.addCell().addContent(T_epeople_column4);

        for (EPerson person : epeople) {
            String epersonID = String.valueOf(person.getID());
            String fullName = person.getFullName();
            String email = person.getEmail();
            String url = contextPath + "/admin/epeople?administrative-continue=" + knot.getId()
                    + "&submit_edit_eperson&epersonID=" + epersonID;

            Row personData = table.addRow();

            personData.addCell().addContent(person.getID().toString());
            personData.addCell().addXref(url, fullName);
            personData.addCell().addXref(url, email);

            // check if they are already a member of the group
            if (memberEPeopleIDs.contains(person.getID())) {
                // Check if they really members or just pending members
                if (group != null && groupService.isDirectMember(group, person)) {
                    personData.addCellContent(T_member);
                } else {
                    personData.addCell().addHighlight("warn").addContent(T_pending);
                }
            } else {
                personData.addCell().addButton("submit_add_eperson_" + epersonID).setValue(T_submit_add);
            }
        }

        if (epeople.size() <= 0) {
            table.addRow().addCell(1, 4).addContent(T_no_results);
        }
    }

    /**
     * Search for groups to add to this group.
     */
    private void addGroupSearch(Division div, Group sourceGroup, String query, int page, Group parent,
            List<UUID> memberGroupIDs) throws WingException, SQLException {
        int resultCount = groupService.searchResultCount(context, query);
        java.util.List<Group> groups = groupService.search(context, query, page * RESULTS_PER_PAGE,
                RESULTS_PER_PAGE);

        Division results = div.addDivision("results");

        if (resultCount > RESULTS_PER_PAGE) {
            // If there are enough results then paginate the results
            String baseURL = contextPath + "/admin/groups?administrative-continue=" + knot.getId();
            int firstIndex = page * RESULTS_PER_PAGE + 1;
            int lastIndex = page * RESULTS_PER_PAGE + groups.size();

            String nextURL = null, prevURL = null;
            if (page < (resultCount / RESULTS_PER_PAGE)) {
                nextURL = baseURL + "&page=" + (page + 1);
            }
            if (page > 0) {
                prevURL = baseURL + "&page=" + (page - 1);
            }

            results.setSimplePagination(resultCount, firstIndex, lastIndex, prevURL, nextURL);
        }

        // DS-3205 fix
        //        Table table = results.addTable("roup-edit-search-group",groups.size() + 1, 1);
        Table table = results.addTable("group-edit-search-group", groups.size() + 1, 1);
        Row header = table.addRow(Row.ROLE_HEADER);
        header.addCell().addContent(T_groups_column1);
        header.addCell().addContent(T_groups_column2);
        header.addCell().addContent(T_groups_column3);
        header.addCell().addContent(T_groups_column4);
        header.addCell().addContent(T_groups_column5);

        for (Group group : groups) {
            String groupID = String.valueOf(group.getID());
            String name = group.getName();
            String url = contextPath + "/admin/groups?administrative-continue=" + knot.getId()
                    + "&submit_edit_group&groupID=" + groupID;
            int memberCount = group.getMembers().size() + group.getMemberGroups().size();

            Row row = table.addRow();

            row.addCell().addContent(groupID);
            if (authorizeService.isAdmin(context))
            // Only administrators can edit other groups.
            {
                row.addCell().addXref(url, name);
            } else {
                row.addCell().addContent(name);
            }

            row.addCell().addContent(memberCount == 0 ? "-" : String.valueOf(memberCount));

            Cell cell = row.addCell();
            if (FlowGroupUtils.getCollectionId(context, group.getName()) != null) {
                Collection collection = collectionService.find(context,
                        FlowGroupUtils.getCollectionId(context, group.getName()));
                if (collection != null) {
                    String collectionName = collectionService.getMetadata(collection, "name");

                    if (collectionName == null) {
                        collectionName = "";
                    } else if (collectionName.length() > MAX_COLLECTION_NAME) {
                        collectionName = collectionName.substring(0, MAX_COLLECTION_NAME - 3) + "...";
                    }

                    cell.addContent(collectionName + " ");

                    Highlight highlight = cell.addHighlight("fade");
                    highlight.addContent("[");
                    highlight.addXref(contextPath + "/handle/" + collection.getHandle(), T_groups_collection_link);
                    highlight.addContent("]");
                }
            }

            // Check if the group is already a member or would create a cycle.
            if (memberGroupIDs.contains(group.getID())) {
                // Check if they really members or just pending members
                if (parent != null && groupService.isMember(parent, group)) {
                    row.addCellContent(T_member);
                } else {
                    row.addCell().addHighlight("warn").addContent(T_pending);
                }
            } else if (isDescendant(sourceGroup, group, memberGroupIDs)) {
                row.addCellContent(T_cycle);
            } else {
                row.addCell().addButton("submit_add_group_" + groupID).setValue(T_submit_add);
            }

        }
        if (groups.size() <= 0) {
            table.addRow().addCell(1, 4).addContent(T_no_results);
        }
    }

    /**
     * Method to extensively check whether the first group has the second group as a distant
     * parent. This is used to avoid creating cycles like A->B, B->C, C->D, D->A which leads
     * all the groups involved to essentially include themselves.
     */
    private boolean isDescendant(Group descendant, Group ancestor, List<UUID> memberGroupIDs) throws SQLException {
        Queue<Group> toVisit = new LinkedList<Group>();
        Group currentGroup;

        toVisit.offer(ancestor);

        // Initialize by adding a list of our current list of group members.
        for (UUID groupid : memberGroupIDs) {
            Group member = groupService.find(context, groupid);
            toVisit.offer(member);
        }

        while (!toVisit.isEmpty()) {
            // 1. Grab a group from the queue
            currentGroup = toVisit.poll();

            // 2. See if it's the descendant we're looking for
            if (currentGroup.equals(descendant)) {
                return true;
            }

            // 3. If not, add that group's children to the queue
            for (Group nextBatch : currentGroup.getMemberGroups()) {
                toVisit.offer(nextBatch);
            }
        }
        return false;
    }

    /**
     * Add a table with all the current group's members to the specified division.
     * @throws SQLException
     */
    private boolean addMemberList(Division div, Group parent, List<UUID> memberGroupIDs,
            List<UUID> memberEPeopleIDs, String highlightEPersonID, String highlightGroupID)
            throws WingException, SQLException {
        // Flag to remember if there are any pending changes.
        boolean changes = false;

        Division members = div.addDivision("group-edit-members");
        members.setHead(T_members_head);

        Table table = members.addTable("group-edit-members-table",
                memberGroupIDs.size() + memberEPeopleIDs.size() + 1, 4);

        Row header = table.addRow(Row.ROLE_HEADER);
        header.addCell().addContent(T_members_column1);
        header.addCell().addContent(T_members_column2);
        header.addCell().addContent(T_members_column3);
        header.addCell().addContent(T_members_column4);

        // get all group members, pend or actual
        @SuppressWarnings("unchecked") // the cast is correct
        List<UUID> allMemberGroupIDs = new ArrayList<UUID>(memberGroupIDs);
        for (Group group : parent.getMemberGroups()) {
            if (!allMemberGroupIDs.contains(group.getID())) {
                allMemberGroupIDs.add(group.getID());
            }
        }
        // Sort them to a consistent ordering
        Collections.sort(allMemberGroupIDs);

        // Loop through all group ids and display them.
        for (UUID groupID : allMemberGroupIDs) {
            Group group = groupService.find(context, groupID);
            boolean highlight = (group.getID().toString().equals(highlightGroupID));
            boolean pendingAddition = !groupService.isMember(parent, group);
            boolean pendingRemoval = !memberGroupIDs.contains(groupID);
            addMemberRow(table, group, highlight, pendingAddition, pendingRemoval);

            if (pendingAddition || pendingRemoval) {
                changes = true;
            }
        }

        // get all members, pend or actual
        @SuppressWarnings("unchecked") // the cast is correct
        List<UUID> allMemberEPeopleIDs = new ArrayList<UUID>(memberEPeopleIDs);
        for (EPerson eperson : parent.getMembers()) {
            if (!allMemberEPeopleIDs.contains(eperson.getID())) {
                allMemberEPeopleIDs.add(eperson.getID());
            }
        }
        // Sort them to a consistent ordering
        Collections.sort(allMemberEPeopleIDs);

        for (UUID epersonID : allMemberEPeopleIDs) {
            EPerson eperson = ePersonService.find(context, epersonID);
            boolean highlight = (eperson.getID().toString().equals(highlightEPersonID));
            boolean pendingAddition = !groupService.isDirectMember(parent, eperson);
            boolean pendingRemoval = !memberEPeopleIDs.contains(epersonID);
            addMemberRow(table, eperson, highlight, pendingAddition, pendingRemoval);

            if (pendingAddition || pendingRemoval) {
                changes = true;
            }
        }

        if (allMemberGroupIDs.size() <= 0 && allMemberEPeopleIDs.size() <= 0) {
            table.addRow().addCell(1, 4).addContent(T_members_none);
        }

        return changes;
    }

    /**
     * Add a single member row for groups.
     *
     * @param table The table to add the row too.
     * @param group The group being displayed in this row.
     * @param highlight Should the row be highlighted.
     * @param pendingAddition Is this group pending addition
     * @param pendingRemoval Is this group pending removal
     */
    private void addMemberRow(Table table, Group group, boolean highlight, boolean pendingAddition,
            boolean pendingRemoval) throws WingException, SQLException {
        String name = group.getName();
        String url = contextPath + "/admin/groups?administrative-continue=" + knot.getId()
                + "&submit_edit_group&groupID=" + group.getID();

        Row groupData = table.addRow(null, null, highlight ? "highlight" : null);

        groupData.addCell().addHighlight("bold").addContent(group.getID().toString());

        // Mark if this member is pending or not.
        Cell nameCell = groupData.addCell();
        if (authorizeService.isAdmin(context)) {
            nameCell.addHighlight("bold").addXref(url, T_members_group_name.parameterize(name));
        } else {
            nameCell.addHighlight("bold").addContent(T_members_group_name.parameterize(name));
        }

        if (pendingAddition) {
            nameCell.addContent(" ");
            nameCell.addHighlight("warn").addContent(T_members_pending);
        }

        groupData.addCell().addContent("-");

        if (pendingRemoval) {
            groupData.addCell().addHighlight("warn").addContent(T_pending);
        } else {
            groupData.addCell().addButton("submit_remove_group_" + group.getID()).setValue(T_submit_remove);
        }
    }

    /**
     * Add a single member row for epeople.
     *
     * @param table The table to add a row too.
     * @param eperson The eperson being displayed
     * @param highlight Should this eperson be highlighted?
     * @param pendingAddition Is this eperson pending addition?
     * @param pendingRemoval Is this eperson pending removal?
     */
    private void addMemberRow(Table table, EPerson eperson, boolean highlight, boolean pendingAddition,
            boolean pendingRemoval) throws WingException, SQLException {
        String fullName = eperson.getFullName();
        String email = eperson.getEmail();
        String url = contextPath + "/admin/epeople?administrative-continue=" + knot.getId()
                + "&submit_edit_eperson&epersonID=" + eperson.getID();

        Row personData = table.addRow(null, null, highlight ? "highlight" : null);

        personData.addCell().addContent(eperson.getID().toString());

        Cell nameCell = personData.addCell();
        nameCell.addXref(url, fullName);
        if (pendingAddition) {
            nameCell.addContent(" ");
            nameCell.addHighlight("warn").addContent(T_members_pending);
        }

        personData.addCell().addXref(url, email);

        if (pendingRemoval) {
            personData.addCell().addHighlight("warn").addContent(T_pending);
        } else {
            personData.addCell().addButton("submit_remove_eperson_" + eperson.getID()).setValue(T_submit_remove);
        }
    }
}