void onDispose(Event event) {
    removeListener(SWT.Dispose, listener);
    notifyListeners(SWT.Dispose, event);
    event.type = SWT.None;

    table.removeListener(SWT.FocusIn, tableListener);
    table.removeListener(SWT.MouseDown, tableListener);
    unhookRowColumnListeners();
    ScrollBar hBar = table.getHorizontalBar();
    if (hBar != null) {
      hBar.removeListener(SWT.Selection, resizeListener);
    }
    ScrollBar vBar = table.getVerticalBar();
    if (vBar != null) {
      vBar.removeListener(SWT.Selection, resizeListener);
    }
  }
  /**
   * Constructs a new instance of this class given its parent table and a style value describing its
   * behavior and appearance.
   *
   * <p>The style value is either one of the style constants defined in class <code>SWT</code> which
   * is applicable to instances of this class, or must be built by <em>bitwise OR</em>'ing together
   * (that is, using the <code>int</code> "|" operator) two or more of those <code>SWT</code> style
   * constants. The class description lists the style constants that are applicable to the class.
   * Style bits are also inherited from superclasses.
   *
   * @param parent a Table control which will be the parent of the new instance (cannot be null)
   * @param style the style of control to construct
   * @exception IllegalArgumentException
   *     <ul>
   *       <li>ERROR_NULL_ARGUMENT - if the parent is null
   *     </ul>
   *
   * @exception SWTException
   *     <ul>
   *       <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent
   *       <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass
   *     </ul>
   *
   * @see SWT#BORDER
   * @see Widget#checkSubclass()
   * @see Widget#getStyle()
   */
  public TableCursor(Table parent, int style) {
    super(parent, style);
    table = parent;
    setBackground(null);
    setForeground(null);

    listener =
        event -> {
          switch (event.type) {
            case SWT.Dispose:
              onDispose(event);
              break;
            case SWT.FocusIn:
            case SWT.FocusOut:
              redraw();
              break;
            case SWT.KeyDown:
              keyDown(event);
              break;
            case SWT.Paint:
              paint(event);
              break;
            case SWT.Traverse:
              {
                event.doit = true;
                switch (event.detail) {
                  case SWT.TRAVERSE_ARROW_NEXT:
                  case SWT.TRAVERSE_ARROW_PREVIOUS:
                  case SWT.TRAVERSE_RETURN:
                    event.doit = false;
                    break;
                }
                break;
              }
          }
        };
    int[] events =
        new int[] {SWT.Dispose, SWT.FocusIn, SWT.FocusOut, SWT.KeyDown, SWT.Paint, SWT.Traverse};
    for (int i = 0; i < events.length; i++) {
      addListener(events[i], listener);
    }

    tableListener =
        event -> {
          switch (event.type) {
            case SWT.MouseDown:
              tableMouseDown(event);
              break;
            case SWT.FocusIn:
              tableFocusIn(event);
              break;
          }
        };
    table.addListener(SWT.FocusIn, tableListener);
    table.addListener(SWT.MouseDown, tableListener);

    disposeItemListener =
        event -> {
          unhookRowColumnListeners();
          row = null;
          column = null;
          _resize();
        };
    disposeColumnListener =
        event -> {
          unhookRowColumnListeners();
          row = null;
          column = null;
          _resize();
        };
    resizeListener = event -> _resize();
    ScrollBar hBar = table.getHorizontalBar();
    if (hBar != null) {
      hBar.addListener(SWT.Selection, resizeListener);
    }
    ScrollBar vBar = table.getVerticalBar();
    if (vBar != null) {
      vBar.addListener(SWT.Selection, resizeListener);
    }

    getAccessible()
        .addAccessibleControlListener(
            new AccessibleControlAdapter() {
              @Override
              public void getRole(AccessibleControlEvent e) {
                e.detail = ACC.ROLE_TABLECELL;
              }
            });
    getAccessible()
        .addAccessibleListener(
            new AccessibleAdapter() {
              @Override
              public void getName(AccessibleEvent e) {
                if (row == null) return;
                int columnIndex = column == null ? 0 : table.indexOf(column);
                e.result = row.getText(columnIndex);
              }
            });
  }