@Override
    public void load(
        final Filter f,
        final long start,
        final long end,
        final DataLoadHandler<ListGridEntry<ProjectMember>> lh) {

      if (_mode.equals(FormEditMode.CREATE)) {
        if (_o.members() == null) {
          lh.loaded(0, 0, 0, null, null);
        } else {
          doLoad(f, start, end, _o.members(), lh);
        }
      } else {
        new ProjectMemberList(_o)
            .send(
                new ObjectMessageResponse<List<ProjectMember>>() {

                  @Override
                  public void responded(List<ProjectMember> pms) {

                    if (pms != null) {
                      if (!pms.isEmpty()) {
                        doLoad(f, start, end, pms, lh);
                        return;
                      }
                    }
                    lh.loaded(0, 0, 0, null, null);
                  }
                });
      }
    }
  @Override
  public boolean changed() {

    if (_mode.equals(FormEditMode.READ_ONLY)) {
      return false;
    }
    return _changed;
  }
    @Override
    public boolean isRemote() {

      if (_mode.equals(FormEditMode.CREATE)) {
        return true;
      }
      return false;
    }
  @Override
  public DropCheck checkCanDrop(Object o) {

    if (_mode.equals(FormEditMode.READ_ONLY)) {
      return DropCheck.CANNOT;
    }
    if (o instanceof UserRef || o instanceof ProjectMember) {
      return DropCheck.CAN;
    }
    return DropCheck.CANNOT;
  }
  @Override
  public Validity valid() {

    if (_mode.equals(FormEditMode.READ_ONLY)) {
      return IsValid.INSTANCE;
    }

    if (!_o.hasMembersOrRoleMembers()) {
      return new Validity() {

        @Override
        public boolean valid() {

          return false;
        }

        @Override
        public String reasonForIssue() {

          return "No member or role members are set.";
        }
      };
    }
    if (!_o.hasAdminMember()) {
      return new Validity() {

        @Override
        public boolean valid() {

          return false;
        }

        @Override
        public String reasonForIssue() {

          return "No project-administrator member or role member is set.";
        }
      };
    }
    return IsValid.INSTANCE;
  }
  private void commitChanges(final Action postAction) {

    if (_mode.equals(FormEditMode.UPDATE)) {
      _o.commitMembers(
          new ObjectMessageResponse<Boolean>() {

            @Override
            public void responded(Boolean r) {

              if (r) {
                _changed = true;
                ProjectMemberGrid.this.notifyOfChangeInState();
                postAction.execute();
              }
            }
          });
    } else {
      notifyOfChangeInState();
      if (postAction != null) {
        postAction.execute();
      }
    }
  }
  public ProjectMemberGrid(Project o, FormEditMode mode) {

    super(new ProjectMemberDataSource(o, mode), ScrollPolicy.AUTO);
    _o = o;
    _mode = mode;
    if (_mode.equals(FormEditMode.READ_ONLY)) {
      addColumnDefn("name", "Name").setWidth(100);
      addColumnDefn("authority", "Authority").setWidth(120);
      addColumnDefn("domain", "Domain").setWidth(100);
      addColumnDefn("user", "User").setWidth(100);
      addColumnDefn("role", "Role").setWidth(120);
      addColumnDefn("dataUse", "Data Use").setWidth(80);
    } else {
      addColumnDefn("role", "Role").setWidth(120);
      addColumnDefn("domain", "Domain").setWidth(100);
      addColumnDefn("user", "User").setWidth(100);
      addColumnDefn("dataUse", "Data Use").setWidth(80);
    }

    fitToParent();
    setShowHeader(true);
    setShowRowSeparators(true);
    setMultiSelect(false);
    setFontSize(10);
    setCellSpacing(0);
    setCellPadding(1);
    setEmptyMessage("");
    setLoadingMessage("Loading project members...");
    setCursorSize(Integer.MAX_VALUE);

    setRowToolTip(
        new ToolTip<ProjectMember>() {

          @Override
          public void generate(ProjectMember pm, ToolTipHandler th) {

            th.setTip(new HTML(pm.toHTML()));
          }
        });

    /*
     *
     */
    setObjectRegistry(DObjectGUIRegistry.get());

    /*
     * make drop target, and enable row drag (to delete member)
     */
    if (!_mode.equals(FormEditMode.READ_ONLY)) {
      setRowDoubleClickHandler(
          new ListGridRowDoubleClickHandler<ProjectMember>() {

            @Override
            public void doubleClicked(final ProjectMember pm, DoubleClickEvent event) {

              if (pm == null) {
                return;
              }
              int x = event.getClientX();
              int y = event.getClientY();
              ProjectMemberRoleSelector.showAt(
                  x,
                  y,
                  new ProjectMemberRoleSelector.RoleSelectionListener() {

                    @Override
                    public void roleSelected(ProjectRole role, DataUse dataUse) {

                      if (role != null) {
                        pm.setRole(role);
                        pm.setDataUse(dataUse);
                        _o.addMember(pm);
                        if (_mode == FormEditMode.UPDATE) {
                          commitChangesAndRefresh();
                        } else if (_mode == FormEditMode.CREATE) {
                          notifyOfChangeInState();
                        }
                      }
                    }
                  });
            }
          });

      setRowContextMenuHandler(
          new ListGridRowContextMenuHandler<ProjectMember>() {

            @Override
            public void show(final ProjectMember pm, ContextMenuEvent event) {

              final int x = event.getNativeEvent().getClientX();
              final int y = event.getNativeEvent().getClientY();
              Menu menu = new Menu("Member");
              menu.setShowTitle(true);
              menu.add(
                  new ActionEntry(
                      "Remove",
                      new Action() {

                        @Override
                        public void execute() {

                          _o.removeMember(pm);
                          commitChangesAndRefresh();
                        }
                      }));
              menu.add(
                  new ActionEntry(
                      "Set role and data-use",
                      new Action() {

                        @Override
                        public void execute() {

                          ProjectMemberRoleSelector.showAt(
                              x,
                              y,
                              new ProjectMemberRoleSelector.RoleSelectionListener() {

                                @Override
                                public void roleSelected(ProjectRole role, DataUse dataUse) {

                                  if (role != null) {
                                    if (!role.equals(pm.role())
                                        || !ObjectUtil.equals(dataUse, pm.dataUse())) {
                                      pm.setRole(role);
                                      pm.setDataUse(dataUse);
                                      _o.addMember(pm);
                                      commitChangesAndRefresh();
                                    }
                                  }
                                }
                              });
                        }
                      }));
              ActionContextMenu am = new ActionContextMenu(menu);
              NativeEvent ne = event.getNativeEvent();
              am.showAt(ne);
            }
          });
      enableDropTarget(false);
      setDropHandler(this);
      enableRowDrag();
    }
  }