import sun.awt.AWTAccessor;
import sun.awt.AppContext;
import sun.awt.CausedFocusEvent;
import sun.awt.RequestFocusController;

import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.WindowConstants;
import java.awt.AWTEvent;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Cursor;
import java.awt.Font;
import java.awt.GraphicsConfiguration;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.peer.ComponentPeer;
import java.security.AccessControlContext;

public class RequestFocusDemo {
  public static void main(String[] args) {

    RequestFocusController ourRequestFocusController = new RequestFocusController() {
      @Override
      public boolean acceptRequestFocus(final Component component, final Component component1, final boolean b, final boolean b1, final CausedFocusEvent.Cause cause) {
        System.out.println("acceptRequestFocus");
        return true;
      }
    };

    AWTAccessor.setComponentAccessor(new ComponentAccessorDelegator(AWTAccessor.getComponentAccessor()) {
      @Override
      public void setRequestFocusController(final RequestFocusController requestFocusController) {
        super.setRequestFocusController(ourRequestFocusController); // disallow further changes
      }
    });
    AWTAccessor.getComponentAccessor().setRequestFocusController(ourRequestFocusController);

    JPanel panel = new JPanel();
    BoxLayout layout = new BoxLayout(panel, BoxLayout.Y_AXIS);
    panel.setLayout(layout);
    panel.add(new TextFieldImpl());
    panel.add(new TextFieldImpl());
    panel.add(new TextFieldImpl());
    panel.add(new TextFieldImpl());

    JFrame frame = new JFrame();
    frame.getContentPane().add(panel);
    frame.setSize(400, 400);
    frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
    frame.setVisible(true);
  }

  static class TextFieldImpl extends JTextField {
    TextFieldImpl() {
    }

    @Override
    public void requestFocus() {
      System.out.println("requestFocus");
      super.requestFocus();
    }

    @Override
    public boolean requestFocus(boolean temporary) {
      System.out.println("requestFocus(boolean)");
      return super.requestFocus(temporary);
    }

    @Override
    public boolean requestFocusInWindow() {
      System.out.println("requestFocusInWindow");
      return super.requestFocusInWindow();
    }

    @Override
    protected boolean requestFocusInWindow(boolean temporary) {
      System.out.println("requestFocusInWindow(boolean)");
      return super.requestFocusInWindow(temporary);
    }
  }


  static class ComponentAccessorDelegator implements AWTAccessor.ComponentAccessor {
    private AWTAccessor.ComponentAccessor delegation;

    private ComponentAccessorDelegator(AWTAccessor.ComponentAccessor delegation) {
      this.delegation = delegation;
    }

    @Override
    public void setBackgroundEraseDisabled(Component component, boolean b) {
      delegation.setBackgroundEraseDisabled(component, b);
    }

    @Override
    public boolean getBackgroundEraseDisabled(Component component) {
      return delegation.getBackgroundEraseDisabled(component);
    }

    @Override
    public Rectangle getBounds(Component component) {
      return delegation.getBounds(component);
    }

    @Override
    public void setMixingCutoutShape(Component component, Shape shape) {
      delegation.setMixingCutoutShape(component, shape);
    }

    @Override
    public void setGraphicsConfiguration(Component component, GraphicsConfiguration graphicsConfiguration) {
      delegation.setGraphicsConfiguration(component, graphicsConfiguration);
    }

    @Override
    public boolean requestFocus(Component component, CausedFocusEvent.Cause cause) {
      return delegation.requestFocus(component, cause);
    }

    @Override
    public boolean canBeFocusOwner(Component component) {
      return delegation.canBeFocusOwner(component);
    }

    @Override
    public boolean isVisible(Component component) {
      return delegation.isVisible(component);
    }

    @Override
    public void setRequestFocusController(RequestFocusController requestFocusController) {
      delegation.setRequestFocusController(requestFocusController);
    }

    @Override
    public AppContext getAppContext(Component component) {
      return delegation.getAppContext(component);
    }

    @Override
    public void setAppContext(Component component, AppContext appContext) {
      delegation.setAppContext(component, appContext);
    }

    @Override
    public Container getParent(Component component) {
      return delegation.getParent(component);
    }

    @Override
    public void setParent(Component component, Container container) {
      delegation.setParent(component, container);
    }

    @Override
    public void setSize(Component component, int i, int i1) {
      delegation.setSize(component, i, i1);
    }

    @Override
    public Point getLocation(Component component) {
      return delegation.getLocation(component);
    }

    @Override
    public void setLocation(Component component, int i, int i1) {
      delegation.setLocation(component, i, i1);
    }

    @Override
    public boolean isEnabled(Component component) {
      return delegation.isEnabled(component);
    }

    @Override
    public boolean isDisplayable(Component component) {
      return delegation.isDisplayable(component);
    }

    @Override
    public Cursor getCursor(Component component) {
      return delegation.getCursor(component);
    }

    @Override
    public ComponentPeer getPeer(Component component) {
      return delegation.getPeer(component);
    }

    @Override
    public void setPeer(Component component, ComponentPeer componentPeer) {
      delegation.setPeer(component, componentPeer);
    }

    @Override
    public boolean isLightweight(Component component) {
      return delegation.isLightweight(component);
    }

    @Override
    public boolean getIgnoreRepaint(Component component) {
      return delegation.getIgnoreRepaint(component);
    }

    @Override
    public int getWidth(Component component) {
      return delegation.getWidth(component);
    }

    @Override
    public int getHeight(Component component) {
      return delegation.getHeight(component);
    }

    @Override
    public int getX(Component component) {
      return delegation.getX(component);
    }

    @Override
    public int getY(Component component) {
      return delegation.getY(component);
    }

    @Override
    public Color getForeground(Component component) {
      return delegation.getForeground(component);
    }

    @Override
    public Color getBackground(Component component) {
      return delegation.getBackground(component);
    }

    @Override
    public void setBackground(Component component, Color color) {
      delegation.setBackground(component, color);
    }

    @Override
    public Font getFont(Component component) {
      return delegation.getFont(component);
    }

    @Override
    public void processEvent(Component component, AWTEvent awtEvent) {
      delegation.processEvent(component, awtEvent);
    }

    @Override
    public AccessControlContext getAccessControlContext(Component component) {
      return delegation.getAccessControlContext(component);
    }

    @Override
    public void revalidateSynchronously(Component component) {
      delegation.revalidateSynchronously(component);
    }
  }
}
