<commit_before>// Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.ui.popup;

import com.intellij.codeInsight.hint.HintUtil;
import com.intellij.icons.AllIcons;
import com.intellij.ide.*;
import com.intellij.ide.actions.WindowAction;
import com.intellij.ide.ui.PopupLocationTracker;
import com.intellij.ide.ui.ScreenAreaConsumer;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.MnemonicHelper;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.actionSystem.DataProvider;
import com.intellij.openapi.actionSystem.PlatformDataKeys;
import com.intellij.openapi.actionSystem.impl.ActionToolbarImpl;
import com.intellij.openapi.actionSystem.impl.AutoPopupSupportingListener;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.application.TransactionGuard;
import com.intellij.openapi.application.TransactionGuardImpl;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.EditorActivityManager;
import com.intellij.openapi.editor.ex.EditorEx;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectUtil;
import com.intellij.openapi.ui.popup.*;
import com.intellij.openapi.util.*;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.util.text.HtmlChunk;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.wm.*;
import com.intellij.openapi.wm.ex.WindowManagerEx;
import com.intellij.openapi.wm.impl.IdeGlassPaneImpl;
import com.intellij.ui.*;
import com.intellij.ui.awt.RelativePoint;
import com.intellij.ui.components.JBLabel;
import com.intellij.ui.mac.touchbar.TouchBarsManager;
import com.intellij.ui.scale.JBUIScale;
import com.intellij.ui.speedSearch.ListWithFilter;
import com.intellij.ui.speedSearch.SpeedSearch;
import com.intellij.util.*;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.WeakList;
import com.intellij.util.ui.*;
import com.intellij.util.ui.accessibility.AccessibleContextUtil;
import org.jetbrains.annotations.*;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.Supplier;

import static java.awt.event.MouseEvent.*;
import static java.awt.event.WindowEvent.WINDOW_ACTIVATED;
import static java.awt.event.WindowEvent.WINDOW_GAINED_FOCUS;

public class AbstractPopup implements JBPopup, ScreenAreaConsumer {
  @NonNls public static final String SHOW_HINTS = "ShowHints";

  // Popup size stored with DimensionService is null first time
  // In this case you can put Dimension in content client properties to adjust size
  // Zero or negative values (with/height or both) would be ignored (actual values would be obtained from preferred size)
  @NonNls public static final String FIRST_TIME_SIZE = "FirstTimeSize";

  private static final Logger LOG = Logger.getInstance(AbstractPopup.class);

  private PopupComponent myPopup;
  private MyContentPanel myContent;
  private JComponent myPreferredFocusedComponent;
  private boolean myRequestFocus;
  private boolean myFocusable;
  private boolean myForcedHeavyweight;
  private boolean myLocateWithinScreen;
  private boolean myResizable;
  private WindowResizeListener myResizeListener;
  private WindowMoveListener myMoveListener;
  private JPanel myHeaderPanel;
  private CaptionPanel myCaption;
  private JComponent myComponent;
  private SpeedSearch mySpeedSearchFoundInRootComponent;
  private String myDimensionServiceKey;
  private Computable<Boolean> myCallBack;
  private Project myProject;
  private boolean myCancelOnClickOutside;
  private final List<JBPopupListener> myListeners = new CopyOnWriteArrayList<>();
  private boolean myUseDimServiceForXYLocation;
  private MouseChecker myCancelOnMouseOutCallback;
  private Canceller myMouseOutCanceller;
  private boolean myCancelOnWindow;
  private boolean myCancelOnWindowDeactivation = true;
  private Dimension myForcedSize;
  private Point myForcedLocation;
  private boolean myCancelKeyEnabled;
  private boolean myLocateByContent;
  private Dimension myMinSize;
  private List<Object> myUserData;
  private boolean myShadowed;

  private float myAlpha;
  private float myLastAlpha;

  private MaskProvider myMaskProvider;

  private Window myWindow;
  private boolean myInStack;
  private MyWindowListener myWindowListener;

  private boolean myModalContext;

  private Component[] myFocusOwners;
  private PopupBorder myPopupBorder;
  private Dimension myRestoreWindowSize;
  protected Component myOwner;
  private Component myRequestorComponent;
  private boolean myHeaderAlwaysFocusable;
  private boolean myMovable;
  private JComponent myHeaderComponent;

  InputEvent myDisposeEvent;

  private Runnable myFinalRunnable;
  private Runnable myOkHandler;
  private @Nullable BooleanFunction<? super KeyEvent> myKeyEventHandler;

  protected boolean myOk;
  private final List<Runnable> myResizeListeners = new ArrayList<>();

  private static final WeakList<JBPopup> all = new WeakList<>();

  private boolean mySpeedSearchAlwaysShown;
  protected final SpeedSearch mySpeedSearch = new SpeedSearch() {
    boolean searchFieldShown;

    @Override
    public void update() {
      mySpeedSearchPatternField.getTextEditor().setBackground(UIUtil.getTextFieldBackground());
      onSpeedSearchPatternChanged();
      mySpeedSearchPatternField.setText(getFilter());
      if (!mySpeedSearchAlwaysShown) {
        if (isHoldingFilter() && !searchFieldShown) {
          setHeaderComponent(mySpeedSearchPatternField);
          searchFieldShown = true;
        }
        else if (!isHoldingFilter() && searchFieldShown) {
          setHeaderComponent(null);
          searchFieldShown = false;
        }
      }
    }

    @Override
    public void noHits() {
      mySpeedSearchPatternField.getTextEditor().setBackground(LightColors.RED);
    }
  };

  protected SearchTextField mySpeedSearchPatternField;
  private boolean myNativePopup;
  private boolean myMayBeParent;
  private JLabel myAdComponent;
  private boolean myDisposed;
  private boolean myNormalWindowLevel;

  private UiActivity myActivityKey;
  private Disposable myProjectDisposable;

  private volatile State myState = State.NEW;

  void setNormalWindowLevel(boolean normalWindowLevel) {
    myNormalWindowLevel = normalWindowLevel;
  }

  private enum State {NEW, INIT, SHOWING, SHOWN, CANCEL, DISPOSE}

  private void debugState(@NonNls @NotNull String message, State @NotNull ... states) {
    if (LOG.isDebugEnabled()) {
      LOG.debug(hashCode() + " - " + message);
      if (!ApplicationManager.getApplication().isDispatchThread()) {
        LOG.debug("unexpected thread");
      }
      for (State state : states) {
        if (state == myState) {
          return;
        }
      }
      LOG.debug(new IllegalStateException("myState=" + myState));
    }
  }

  protected AbstractPopup() { }

  protected @NotNull AbstractPopup init(Project project,
                                        @NotNull JComponent component,
                                        @Nullable JComponent preferredFocusedComponent,
                                        boolean requestFocus,
                                        boolean focusable,
                                        boolean movable,
                                        String dimensionServiceKey,
                                        boolean resizable,
                                        @NlsContexts.PopupTitle @Nullable String caption,
                                        @Nullable Computable<Boolean> callback,
                                        boolean cancelOnClickOutside,
                                        @NotNull Set<? extends JBPopupListener> listeners,
                                        boolean useDimServiceForXYLocation,
                                        ActiveComponent commandButton,
                                        @Nullable IconButton cancelButton,
                                        @Nullable MouseChecker cancelOnMouseOutCallback,
                                        boolean cancelOnWindow,
                                        @Nullable ActiveIcon titleIcon,
                                        boolean cancelKeyEnabled,
                                        boolean locateByContent,
                                        boolean placeWithinScreenBounds,
                                        @Nullable Dimension minSize,
                                        float alpha,
                                        @Nullable MaskProvider maskProvider,
                                        boolean inStack,
                                        boolean modalContext,
                                        Component @NotNull [] focusOwners,
                                        @Nullable @NlsContexts.PopupAdvertisement String adText,
                                        int adTextAlignment,
                                        boolean headerAlwaysFocusable,
                                        @NotNull List<? extends Pair<ActionListener, KeyStroke>> keyboardActions,
                                        Component settingsButtons,
                                        final @Nullable Processor<? super JBPopup> pinCallback,
                                        boolean mayBeParent,
                                        boolean showShadow,
                                        boolean showBorder,
                                        Color borderColor,
                                        boolean cancelOnWindowDeactivation,
                                        @Nullable BooleanFunction<? super KeyEvent> keyEventHandler) {
    assert !requestFocus || focusable : "Incorrect argument combination: requestFocus=true focusable=false";

    all.add(this);

    myActivityKey = new UiActivity.Focus("Popup:" + this);
    myProject = project;
    myComponent = component;
    mySpeedSearchFoundInRootComponent =
      findInComponentHierarchy(component, it -> it instanceof ListWithFilter ? ((ListWithFilter)it).getSpeedSearch() : null);
    myPopupBorder = showBorder ? borderColor != null ? PopupBorder.Factory.createColored(borderColor) :
                                 PopupBorder.Factory.create(true, showShadow) :
                                 PopupBorder.Factory.createEmpty();
    myShadowed = showShadow;
    myContent = createContentPanel(resizable, myPopupBorder, false);
    myMayBeParent = mayBeParent;
    myCancelOnWindowDeactivation = cancelOnWindowDeactivation;

    myContent.add(component, BorderLayout.CENTER);
    if (adText != null) {
      setAdText(adText, adTextAlignment);
    }

    myCancelKeyEnabled = cancelKeyEnabled;
    myLocateByContent = locateByContent;
    myLocateWithinScreen = placeWithinScreenBounds;
    myAlpha = alpha;
    myMaskProvider = maskProvider;
    myInStack = inStack;
    myModalContext = modalContext;
    myFocusOwners = focusOwners;
    myHeaderAlwaysFocusable = headerAlwaysFocusable;
    myMovable = movable;

    ActiveIcon actualIcon = titleIcon == null ? new ActiveIcon(EmptyIcon.ICON_0) : titleIcon;

    myHeaderPanel = new JPanel(new BorderLayout());

    if (caption != null) {
      if (!caption.isEmpty()) {
        myCaption = new TitlePanel(actualIcon.getRegular(), actualIcon.getInactive());
        ((TitlePanel)myCaption).setText(caption);
      }
      else {
        myCaption = new CaptionPanel();
      }

      if (pinCallback != null) {
        Icon icon = ToolWindowManager.getInstance(myProject != null ? myProject : ProjectUtil.guessCurrentProject((JComponent)myOwner))
          .getLocationIcon(ToolWindowId.FIND, AllIcons.General.Pin_tab);
        myCaption.setButtonComponent(new InplaceButton(
          new IconButton(IdeBundle.message("show.in.find.window.button.name"), icon),
          e -> pinCallback.process(this)
        ), JBUI.Borders.empty(4));
      }
      else if (cancelButton != null) {
        myCaption.setButtonComponent(new InplaceButton(cancelButton, e -> cancel()), JBUI.Borders.empty(4));
      }
      else if (commandButton != null) {
        myCaption.setButtonComponent(commandButton, null);
      }
    }
    else {
      myCaption = new CaptionPanel();
      myCaption.setBorder(null);
      myCaption.setPreferredSize(JBUI.emptySize());
    }

    setWindowActive(myHeaderAlwaysFocusable);

    myHeaderPanel.add(myCaption, BorderLayout.NORTH);
    myContent.add(myHeaderPanel, BorderLayout.NORTH);

    myForcedHeavyweight = true;
    myResizable = resizable;
    myPreferredFocusedComponent = preferredFocusedComponent;
    myRequestFocus = requestFocus;
    myFocusable = focusable;
    myDimensionServiceKey = dimensionServiceKey;
    myCallBack = callback;
    myCancelOnClickOutside = cancelOnClickOutside;
    myCancelOnMouseOutCallback = cancelOnMouseOutCallback;
    myListeners.addAll(listeners);
    myUseDimServiceForXYLocation = useDimServiceForXYLocation;
    myCancelOnWindow = cancelOnWindow;
    myMinSize = minSize;

    if (Registry.is("ide.popup.horizontal.scroll.bar.opaque")) {
      forHorizontalScrollBar(bar -> bar.setOpaque(true));
    }

    for (Pair<ActionListener, KeyStroke> pair : keyboardActions) {
      myContent.registerKeyboardAction(pair.getFirst(), pair.getSecond(), JComponent.WHEN_IN_FOCUSED_WINDOW);
    }

    if (settingsButtons != null) {
      myCaption.addSettingsComponent(settingsButtons);
    }

    myKeyEventHandler = keyEventHandler;
    debugState("popup initialized", State.NEW);
    myState = State.INIT;
    return this;
  }

  private void setWindowActive(boolean active) {
    boolean value = myHeaderAlwaysFocusable || active;

    if (myCaption != null) {
      myCaption.setActive(value);
    }
    myPopupBorder.setActive(value);
    myContent.repaint();
  }


  protected @NotNull MyContentPanel createContentPanel(final boolean resizable, @NotNull PopupBorder border, boolean isToDrawMacCorner) {
    return new MyContentPanel(border);
  }

  public void setShowHints(boolean show) {
    final Window ancestor = getContentWindow(myComponent);
    if (ancestor instanceof RootPaneContainer) {
      final JRootPane rootPane = ((RootPaneContainer)ancestor).getRootPane();
      if (rootPane != null) {
        rootPane.putClientProperty(SHOW_HINTS, show);
      }
    }
  }

  public String getDimensionServiceKey() {
    return myDimensionServiceKey;
  }

  public void setDimensionServiceKey(final @Nullable String dimensionServiceKey) {
    myDimensionServiceKey = dimensionServiceKey;
  }

  public void setAdText(@NotNull @NlsContexts.PopupAdvertisement String s) {
    setAdText(s, SwingConstants.LEFT);
  }

  public @NotNull PopupBorder getPopupBorder() {
    return myPopupBorder;
  }

  @Override
  public void setAdText(@NotNull String s, int alignment) {
    if (myAdComponent == null) {
      myAdComponent = HintUtil.createAdComponent(s, JBUI.CurrentTheme.Advertiser.border(), alignment);
      myContent.add(myAdComponent, BorderLayout.SOUTH);
      pack(false, true);
    }

    Dimension prefSize = myAdComponent.isVisible() ? myAdComponent.getPreferredSize() : JBUI.emptySize();
    myAdComponent.setVisible(StringUtil.isNotEmpty(s));
    myAdComponent.setText(wrapToSize(s));
    myAdComponent.setHorizontalAlignment(alignment);

    Dimension newPrefSize = myAdComponent.isVisible() ? myAdComponent.getPreferredSize() : JBUI.emptySize();
    int delta = newPrefSize.height - prefSize.height;

    // Resize popup to match new advertiser size.
    if (myPopup != null && !isBusy() && delta != 0) {
      Window popupWindow = getContentWindow(myContent);
      if (popupWindow != null) {
        Dimension size = popupWindow.getSize();
        size.height += delta;
        myContent.setPreferredSize(size);
        popupWindow.pack();
        updateMaskAndAlpha(popupWindow);
      }
    }
  }

  @NotNull
  @Nls
  private String wrapToSize(@NotNull @Nls String hint) {<commit_msg>CWM-2232 Create a user flows to reflect CWM licensing ( Free, Premium, Enterprise)<commit_after>// Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.ui.popup;

import com.intellij.codeInsight.hint.HintUtil;
import com.intellij.icons.AllIcons;
import com.intellij.ide.*;
import com.intellij.ide.actions.WindowAction;
import com.intellij.ide.ui.PopupLocationTracker;
import com.intellij.ide.ui.ScreenAreaConsumer;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.MnemonicHelper;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.actionSystem.DataProvider;
import com.intellij.openapi.actionSystem.PlatformDataKeys;
import com.intellij.openapi.actionSystem.impl.ActionToolbarImpl;
import com.intellij.openapi.actionSystem.impl.AutoPopupSupportingListener;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.application.TransactionGuard;
import com.intellij.openapi.application.TransactionGuardImpl;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.EditorActivityManager;
import com.intellij.openapi.editor.ex.EditorEx;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectUtil;
import com.intellij.openapi.ui.popup.*;
import com.intellij.openapi.util.*;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.util.text.HtmlChunk;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.wm.*;
import com.intellij.openapi.wm.ex.WindowManagerEx;
import com.intellij.openapi.wm.impl.IdeGlassPaneImpl;
import com.intellij.ui.*;
import com.intellij.ui.awt.RelativePoint;
import com.intellij.ui.components.JBLabel;
import com.intellij.ui.mac.touchbar.TouchBarsManager;
import com.intellij.ui.scale.JBUIScale;
import com.intellij.ui.speedSearch.ListWithFilter;
import com.intellij.ui.speedSearch.SpeedSearch;
import com.intellij.util.*;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.WeakList;
import com.intellij.util.ui.*;
import com.intellij.util.ui.accessibility.AccessibleContextUtil;
import org.jetbrains.annotations.*;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.Supplier;

import static java.awt.event.MouseEvent.*;
import static java.awt.event.WindowEvent.WINDOW_ACTIVATED;
import static java.awt.event.WindowEvent.WINDOW_GAINED_FOCUS;

public class AbstractPopup implements JBPopup, ScreenAreaConsumer {
  @NonNls public static final String SHOW_HINTS = "ShowHints";

  // Popup size stored with DimensionService is null first time
  // In this case you can put Dimension in content client properties to adjust size
  // Zero or negative values (with/height or both) would be ignored (actual values would be obtained from preferred size)
  @NonNls public static final String FIRST_TIME_SIZE = "FirstTimeSize";

  private static final Logger LOG = Logger.getInstance(AbstractPopup.class);

  private PopupComponent myPopup;
  private MyContentPanel myContent;
  private JComponent myPreferredFocusedComponent;
  private boolean myRequestFocus;
  private boolean myFocusable;
  private boolean myForcedHeavyweight;
  private boolean myLocateWithinScreen;
  private boolean myResizable;
  private WindowResizeListener myResizeListener;
  private WindowMoveListener myMoveListener;
  private JPanel myHeaderPanel;
  private JPanel myBottomPanel;
  private CaptionPanel myCaption;
  private JComponent myComponent;
  private SpeedSearch mySpeedSearchFoundInRootComponent;
  private String myDimensionServiceKey;
  private Computable<Boolean> myCallBack;
  private Project myProject;
  private boolean myCancelOnClickOutside;
  private final List<JBPopupListener> myListeners = new CopyOnWriteArrayList<>();
  private boolean myUseDimServiceForXYLocation;
  private MouseChecker myCancelOnMouseOutCallback;
  private Canceller myMouseOutCanceller;
  private boolean myCancelOnWindow;
  private boolean myCancelOnWindowDeactivation = true;
  private Dimension myForcedSize;
  private Point myForcedLocation;
  private boolean myCancelKeyEnabled;
  private boolean myLocateByContent;
  private Dimension myMinSize;
  private List<Object> myUserData;
  private boolean myShadowed;

  private float myAlpha;
  private float myLastAlpha;

  private MaskProvider myMaskProvider;

  private Window myWindow;
  private boolean myInStack;
  private MyWindowListener myWindowListener;

  private boolean myModalContext;

  private Component[] myFocusOwners;
  private PopupBorder myPopupBorder;
  private Dimension myRestoreWindowSize;
  protected Component myOwner;
  private Component myRequestorComponent;
  private boolean myHeaderAlwaysFocusable;
  private boolean myMovable;
  private JComponent myHeaderComponent;
  private JComponent myBottomComponent;

  InputEvent myDisposeEvent;

  private Runnable myFinalRunnable;
  private Runnable myOkHandler;
  private @Nullable BooleanFunction<? super KeyEvent> myKeyEventHandler;

  protected boolean myOk;
  private final List<Runnable> myResizeListeners = new ArrayList<>();

  private static final WeakList<JBPopup> all = new WeakList<>();

  private boolean mySpeedSearchAlwaysShown;
  protected final SpeedSearch mySpeedSearch = new SpeedSearch() {
    boolean searchFieldShown;

    @Override
    public void update() {
      mySpeedSearchPatternField.getTextEditor().setBackground(UIUtil.getTextFieldBackground());
      onSpeedSearchPatternChanged();
      mySpeedSearchPatternField.setText(getFilter());
      if (!mySpeedSearchAlwaysShown) {
        if (isHoldingFilter() && !searchFieldShown) {
          setHeaderComponent(mySpeedSearchPatternField);
          searchFieldShown = true;
        }
        else if (!isHoldingFilter() && searchFieldShown) {
          setHeaderComponent(null);
          searchFieldShown = false;
        }
      }
    }

    @Override
    public void noHits() {
      mySpeedSearchPatternField.getTextEditor().setBackground(LightColors.RED);
    }
  };

  protected SearchTextField mySpeedSearchPatternField;
  private boolean myNativePopup;
  private boolean myMayBeParent;
  private JComponent myAdComponent;
  private boolean myDisposed;
  private boolean myNormalWindowLevel;

  private UiActivity myActivityKey;
  private Disposable myProjectDisposable;

  private volatile State myState = State.NEW;

  void setNormalWindowLevel(boolean normalWindowLevel) {
    myNormalWindowLevel = normalWindowLevel;
  }

  private enum State {NEW, INIT, SHOWING, SHOWN, CANCEL, DISPOSE}

  private void debugState(@NonNls @NotNull String message, State @NotNull ... states) {
    if (LOG.isDebugEnabled()) {
      LOG.debug(hashCode() + " - " + message);
      if (!ApplicationManager.getApplication().isDispatchThread()) {
        LOG.debug("unexpected thread");
      }
      for (State state : states) {
        if (state == myState) {
          return;
        }
      }
      LOG.debug(new IllegalStateException("myState=" + myState));
    }
  }

  protected AbstractPopup() { }

  protected @NotNull AbstractPopup init(Project project,
                                        @NotNull JComponent component,
                                        @Nullable JComponent preferredFocusedComponent,
                                        boolean requestFocus,
                                        boolean focusable,
                                        boolean movable,
                                        String dimensionServiceKey,
                                        boolean resizable,
                                        @NlsContexts.PopupTitle @Nullable String caption,
                                        @Nullable Computable<Boolean> callback,
                                        boolean cancelOnClickOutside,
                                        @NotNull Set<? extends JBPopupListener> listeners,
                                        boolean useDimServiceForXYLocation,
                                        ActiveComponent commandButton,
                                        @Nullable IconButton cancelButton,
                                        @Nullable MouseChecker cancelOnMouseOutCallback,
                                        boolean cancelOnWindow,
                                        @Nullable ActiveIcon titleIcon,
                                        boolean cancelKeyEnabled,
                                        boolean locateByContent,
                                        boolean placeWithinScreenBounds,
                                        @Nullable Dimension minSize,
                                        float alpha,
                                        @Nullable MaskProvider maskProvider,
                                        boolean inStack,
                                        boolean modalContext,
                                        Component @NotNull [] focusOwners,
                                        @Nullable @NlsContexts.PopupAdvertisement String adText,
                                        int adTextAlignment,
                                        boolean headerAlwaysFocusable,
                                        @NotNull List<? extends Pair<ActionListener, KeyStroke>> keyboardActions,
                                        Component settingsButtons,
                                        final @Nullable Processor<? super JBPopup> pinCallback,
                                        boolean mayBeParent,
                                        boolean showShadow,
                                        boolean showBorder,
                                        Color borderColor,
                                        boolean cancelOnWindowDeactivation,
                                        @Nullable BooleanFunction<? super KeyEvent> keyEventHandler) {
    assert !requestFocus || focusable : "Incorrect argument combination: requestFocus=true focusable=false";

    all.add(this);

    myActivityKey = new UiActivity.Focus("Popup:" + this);
    myProject = project;
    myComponent = component;
    mySpeedSearchFoundInRootComponent =
      findInComponentHierarchy(component, it -> it instanceof ListWithFilter ? ((ListWithFilter)it).getSpeedSearch() : null);
    myPopupBorder = showBorder ? borderColor != null ? PopupBorder.Factory.createColored(borderColor) :
                                 PopupBorder.Factory.create(true, showShadow) :
                                 PopupBorder.Factory.createEmpty();
    myShadowed = showShadow;
    myContent = createContentPanel(resizable, myPopupBorder, false);
    myMayBeParent = mayBeParent;
    myCancelOnWindowDeactivation = cancelOnWindowDeactivation;

    myContent.add(component, BorderLayout.CENTER);
    if (adText != null) {
      setAdText(adText, adTextAlignment);
    }

    myCancelKeyEnabled = cancelKeyEnabled;
    myLocateByContent = locateByContent;
    myLocateWithinScreen = placeWithinScreenBounds;
    myAlpha = alpha;
    myMaskProvider = maskProvider;
    myInStack = inStack;
    myModalContext = modalContext;
    myFocusOwners = focusOwners;
    myHeaderAlwaysFocusable = headerAlwaysFocusable;
    myMovable = movable;

    ActiveIcon actualIcon = titleIcon == null ? new ActiveIcon(EmptyIcon.ICON_0) : titleIcon;

    myHeaderPanel = new JPanel(new BorderLayout());
    myBottomPanel = new JPanel(new BorderLayout());

    if (caption != null) {
      if (!caption.isEmpty()) {
        myCaption = new TitlePanel(actualIcon.getRegular(), actualIcon.getInactive());
        ((TitlePanel)myCaption).setText(caption);
      }
      else {
        myCaption = new CaptionPanel();
      }

      if (pinCallback != null) {
        Icon icon = ToolWindowManager.getInstance(myProject != null ? myProject : ProjectUtil.guessCurrentProject((JComponent)myOwner))
          .getLocationIcon(ToolWindowId.FIND, AllIcons.General.Pin_tab);
        myCaption.setButtonComponent(new InplaceButton(
          new IconButton(IdeBundle.message("show.in.find.window.button.name"), icon),
          e -> pinCallback.process(this)
        ), JBUI.Borders.empty(4));
      }
      else if (cancelButton != null) {
        myCaption.setButtonComponent(new InplaceButton(cancelButton, e -> cancel()), JBUI.Borders.empty(4));
      }
      else if (commandButton != null) {
        myCaption.setButtonComponent(commandButton, null);
      }
    }
    else {
      myCaption = new CaptionPanel();
      myCaption.setBorder(null);
      myCaption.setPreferredSize(JBUI.emptySize());
    }

    setWindowActive(myHeaderAlwaysFocusable);

    myHeaderPanel.add(myCaption, BorderLayout.NORTH);
    myContent.add(myHeaderPanel, BorderLayout.NORTH);
    myContent.add(myBottomPanel, BorderLayout.SOUTH);

    myForcedHeavyweight = true;
    myResizable = resizable;
    myPreferredFocusedComponent = preferredFocusedComponent;
    myRequestFocus = requestFocus;
    myFocusable = focusable;
    myDimensionServiceKey = dimensionServiceKey;
    myCallBack = callback;
    myCancelOnClickOutside = cancelOnClickOutside;
    myCancelOnMouseOutCallback = cancelOnMouseOutCallback;
    myListeners.addAll(listeners);
    myUseDimServiceForXYLocation = useDimServiceForXYLocation;
    myCancelOnWindow = cancelOnWindow;
    myMinSize = minSize;

    if (Registry.is("ide.popup.horizontal.scroll.bar.opaque")) {
      forHorizontalScrollBar(bar -> bar.setOpaque(true));
    }

    for (Pair<ActionListener, KeyStroke> pair : keyboardActions) {
      myContent.registerKeyboardAction(pair.getFirst(), pair.getSecond(), JComponent.WHEN_IN_FOCUSED_WINDOW);
    }

    if (settingsButtons != null) {
      myCaption.addSettingsComponent(settingsButtons);
    }

    myKeyEventHandler = keyEventHandler;
    debugState("popup initialized", State.NEW);
    myState = State.INIT;
    return this;
  }

  private void setWindowActive(boolean active) {
    boolean value = myHeaderAlwaysFocusable || active;

    if (myCaption != null) {
      myCaption.setActive(value);
    }
    myPopupBorder.setActive(value);
    myContent.repaint();
  }


  protected @NotNull MyContentPanel createContentPanel(final boolean resizable, @NotNull PopupBorder border, boolean isToDrawMacCorner) {
    return new MyContentPanel(border);
  }

  public void setShowHints(boolean show) {
    final Window ancestor = getContentWindow(myComponent);
    if (ancestor instanceof RootPaneContainer) {
      final JRootPane rootPane = ((RootPaneContainer)ancestor).getRootPane();
      if (rootPane != null) {
        rootPane.putClientProperty(SHOW_HINTS, show);
      }
    }
  }

  public String getDimensionServiceKey() {
    return myDimensionServiceKey;
  }

  public void setDimensionServiceKey(final @Nullable String dimensionServiceKey) {
    myDimensionServiceKey = dimensionServiceKey;
  }

  public void setAdText(@NotNull @NlsContexts.PopupAdvertisement String s) {
    setAdText(s, SwingConstants.LEFT);
  }

  public @NotNull PopupBorder getPopupBorder() {
    return myPopupBorder;
  }

  @Override
  public void setAdText(@NotNull String s, int alignment) {
    JLabel label;
    if (myAdComponent == null || !(myAdComponent instanceof JLabel)) {
      label = HintUtil.createAdComponent(s, JBUI.CurrentTheme.Advertiser.border(), alignment);
      setFooterComponent(label);
    } else {
      label = (JLabel)myAdComponent;
    }

    label.setVisible(StringUtil.isNotEmpty(s));
    label.setText(wrapToSize(s));
    label.setHorizontalAlignment(alignment);
  }

  protected void setFooterComponent(JComponent c) {
    if (myAdComponent != null) {
      myContent.remove(myAdComponent);
    }

    myContent.add(c, BorderLayout.SOUTH);
    pack(false, true);
    myAdComponent = c;

    Dimension prefSize = myAdComponent.isVisible() ? myAdComponent.getPreferredSize() : JBUI.emptySize();

    Dimension newPrefSize = myAdComponent.isVisible() ? myAdComponent.getPreferredSize() : JBUI.emptySize();
    int delta = newPrefSize.height - prefSize.height;

    // Resize popup to match new advertiser size.
    if (myPopup != null && !isBusy() && delta != 0) {
      Window popupWindow = getContentWindow(myContent);
      if (popupWindow != null) {
        Dimension size = popupWindow.getSize();
        size.height += delta;
        myContent.setPreferredSize(size);
        popupWindow.pack();
        updateMaskAndAlpha(popupWindow);
      }
    }
  }

  @NotNull
  @Nls
  private String wrapToSize(@NotNull @Nls String hint) {
{'fraction_non_alphanumeric': 0.07899957914988276, 'fraction_numerical': 0.0009619431251127277, 'mean_word_length': 2.92855455833727, 'pattern_counts': {'":': 0, '<': 35, '<?xml version=': 0, '>': 43, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 82, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5629297', 'n_tokens_mistral': 8762, 'n_tokens_neox': 8594, 'n_words': 1920}