# UsersView.java

    /*
    ** Module   : UsersView.java
    ** Abstract : UsersView is a view to manage user accounts.
    **
    ** Copyright (c) 2017, Golden Code Development Corporation.
    **
    ** -#- -I- --Date-- ----------------Description----------------------
    ** 001 SBI 20170601 Created initial version.
    */
    /*
    ** This program is free software: you can redistribute it and/or modify
    ** it under the terms of the GNU Affero General Public License as
    ** published by the Free Software Foundation, either version 3 of the
    ** License, or (at your option) any later version.
    **
    ** This program is distributed in the hope that it will be useful,
    ** but WITHOUT ANY WARRANTY; without even the implied warranty of
    ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    ** GNU Affero General Public License for more details.
    **
    ** You may find a copy of the GNU Affero GPL version 3 at the following
    ** location: https://www.gnu.org/licenses/agpl-3.0.en.html
    **
    ** Additional terms under GNU Affero GPL version 3 section 7:
    **
    **   Under Section 7 of the GNU Affero GPL version 3, the following additional
    **   terms apply to the works covered under the License.  These additional terms
    **   are non-permissive additional terms allowed under Section 7 of the GNU
    **   Affero GPL version 3 and may not be removed by you.
    **
    **   0. Attribution Requirement.
    **
    **     You must preserve all legal notices or author attributions in the covered
    **     work or Appropriate Legal Notices displayed by works containing the covered
    **     work.  You may not remove from the covered work any author or developer
    **     credit already included within the covered work.
    **
    **   1. No License To Use Trademarks.
    **
    **     This license does not grant any license or rights to use the trademarks
    **     Golden Code, FWD, any Golden Code or FWD logo, or any other trademarks
    **     of Golden Code Development Corporation. You are not authorized to use the
    **     name Golden Code, FWD, or the names of any author or contributor, for
    **     publicity purposes without written authorization.
    **
    **   2. No Misrepresentation of Affiliation.
    **
    **     You may not represent yourself as Golden Code Development Corporation or FWD.
    **
    **     You may not represent yourself for publicity purposes as associated with
    **     Golden Code Development Corporation, FWD, or any author or contributor to
    **     the covered work, without written authorization.
    **
    **   3. No Misrepresentation of Source or Origin.
    **
    **     You may not represent the covered work as solely your work.  All modified
    **     versions of the covered work must be marked in a reasonable way to make it
    **     clear that the modified work is not originating from Golden Code Development
    **     Corporation or FWD.  All modified versions must contain the notices of
    **     attribution required in this license.
    */

    package com.goldencode.p2j.admin.client.application.home.accounts.users;

    import java.util.Arrays;
    import java.util.EnumMap;
    import java.util.List;
    import java.util.Set;

    import com.google.gwt.user.client.ui.*;

    import org.gwtbootstrap3.client.ui.Button;
    import org.gwtbootstrap3.client.ui.TextBox;
    import org.gwtbootstrap3.client.ui.gwt.DataGrid;

    import com.goldencode.p2j.admin.TaggedName;
    import com.goldencode.p2j.admin.client.NameTokens;
    import com.goldencode.p2j.admin.client.application.home.BaseViewWithUiHandlers;
    import com.goldencode.p2j.admin.client.widget.GridHandle;
    import com.goldencode.p2j.admin.client.widget.GridHelper;
    import com.goldencode.p2j.admin.shared.PaperFormat;
    import com.goldencode.p2j.admin.shared.PaperOrientation;
    import com.goldencode.p2j.admin.shared.ReportParameters;
    import com.goldencode.p2j.admin.shared.Reports;
    import com.google.gwt.core.client.Scheduler;
    import com.google.gwt.core.client.Scheduler.ScheduledCommand;
    import com.google.gwt.dom.client.Style.Unit;
    import com.google.gwt.event.dom.client.ClickEvent;
    import com.google.gwt.regexp.shared.RegExp;
    import com.google.gwt.uibinder.client.UiBinder;
    import com.google.gwt.uibinder.client.UiField;
    import com.google.gwt.uibinder.client.UiHandler;
    import com.google.gwt.view.client.ListDataProvider;
    import com.google.gwt.view.client.MultiSelectionModel;
    import com.google.gwt.view.client.SelectionChangeEvent;
    import com.google.inject.Inject;

    /**
     * UsersView is a view to manage user accounts.
     */
    public class UsersView
    extends BaseViewWithUiHandlers<UsersUIHandlers>
    implements UsersPresenter.MyView
    {
       /**
        * GWT UI creator.
        */
       interface Binder
       extends UiBinder<Widget, UsersView>
       {}

       /** The Refresh button */
       @UiField
       Button refresh;

       /** The Add User button */
       @UiField
       Button addUserAccount;

       /** The Delete User button */
       @UiField
       Button deleteUserAccount;

       /** The Clone User button */
       @UiField
       Button cloneUserAccount;

       /** The Edit User button */
       @UiField
       Button editUserAccount;

       /** The Disable/Enable User button */
       @UiField
       Button disableUserAccount;

       /** The Find User button */
       @UiField
       Button findUser;

       /** The Switch to ACLs button */
       @UiField
       Button switchToACLs;

       /** The Delete Group button */
       @UiField
       Button deleteGroup;

       /** The Assign New Group button */
       @UiField
       Button assignNewGroup;

       /** The New Group button */
       @UiField
       TextBox newGroup;

       /** The Populate all groups button */
       @UiField
       Button populateGroups;

       /** The Add Selected button */
       @UiField
       Button addSelected;

       /** The filter text box to select groups according to the given criteria */
       @UiField
       TextBox filterSelector;

       /** The Filter groups button */
       @UiField
       Button filterGroups;

       /** The all users table view */
       @UiField(provided = true)
       DataGrid<TaggedName> usersGrid = GridHelper.create();

       /** The user's assigned groups table view */
       @UiField(provided = true)
       DataGrid<TaggedName> userGroupsGrid = GridHelper.create();

       /** The all existing groups table view */
       @UiField(provided = true)
       DataGrid<TaggedName> allGroupsGrid = GridHelper.create();

       /** The modal container */
       @UiField
       HasWidgets modalFragment;

       /** The parent container for the Add/Edit User Definition view */
       @UiField
       FlowPanel userDefModal;

       /** The column names for the all users table. */
       private final String[] usersColumnNames = { "User ID", "Person", "OS User ID" };

       /** The column names for the user's groups and all groups tables */
       private final String[] userGroupsColumnNames = { "Group ID", "Description" };

       /** The all users grid handle */
       private final GridHandle<TaggedName> usersGridHandle;

       /** The all users data provider */
       private final ListDataProvider<TaggedName> usersProvider;

       /** The all users selection model */
       private final MultiSelectionModel<TaggedName> usersSelectionModel;

       /** The user's assigned groups grid handle */
       private final GridHandle<TaggedName> userGroupsGridHandle;

       /** The user's assigned groups data provider */
       private final ListDataProvider<TaggedName> userGroupsProvider;

       /** The user's assigned groups selection model */
       private final MultiSelectionModel<TaggedName> userGroupsSelectionModel;

       /** The all groups grid handle */
       private final GridHandle<TaggedName> allGroupsGridHandle;

       /** The all groups data provider */
       private final ListDataProvider<TaggedName> allGroupsProvider;

       /** The all groups selection model */
       private final MultiSelectionModel<TaggedName> allGroupsSelectionModel;

       /** The Clone User Account View */
       private final DeletingUsersAlert deletingUsersAlert;

       /** The  */
       private final CloneUserAccountView cloneUserAccountView;

       /** The Removing Groups Alert */
       private final RemovingGroupsAlert removingGroupsAlert;

       /**
        * Constructs this view, used by MPV gwtplatform of ArcBees Inc.
        *
        * @param    binder
        *           UI creator
        * @param    deletingUsersAlert
        *           Deleting user alert child view
        * @param    cloneUserAccountView
        *           Clone user account child view
        * @param    removingGroupsAlert
        *           Removing groups alert child view
        */
       @Inject
       public UsersView(Binder binder,
                        DeletingUsersAlert deletingUsersAlert,
                        CloneUserAccountView cloneUserAccountView,
                        RemovingGroupsAlert removingGroupsAlert)
       {
          initWidget(binder.createAndBindUi(this));

          this.deletingUsersAlert = deletingUsersAlert;
          this.cloneUserAccountView = cloneUserAccountView;
          this.removingGroupsAlert = removingGroupsAlert;

          this.usersGridHandle = initTable(usersGrid, usersColumnNames, true, true);
          this.usersProvider = this.usersGridHandle.getDataProvider();
          this.usersSelectionModel = (MultiSelectionModel<TaggedName>)this.usersGridHandle.getSelectionModel();
          this.usersSelectionModel.addSelectionChangeHandler(new SelectionChangeEvent.Handler()
          {
             @Override
             public void onSelectionChange(SelectionChangeEvent event)
             {
                Set<TaggedName> selected = UsersView.this.usersSelectionModel.getSelectedSet();
                logger.info("usersSelectionModel: onSelectionChange: " + Arrays.toString(selected.stream().map(tn -> tn.getName()).toArray()));
                if (selected.size() != 1)
                {
                   UsersView.this.userGroupsSelectionModel.clear();
                }
                UsersView.this.getUiHandlers().onUserSelected(selected);
             }
          });

          this.userGroupsGridHandle = initTable(userGroupsGrid, userGroupsColumnNames, true, true);
          this.userGroupsProvider = this.userGroupsGridHandle.getDataProvider();
          this.userGroupsSelectionModel = (MultiSelectionModel<TaggedName>)this.userGroupsGridHandle.getSelectionModel();
          this.userGroupsSelectionModel.addSelectionChangeHandler(new SelectionChangeEvent.Handler()
          {
             @Override
             public void onSelectionChange(SelectionChangeEvent event)
             {
                Set<TaggedName> selected = UsersView.this.userGroupsSelectionModel.getSelectedSet();
                logger.info("userGroupsSelectionModel: onSelectionChange: " + Arrays.toString(selected.stream().map(tn -> tn.getName()).toArray()));
                UsersView.this.getUiHandlers().onGroupSelected(selected);
             }
          });

          this.allGroupsGridHandle = initTable(allGroupsGrid, userGroupsColumnNames, true, true);
          this.allGroupsProvider = this.allGroupsGridHandle.getDataProvider();
          this.allGroupsSelectionModel = (MultiSelectionModel<TaggedName>)this.allGroupsGridHandle.getSelectionModel();
          this.allGroupsSelectionModel.addSelectionChangeHandler(new SelectionChangeEvent.Handler()
          {
             @Override
             public void onSelectionChange(SelectionChangeEvent event)
             {
                if (UsersView.this.usersSelectionModel.getSelectedSet().size() == 1)
                {
                   Set<TaggedName> selected = UsersView.this.allGroupsSelectionModel.getSelectedSet();
                   List<TaggedName> userGroups = UsersView.this.userGroupsProvider.getList();
                   userGroups.forEach(group -> UsersView.this.allGroupsSelectionModel.setSelected(group, true));

                   UsersView.this.addSelected.setEnabled(!userGroups.containsAll(selected));
                }
                else
                {
                   UsersView.this.allGroupsSelectionModel.clear();
                }
             }
          });

          ((com.google.gwt.user.cellview.client.DataGrid<TaggedName>) usersGrid).setMinimumTableWidth(300, Unit.PX);
          setupModalSlot(UsersPresenter.MODAL_CONTENT, modalFragment);
          addDialog(deletingUsersAlert);
          addDialog(cloneUserAccountView);
          addDialog(removingGroupsAlert);
       }

       /**
        * Setups the given table view.
        *
        * @param    grid
        *           The given table view
        * @param    columnNames
        *           The column names
        * @param    multiSelection
        *           The true value indicates that the multiple rows selection is supported, otherwise
        *           the single selection is supported only.
        * @param    sortable
        *           The true value indicates that the table columns supports changing their sort order
        *           from descending to ascending and vice versa.
        *
        * @return   The grid handle
        */
       private GridHandle<TaggedName> initTable(DataGrid<TaggedName> grid,
                                                String[] columnNames,
                                                boolean multiSelection,
                                                boolean sortable)
       {
    //      grid.setSelectionModel(selectionModel);
    //      grid.setKeyboardSelectionPolicy(KeyboardSelectionPolicy.ENABLED);
    //      grid.setKeyboardPagingPolicy(KeyboardPagingPolicy.CURRENT_PAGE);
    //
    //      grid.addCellPreviewHandler(new CellPreviewEvent.Handler<TaggedName>()
    //      {
    //         @Override
    //         public void onCellPreview(CellPreviewEvent<TaggedName> event)
    //         {
    //            NativeEvent nevt = event.getNativeEvent();
    //
    //            int keyCode = nevt.getKeyCode();
    //             if (keyCode == KeyCodes.KEY_UP     || keyCode == KeyCodes.KEY_DOWN ||
    //                 keyCode == KeyCodes.KEY_LEFT   || keyCode == KeyCodes.KEY_RIGHT ||
    //                 keyCode == KeyCodes.KEY_PAGEUP || keyCode == KeyCodes.KEY_PAGEDOWN)
    //             {
    //                int rowIndex = grid.getKeyboardSelectedRow();
    //                TaggedName row = dataProvider.getList().get(rowIndex);
    //                selectionModel.setSelected(row, true);
    //             }
    //         }});
          //noinspection NonJREEmulationClassesInClientCode
          GridHelper.ColumnInfo<TaggedName> col1 = new GridHelper.ColumnInfo<TaggedName>(
                   columnNames[0],
                   (tn) -> tn.getName(),
                   (sortable) ? (tn1, tn2) -> tn1.getName().compareTo(tn2.getName()) : null
                   );
          //noinspection NonJREEmulationClassesInClientCode
          GridHelper.ColumnInfo<TaggedName> col2 = new GridHelper.ColumnInfo<TaggedName>(
             columnNames[1],
             (tn) -> tn.getTag(),
             (sortable) ? (tn1, tn2) -> tn1.getTag().compareTo(tn2.getTag()) : null
          );
          //noinspection NonJREEmulationClassesInClientCode
          GridHelper.ColumnInfo<TaggedName> col3 = new GridHelper.ColumnInfo<TaggedName>(
             columnNames[2],
             (tn) -> tn.get(2),
             (sortable) ? (tn1, tn2) -> tn1.getTag().compareTo(tn2.get(2)) : null
          );

          return GridHelper.initListGrid(grid, multiSelection, sortable, col1, col2, col3);
       }

       private void updateDataProvider(DataGrid<TaggedName> grid,
                                       ListDataProvider<TaggedName> dataProvider,
                                       TaggedName[] records)
       {
          GridHelper.updateDataProvider(grid, dataProvider, records);
       }

       /**
        * Setups the table data provider.
        *
        * @param    dataGrid
        *           The given table view
        * @param    dataProvider
        *           The given table data provider
        * @param    records
        *           The data
        * @param    filterExp
        *           The regular expression to select data satisfying the provided criteria
        */
       private void updateDataProvider(DataGrid<TaggedName> dataGrid,
                                       ListDataProvider<TaggedName> dataProvider,
                                       TaggedName[] records,
                                       RegExp filterExp)
       {
          dataProvider.getList().clear();

          if (records == null)
          {
             return;
          }

          GridHelper.updateDataProvider(dataGrid, dataProvider, records, filterExp);
       }

       /**
        * Sets the all users table's model with users accounts data given by tagged names
        *
        * @param    users
        *           The array of users accounts given by tagged names
        */
       @Override
       public void setUsers(TaggedName[] users)
       {
          logger.info("setGroups " + users);
          usersSelectionModel.clear();
          updateDataProvider(usersGrid, usersProvider, users);
       }

       /**
        * The Refresh button click handler.
        *
        * @param    e
        *           Click event
        */
       @UiHandler("refresh")
       void onRefresh(ClickEvent e)
       {
          getUiHandlers().onRefresh();
       }

       /**
        * The Add User button click handler.
        *
        * @param    e
        *           Click event
        */
       @UiHandler("addUserAccount")
       void onAddUserAccount(ClickEvent e)
       {
          logger.info("onAddUserAccount");
          getUiHandlers().showAddUserAccountDialog();
       }

       /**
        * The Clone User button click handler.
        *
        * @param    e
        *           Click event
        */
       @UiHandler("cloneUserAccount")
       void onCloneUserAccount(ClickEvent e)
       {
          TaggedName[] users = UsersView.this.usersSelectionModel.getSelectedSet().toArray(new TaggedName[0]);
          getUiHandlers().setupCloneUserAccountDialog(users[0]);
       }

       /**
        * The Edit User button click handler.
        *
        * @param    e
        *           Click event
        */
       @UiHandler("editUserAccount")
       void onEditUserAccount(ClickEvent e)
       {
          logger.info("onEditUserAccount");
          TaggedName[] users = UsersView.this.usersSelectionModel.getSelectedSet().toArray(new TaggedName[0]);
          getUiHandlers().showEditUserAccountDialog(users[0]);
       }

       /**
        * The Populate button click handler.
        *
        * @param    e
        *           Click event
        */
       @UiHandler("populateGroups")
       void onPopulateGroups(ClickEvent e)
       {
          getUiHandlers().populateAndRefreshAllGroups();
       }

       /**
        * The Delete User button click handler.
        *
        * @param    e
        *           Click event
        */
       @UiHandler("deleteUserAccount")
       void onDeleteUserAccount(ClickEvent e)
       {
          logger.info("onDeleteUserAccount");
          TaggedName[] users = this.usersSelectionModel.getSelectedSet().toArray(new TaggedName[0]);

          getUiHandlers().setupDeletingUsersAlert(users);
       }

       /**
        * The Find User button click handler.
        *
        * @param    e
        *           Click event
        */
       @UiHandler("findUser")
       void onFindUserAccount(ClickEvent e)
       {
          logger.info("onFindUserAccount");

          getUiHandlers().setupFindUserAccountDialog();
       }

       /**
        * The Delete Group button click handler.
        *
        * @param    e
        *           Click event
        */
       @UiHandler("deleteGroup")
       void onDeleteGroup(ClickEvent e)
       {
          logger.info("onDeleteGroup");

          TaggedName[] users = this.usersSelectionModel.getSelectedSet().toArray(new TaggedName[0]);
          TaggedName[] groups = this.userGroupsSelectionModel.getSelectedSet().toArray(new TaggedName[0]);

          getUiHandlers().setupRemovingGroupsAlert(users[0], groups);
       }

       /**
        * The Assign New Group button click handler.
        *
        * @param    e
        *           Click event
        */
       @UiHandler("assignNewGroup")
       void onAssignNewGroup(ClickEvent e)
       {
          logger.info("onAssignNewGroup");

          TaggedName[] users = this.usersSelectionModel.getSelectedSet().toArray(new TaggedName[0]);
          //TODO validation
          getUiHandlers().addUserInNewGroup(users[0], newGroup.getText());
       }

       /**
        * The Filter button click handler.
        *
        * @param    e
        *           Click event
        */
       @UiHandler("filterGroups")
       void onFilterGroups(ClickEvent e)
       {
          logger.info("onFilterGroups");
          //TODO input validation
          getUiHandlers().setGroupsFilter(filterSelector.getText());
       }

       /**
        * The Add Selected button click handler.
        *
        * @param    e
        *           Click event
        */
       @UiHandler("addSelected")
       void onAddSelected(ClickEvent e)
       {
          logger.info("AddSelected");
          List<TaggedName> userGroups = UsersView.this.userGroupsProvider.getList();
          Set<TaggedName> selected = this.allGroupsSelectionModel.getSelectedSet();
          selected.removeAll(userGroups);
          TaggedName[] additionalGroups = selected.toArray(new TaggedName[0]);
          TaggedName user = this.usersSelectionModel.getSelectedSet().toArray(new TaggedName[0])[0];

          getUiHandlers().addUserToGroups(user, additionalGroups);
       }

       /**
        * Sets the user's groups table's model with all assigned groups for the single selected
        * user from the all users table view.
        *
        * @param    groups
        *           The array of assigned groups given by tagged names
        */
       @Override
       public void setAssignedGroups(TaggedName[] groups)
       {
          logger.info("setAssignedGroups");
          this.userGroupsSelectionModel.clear();
          this.allGroupsSelectionModel.clear();
          updateDataProvider(userGroupsGrid, userGroupsProvider, groups);

          List<TaggedName> userGroups = UsersView.this.userGroupsProvider.getList();
          userGroups.forEach(group -> UsersView.this.allGroupsSelectionModel.setSelected(group, true));

          UsersView.this.addSelected.setEnabled(false);
       }

       /**
        * Sets the all groups accounts table's model with all existing groups accounts.
        *
        * @param    allGroups
        *           The array of all existing groups accounts
        * @param    filterExp
        *           The regular expression to select groups with accounts names according to this
        *           filter criteria
        */
       @Override
       public void setAllGroups(TaggedName[] allGroups, RegExp filterExp)
       {
          updateDataProvider(allGroupsGrid, allGroupsProvider,
                   allGroups, filterExp);
          if (UsersView.this.usersSelectionModel.getSelectedSet().size() == 1)
          {
             List<TaggedName> userGroups = UsersView.this.userGroupsProvider.getList();
             userGroups.forEach(group -> UsersView.this.allGroupsSelectionModel.setSelected(group, true));
          }
          else
          {
             UsersView.this.allGroupsSelectionModel.clear();
          }
       }

       /**
        * Gets a reference to the Deleting Users Alert.
        *
        * @return   The Deleting Users Alert
        */
       @Override
       public DeletingUsersAlert getDeletingUsersAlert()
       {
          return deletingUsersAlert;
       }

       /**
        * Gets a reference to the Clone User Account View.
        *
        * @return   The Clone User Account View
        */
       @Override
       public CloneUserAccountView getCloneUserAccountView()
       {
          return cloneUserAccountView;
       }

       /**
        * Provides all components that must be managed by its view state machine.
        *
        * @return   The array of components managed by its view state machine
        */
       @Override
       public HasEnabled[] get()
       {
          return new HasEnabled[] {
                   refresh,
                   addUserAccount,
                   deleteUserAccount,
                   cloneUserAccount,
                   editUserAccount,
                   disableUserAccount,
                   findUser,
                   switchToACLs,

                   newGroup,
                   assignNewGroup,
                   deleteGroup,

                   populateGroups,
                   addSelected,
                   filterSelector,
                   filterGroups
          };
       }

       /**
        * Gets a reference to the Removing Groups Alert.
        *
        * @return   The Removing Groups Alert
        */
       @Override
       public RemovingGroupsAlert getRemovingGroupsAlert()
       {
          return removingGroupsAlert;
       }

       /**
        * Tests if this group has been selected from the user's assigned groups table.
        *
        * @param    group
        *           The target group account given by its tagged name
        *
        * @return   True iff the target group has been selected, otherwise false.
        */
       @Override
       public boolean isSelectedFromUserGroups(TaggedName group)
       {
          return userGroupsSelectionModel.isSelected(group);
       }

       /**
        * Tests if these tested users have been selected from the all users table.
        *
        * @param    users
        *           The array of tested user accounts given by tagged names
        *
        * @return   True if all tested users have been selected, otherwise false.
        */
       @Override
       public boolean isSelectedFromUsers(TaggedName[] users)
       {
          return usersSelectionModel.getSelectedSet().containsAll(Arrays.asList(users));
       }

       /**
        * Returns the parent container where the Add/Edit User Definition View will be revealed in.
        *
        * @return   The parent container for the Add/Edit User Definition View.
        */
       @Override
       public HasWidgets getUserDefModalParent()
       {
          return userDefModal;
       }

       /**
        * Selects the user's data row from the all users table by a given user's tagged name.
        *
        * @param    user
        *           The user account given by its tagged name
        */
       @Override
       public void selectUser(TaggedName user)
       {
          logger.info("setSelectedUser " + user.getName());
          usersSelectionModel.clear();
          userGroupsSelectionModel.clear();
          Scheduler.get().scheduleDeferred(new ScheduledCommand()
          {
             @Override
             public void execute()
             {
                usersSelectionModel.setSelected(user, true);
                scrollIntoView(user);
             }
          });
       }

       /**
        * Sets the row with the given user within the current view.
        *
        * @param    user
        *           The user account given by its tagged name
        */
       private void scrollIntoView(TaggedName user)
       {
          int index = usersProvider.getList().indexOf(user);
          if (index >= 0)
          {
             usersGrid.getRowElement(index).scrollIntoView();
          }
       }

       /**
        * Selects the user's data row from the all users table by a given user's account name.
        *
        * @param    name
        *           The account name.
        */
       @Override
       public void selectUserByName(String name)
       {
          logger.info("setSelectedUser " + name);
          usersSelectionModel.clear();
          userGroupsSelectionModel.clear();
          usersProvider.getList().forEach(user -> {
             if (user.getName().equals(name))
             {
                Scheduler.get().scheduleDeferred(new ScheduledCommand()
                {
                   @Override
                   public void execute()
                   {
                      usersSelectionModel.setSelected(user, true);
                      scrollIntoView(user);
                   }
                });
             }
          });

       }

       /**
        * Changes the Populate button's label from "Populate" to "Refresh"
        *
        * @param    populated
        *           The flag which true value means to change the Populate label to Refresh one
        */
       @Override
       public void togglePopulateGroupsButton(boolean populated)
       {
          if (populated)
          {
             populateGroups.setText("Refresh");
          }
       }

       /**
        * Toggles the Disable/Enable User button's label.
        *
        * @param    enabled
        *           Indicates the user's enabled state. The true value switches this button's label
        *           from "Enable User" to "Disable User" and vice versa the false value switches
        *           from "Disable User" to "Enable User".
        */
       @Override
       public void toggleDisableUserButton(boolean enabled)
       {
          if (enabled)
          {
             disableUserAccount.setText("Disable User");
          }
          else
          {
             disableUserAccount.setText("Enable User");
          }
       }

       /**
        * Tests if the tested user has been selected from the all users table.
        *
        * @param    user
        *           The tested user account given by its tagged name
        *
        * @return   True if the tested user has been selected, otherwise false.
        */
       @Override
       public boolean isSelectedFromUsers(TaggedName user)
       {
          return usersSelectionModel.getSelectedSet().contains(user);
       }

       @UiHandler("disableUserAccount")
       public void onDisableUserAccount(ClickEvent e)
       {
          TaggedName user = usersSelectionModel.getSelectedSet().toArray(new TaggedName[0])[0];
          getUiHandlers().disableUserAccount(user);
       }

       /**
        * Tests if these tested groups have been selected from the user's assigned groups table.
        *
        * @param    groups
        *           The array of tested groups given by tagged names
        *
        * @return   True iff the tested groups have been selected, otherwise false.
        */
       @Override
       public boolean isSelectedFromUserGroups(TaggedName[] groups)
       {
          return userGroupsSelectionModel.getSelectedSet().containsAll(Arrays.asList(groups));
       }

       /**
        * Tests if these tested groups have been selected from the all groups table.
        *
        * @param    groups
        *           The array of tested groups given by tagged names
        *
        * @return   True iff the tested groups have been selected, otherwise false.
        */
       @Override
       public boolean isSelectedFromAllGroups(TaggedName[] groups)
       {
          return allGroupsSelectionModel.getSelectedSet().containsAll(Arrays.asList(groups));
       }

       /**
        * The Switch To ACLs button click handler.
        *
        * @param    e
        *           Click event
        */
       @UiHandler("switchToACLs")
       void onSwitchToACLs(ClickEvent e)
       {
          logger.info("onSwitchToACLs");
          TaggedName selected = UsersView.this.usersSelectionModel.getSelectedSet().toArray(new TaggedName[0])[0];
          getUiHandlers().switchToACLs(selected);
       }

       /**
        * Returns pairs of a report parameter key and its value
        *
        * @return   The enumeration map of report parameters keys to their values
        */
       @Override
       public EnumMap<ReportParameters, Object> getReportParameters()
       {
          EnumMap<ReportParameters, Object> parameters = new EnumMap<ReportParameters, Object>(
                   ReportParameters.class);
          parameters.put(ReportParameters.SELECTION, usersSelectionModel.getSelectedSet().toArray(
                   new TaggedName[usersSelectionModel.getSelectedSet().size()]));
          parameters.put(ReportParameters.TITLE, "Users");
          parameters.put(ReportParameters.REPORT_ID, Reports.USERS);
          parameters.put(ReportParameters.PAPER_FORMAT, PaperFormat.A4);
          parameters.put(ReportParameters.PAPER_ORIENT, PaperOrientation.PORTRAIT);

          return parameters;
       }

       /**
        * Returns the size of all data to preview or the size of selected data to preview
        *
        * @param    range
        *           The target range of selected data to preview
        * @return   The size of the selected data
        */
       @Override
       public int getDataSize(Range range)
       {
          if (range == Range.SELECTION)
          {
             return usersSelectionModel.getSelectedSet().size();
          }

          return usersProvider.getList().size();
       }

       /**
        * Returns the value of the preview dialog parameter.
        *
        * @param    parameter
        *           The preview dialog parameter key
        *
        * @return   The value of the preview dialog parameter
        */
       @Override
       public String getPreviewDialogParameter(PreviewDialogParameters parameter)
       {
          int selectedRecordsNumber = usersSelectionModel.getSelectedSet().size();
          int allRecordsNumber = usersProvider.getList().size();
          switch (parameter)
          {
             case HELP_TEXT:
                String hlpText;
                if (selectedRecordsNumber > 0)
                {
                   hlpText = "<h4>Please refine your request.</h4>";
                }
                else
                {
                   if (allRecordsNumber > 1)
                   {
                      hlpText = "<h4>" + allRecordsNumber + " user accounts being printed. Continue?</h4>";
                   }
                   else if (allRecordsNumber == 1)
                   {
                      hlpText = "<h4>1 user account being printed. Continue?</h4>";
                   }
                   else
                   {
                      hlpText = "<h4>There are no users to print. Continue?</h4>";
                   }
                }

                return hlpText;
             case TITLE:
                return "Printing Users";
             case RANGE_ALL_LABEL:
                if (allRecordsNumber > 2)
                {
                   return "all " + allRecordsNumber + " user accounts";
                }
                else if (allRecordsNumber == 2)
                {
                   return "both user accounts";
                }

                break;
             case RANGE_SELECTION_LABEL:
                if (selectedRecordsNumber > 1)
                {
                   return selectedRecordsNumber + " selected user accounts";
                }
                else if (selectedRecordsNumber == 1)
                {
                   return "the selected user account";
                }

                break;
          }

          return null;
       }

       /**
        * Returns url path to this view.
        *
        * @return   The url path.
        */
       @Override
       public String getPathToPrintPreviewOwner()
       {
          return NameTokens.USERS;
       }
    }