package com.intellij.openapi.vcs.changes.actions.diff;

import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.DefaultActionGroup;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectManager;
import com.intellij.openapi.ui.popup.JBPopup;
import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.openapi.util.Ref;
import com.intellij.diff.actions.impl.GoToChangePopupBuilder;
import com.intellij.diff.chains.DiffRequestChain;
import com.intellij.openapi.vcs.changes.Change;
import com.intellij.openapi.vcs.changes.ui.ChangesBrowser;
import com.intellij.openapi.wm.IdeFocusManager;
import com.intellij.util.Consumer;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import javax.swing.*;
import java.util.Collections;
import java.util.List;

public abstract class ChangeGoToChangePopupAction<Chain extends DiffRequestChain>
  extends GoToChangePopupBuilder.BaseGoToChangePopupAction<Chain>{
  public ChangeGoToChangePopupAction(@NotNull Chain chain, @NotNull Consumer onSelected) {
    super(chain, onSelected);
  }

  @NotNull
  @Override
  protected JBPopup createPopup(@NotNull AnActionEvent e) {
    Project project = e.getProject();
    if (project == null) project = ProjectManager.getInstance().getDefaultProject();

    Ref<JBPopup> popup = new Ref<JBPopup>();
    ChangesBrowser cb = new MyChangesBrowser(project, getChanges(), getCurrentSelection(), popup);

    popup.set(JBPopupFactory.getInstance()
                .createComponentPopupBuilder(cb, cb.getPreferredFocusedComponent())
                .setResizable(true)
                .setModalContext(false)
                .setFocusable(true)
                .setRequestFocus(true)
                .setCancelOnWindowDeactivation(true)
                .setCancelOnOtherWindowOpen(true)
                .setMovable(true)
                .setCancelKeyEnabled(true)
                .setCancelOnClickOutside(true)
                .createPopup());

    return popup.get();
  }

  //
  // Abstract
  //

  protected abstract int findSelectedStep(@Nullable Change change);

  @NotNull
  protected abstract List<Change> getChanges();

  @Nullable
  protected abstract Change getCurrentSelection();

  //
  // Helpers
  //

  private class MyChangesBrowser extends ChangesBrowser implements Runnable {
    @NotNull Ref<JBPopup> myPopup;

    public MyChangesBrowser(@NotNull Project project,
                            @NotNull List<Change> changes,
                            @Nullable Change currentChange,
                            @NotNull Ref<JBPopup> popup) {
      super(project, null, changes, null, false, false, null, MyUseCase.LOCAL_CHANGES, null);
      setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
      setChangesToDisplay(changes);
      if (currentChange != null) select(Collections.singletonList(currentChange));

      myPopup = popup;
    }

    @Override
    protected void buildToolBar(DefaultActionGroup toolBarGroup) {
      // remove diff action
    }

    @NotNull
    @Override
    protected Runnable getDoubleClickHandler() {
      return this;
    }

    @Override
    public void run() {
      Change change = getSelectedChanges().get(0);
      final int index = findSelectedStep(change);
      myPopup.get().cancel();
      IdeFocusManager.getInstance(myProject).doWhenFocusSettlesDown(new Runnable() {
        @Override
        public void run() {
          //noinspection unchecked
          myOnSelected.consume(index);
        }
      });
    }
  }
}

@@ -49,16 +49,128 @@
 .diff;%0A%0A
+import com.intellij.diff.actions.impl.GoToChangePopupBuilder;%0Aimport com.intellij.diff.chains.DiffRequestChain;%0A
 import c
@@ -516,120 +516,8 @@
 ef;%0A
-import com.intellij.diff.actions.impl.GoToChangePopupBuilder;%0Aimport com.intellij.diff.chains.DiffRequestChain;%0A
 impo
@@ -698,24 +698,78 @@
 l.Consumer;%0A
+import com.intellij.util.ui.update.UiNotifyConnector;%0A
 import org.j
@@ -2438,32 +2438,46 @@
  %7B%0A    @NotNull 
+private final 
 Ref%3CJBPopup%3E myP
@@ -2482,16 +2482,16 @@
 yPopup;%0A
-
 %0A    pub
@@ -2626,32 +2626,38 @@
       @Nullable 
+final 
 Change currentCh
@@ -2912,16 +2912,131 @@
 anges);%0A
+%0A      UiNotifyConnector.doWhenFirstShown(this, new Runnable() %7B%0A        @Override%0A        public void run() %7B%0A    
       if
@@ -3109,16 +3109,36 @@
 hange));
+%0A        %7D%0A      %7D);
 %0A%0A      

fix initial scroll position for "Go To Change" action