From eb51bdbceaef913b5cd67a0743879f4e30ff5cd1 Mon Sep 17 00:00:00 2001 From: Eugene Petrenko Date: Wed, 18 Dec 2019 15:35:10 +0100 Subject: [PATCH] SdkListModelBuilder - refactor actions processing, avoid side-effects GitOrigin-RevId: 75dccb4e9d39fb78657d57f1f1d6f5a2cd8e948d --- .../roots/ui/configuration/JdkComboBox.java | 18 ++- .../ui/configuration/SdkComboBoxBase.java | 8 -- .../roots/ui/configuration/SdkListItem.java | 29 +---- .../ui/configuration/SdkListModelBuilder.java | 113 +++++++++++------- .../ui/configuration/SdkPopupFactory.java | 14 +-- .../projectRoot/ProjectSdksModel.java | 67 +++++++---- .../darcula/ui/DarculaJBPopupComboPopup.java | 5 +- .../intellij/ui/popup/list/ComboBoxPopup.java | 23 ++-- 8 files changed, 151 insertions(+), 126 deletions(-) diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/JdkComboBox.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/JdkComboBox.java index 961579c26e58..4852ae19cdd0 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/JdkComboBox.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/JdkComboBox.java @@ -108,12 +108,6 @@ public class JdkComboBox extends SdkComboBoxBase { reloadModel(); } - @Override - protected void onNewSdkAdded(@NotNull Sdk sdk) { - setSelectedJdk(sdk); - myOnNewSdkAdded.consume(sdk); - } - @Override protected void onModelUpdated(@NotNull SdkListModel model) { Object previousSelection = getSelectedItem(); @@ -260,7 +254,7 @@ public class JdkComboBox extends SdkComboBoxBase { } private void resolveSuggestionsIfNeeded() { - myModel.reloadActions(this, getSelectedJdk()); + myModel.reloadActions(); DialogWrapper dialogWrapper = DialogWrapper.findInstance(this); if (dialogWrapper == null) { @@ -293,10 +287,12 @@ public class JdkComboBox extends SdkComboBoxBase { if (anObject instanceof InnerComboBoxItem) { SdkListItem item = ((InnerComboBoxItem)anObject).getItem(); - if (item instanceof SdkListItem.ActionableItem) { - ((SdkListItem.ActionableItem)item).executeAction(); - return; - } + if (myModel.executeAction(this, item, newItem -> { + setSelectedItem(newItem); + if (newItem instanceof SdkItem) { + myOnNewSdkAdded.consume(((SdkItem)newItem).getSdk()); + } + })) return; } if (anObject instanceof SelectableComboBoxItem) { diff --git a/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/SdkComboBoxBase.java b/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/SdkComboBoxBase.java index ce83aeeabe65..c47f8575236e 100644 --- a/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/SdkComboBoxBase.java +++ b/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/SdkComboBoxBase.java @@ -2,7 +2,6 @@ package com.intellij.openapi.roots.ui.configuration; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.ui.ComboBox; import com.intellij.util.ui.JBUI; import com.intellij.util.ui.UIUtil; @@ -22,11 +21,6 @@ public abstract class SdkComboBoxBase extends ComboBox { public void syncModel(@NotNull SdkListModel model) { SdkComboBoxBase.this.onModelUpdated(model); } - - @Override - public void onNewSdkAdded(@NotNull Sdk sdk) { - SdkComboBoxBase.this.onNewSdkAdded(sdk); - } }); UIUtil.putClientProperty(this, ANIMATION_IN_RENDERER_ALLOWED, true); @@ -38,8 +32,6 @@ public abstract class SdkComboBoxBase extends ComboBox { protected abstract void onModelUpdated(@NotNull SdkListModel model); - protected abstract void onNewSdkAdded(@NotNull Sdk sdk); - public void setInvalidJdk(String name) { setSelectedItem(myModel.setInvalidSdk(name)); } diff --git a/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/SdkListItem.java b/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/SdkListItem.java index cbae448abd54..d0724cdbb74d 100644 --- a/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/SdkListItem.java +++ b/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/SdkListItem.java @@ -16,10 +16,6 @@ import java.util.Objects; public abstract class SdkListItem { private SdkListItem() {} - public interface ActionableItem { - void executeAction(); - } - public static abstract class SdkItem extends SdkListItem { private final Sdk mySdk; @@ -93,7 +89,7 @@ public abstract class SdkListItem { } } - public static abstract class SuggestedItem extends SdkListItem implements ActionableItem { + public static final class SuggestedItem extends SdkListItem { private final SdkType mySdkType; private final String myHomePath; private final String myVersion; @@ -118,20 +114,16 @@ public abstract class SdkListItem { public String getVersion() { return myVersion; } - - @Override - public abstract void executeAction(); } enum ActionRole { DOWNLOAD, ADD } - public static abstract class ActionItem extends SdkListItem implements ActionableItem { - @Nullable - final GroupItem myGroup; - final ActionRole myRole; - final NewSdkAction myAction; + public static final class ActionItem extends SdkListItem { + @Nullable final GroupItem myGroup; + @NotNull final ActionRole myRole; + @NotNull final NewSdkAction myAction; ActionItem(@NotNull ActionRole role, @NotNull NewSdkAction action, @Nullable GroupItem group) { myRole = role; @@ -141,17 +133,8 @@ public abstract class SdkListItem { @NotNull ActionItem withGroup(@NotNull GroupItem group) { - ActionItem that = this; - return new ActionItem(myRole, myAction, group) { - @Override - public void executeAction() { - that.executeAction(); - } - }; + return new ActionItem(myRole, myAction, group); } - - @Override - public abstract void executeAction(); } public static final class GroupItem extends SdkListItem { diff --git a/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/SdkListModelBuilder.java b/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/SdkListModelBuilder.java index 684874a514ba..40f79fb89146 100644 --- a/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/SdkListModelBuilder.java +++ b/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/SdkListModelBuilder.java @@ -3,10 +3,9 @@ package com.intellij.openapi.roots.ui.configuration; import com.google.common.collect.ImmutableList; import com.intellij.icons.AllIcons; -import com.intellij.ide.DataManager; import com.intellij.openapi.Disposable; -import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.application.ModalityState; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.projectRoots.SdkType; @@ -30,12 +29,13 @@ import java.util.Map; import java.util.Objects; public class SdkListModelBuilder { + private static final Logger LOG = Logger.getInstance(SdkListModelBuilder.class); + @Nullable private final Project myProject; @NotNull private final ProjectSdksModel mySdkModel; @NotNull private final Condition mySdkFilter; @NotNull private final Condition mySdkTypeFilter; @NotNull private final Condition mySdkTypeCreationFilter; - @NotNull private final Consumer myOnNewSdkAdded; @NotNull private final EventDispatcher myModelListener = EventDispatcher.create(ModelListener.class); @@ -68,9 +68,6 @@ public class SdkListModelBuilder { mySdkFilter = sdk -> sdk != null && mySdkTypeFilter.value(sdk.getSdkType()) && (sdkFilter == null || sdkFilter.value(sdk)); - myOnNewSdkAdded = sdk -> { - if (sdk != null) myModelListener.getMulticaster().onNewSdkAdded(sdk); - }; } /** @@ -84,11 +81,6 @@ public class SdkListModelBuilder { * into a specific model and apply it for the control */ default void syncModel(@NotNull SdkListModel model) {} - - /** - * A callback executed when a new Sdk was created and added - */ - default void onNewSdkAdded(@NotNull Sdk sdk) {} } public void addModelListener(@NotNull ModelListener listener) { @@ -99,8 +91,11 @@ public class SdkListModelBuilder { myModelListener.removeListener(listener); } - private void syncModel() { - myModelListener.getMulticaster().syncModel(buildModel()); + @NotNull + private SdkListModel syncModel() { + SdkListModel model = buildModel(); + myModelListener.getMulticaster().syncModel(model); + return model; } @NotNull @@ -183,24 +178,70 @@ public class SdkListModelBuilder { for (Sdk sdk : sortSdks(mySdkModel.getSdks())) { if (!mySdkFilter.value(sdk)) continue; - newHead.add(new SdkItem(sdk) { - @Override - boolean hasSameSdk(@NotNull Sdk value) { - return Objects.equals(getSdk(), value) || Objects.equals(mySdkModel.findSdk(getSdk()), value); - } - }); + newHead.add(newSdkItem(sdk)); } myHead = newHead.build(); syncModel(); } - public void reloadActions(@NotNull JComponent parent, @Nullable Sdk selectedSdk) { - Map downloadActions = mySdkModel.createDownloadActions(parent, selectedSdk, myOnNewSdkAdded, mySdkTypeCreationFilter); - Map addActions = mySdkModel.createAddActions(parent, selectedSdk, myOnNewSdkAdded, mySdkTypeCreationFilter); + @NotNull + private SdkItem newSdkItem(@NotNull Sdk sdk) { + return new SdkItem(sdk) { + @Override + boolean hasSameSdk(@NotNull Sdk value) { + return Objects.equals(getSdk(), value) || Objects.equals(mySdkModel.findSdk(getSdk()), value); + } + }; + } - myDownloadActions = createActions(parent, ActionRole.DOWNLOAD, downloadActions); - myAddActions = createActions(parent, ActionRole.ADD, addActions); + /** + * Executes an action that is associated with the given {@param item}. + *
+ * If there are no actions associated, method returns {@code false}, + * the {@param afterExecution} is NOT executed + *
+ * If there is action associated, it is scheduled for execution. The + * {@param afterExecution} callback is ONLY if the action execution + * ended up successfully and a new item was added to the model. In that + * case the callback is executed after the model is updated and the + * {@link #syncModel()} is invoked. The implementation may not + * execute the callback or and model update for any internal and + * non-selectable items + * + * @return {@code true} if action was started and the {@param afterExecution} + * callback could happen later, {@code false} otherwise + */ + public boolean executeAction(@NotNull JComponent parent, + @NotNull SdkListItem item, + @NotNull Consumer afterExecution) { + Consumer onNewSdkAdded = sdk -> { + reloadSdks(); + SdkItem sdkItem = newSdkItem(sdk); + afterExecution.consume(sdkItem); + }; + + if (item instanceof ActionItem) { + NewSdkAction action = ((ActionItem)item).myAction; + action.actionPerformed(null, parent, onNewSdkAdded); + return true; + } + + if (item instanceof SuggestedItem) { + SuggestedItem suggestedItem = (SuggestedItem)item; + mySdkModel.addSdk(suggestedItem.getSdkType(), suggestedItem.getHomePath(), onNewSdkAdded); + return true; + } + + return false; + } + + public void reloadActions() { + Map downloadActions = mySdkModel.createDownloadActions(mySdkTypeCreationFilter); + Map addActions = mySdkModel.createAddActions(mySdkTypeCreationFilter); + + myDownloadActions = createActions(ActionRole.DOWNLOAD, downloadActions); + myAddActions = createActions(ActionRole.ADD, addActions); syncModel(); } @@ -218,12 +259,7 @@ public class SdkListModelBuilder { @Override public void onSdkDetected(@NotNull SdkType type, @NotNull String version, @NotNull String home) { - SuggestedItem item = new SuggestedItem(type, version, home) { - @Override - public void executeAction() { - mySdkModel.addSdk(getSdkType(), getHomePath(), myOnNewSdkAdded); - } - }; + SuggestedItem item = new SuggestedItem(type, version, home); mySuggestions = ImmutableList.builder() .addAll(mySuggestions) @@ -242,24 +278,11 @@ public class SdkListModelBuilder { } @NotNull - private static ImmutableList createActions(@NotNull JComponent parent, - @NotNull ActionRole role, + private static ImmutableList createActions(@NotNull ActionRole role, @NotNull Map actions) { ImmutableList.Builder builder = ImmutableList.builder(); for (NewSdkAction action : actions.values()) { - builder.add(new ActionItem(role, action, null) { - @Override - public void executeAction() { - DataContext dataContext = DataManager.getInstance().getDataContext(parent); - AnActionEvent event = new AnActionEvent(null, - dataContext, - ActionPlaces.UNKNOWN, - new Presentation(""), - ActionManager.getInstance(), - 0); - myAction.actionPerformed(event); - } - }); + builder.add(new ActionItem(role, action, null)); } return builder.build(); } diff --git a/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/SdkPopupFactory.java b/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/SdkPopupFactory.java index d5b43431ccdc..c2a1b5385865 100644 --- a/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/SdkPopupFactory.java +++ b/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/SdkPopupFactory.java @@ -17,7 +17,6 @@ import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.awt.*; import java.util.Collections; -import java.util.function.Consumer; public class SdkPopupFactory { private final SdkListModelBuilder myModelBuilder; @@ -35,11 +34,10 @@ public class SdkPopupFactory { @NotNull public SdkPopup createPopup(@NotNull SdkPopupListener listener) { SdkListItemContext context = new SdkListItemContext(); + SdkPopupImpl popup = new SdkPopupImpl(context); - SdkPopupImpl popup = new SdkPopupImpl(context, value -> { - if (value instanceof SdkListItem.ActionableItem) { - ((SdkListItem.ActionableItem)value).executeAction(); - //TODO: handle the outcome of the action execution here + popup.addItemSelectedListener(value -> { + if (myModelBuilder.executeAction(popup.getList(), value, listener::onNewItemAdded)) { return; } listener.onExistingItemSelected(value); @@ -58,7 +56,7 @@ public class SdkPopupFactory { popup.addListener(new JBPopupListener() { @Override public void beforeShown(@NotNull LightweightWindowEvent event) { - myModelBuilder.reloadActions(popup.getList(), null); + myModelBuilder.reloadActions(); myModelBuilder.detectItems(popup.getList(), popup); } @@ -73,8 +71,8 @@ public class SdkPopupFactory { } private class SdkPopupImpl extends ComboBoxPopup implements SdkPopup { - SdkPopupImpl(SdkListItemContext context, Consumer onItemSelected) { - super(context, null, onItemSelected); + SdkPopupImpl(SdkListItemContext context) { + super(context, null); } @Override diff --git a/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/projectRoot/ProjectSdksModel.java b/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/projectRoot/ProjectSdksModel.java index c163ff405584..f5d64e5367c9 100644 --- a/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/projectRoot/ProjectSdksModel.java +++ b/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/projectRoot/ProjectSdksModel.java @@ -1,7 +1,6 @@ // Copyright 2000-2018 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.openapi.roots.ui.configuration.projectRoot; -import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.DefaultActionGroup; import com.intellij.openapi.application.ApplicationManager; @@ -246,17 +245,17 @@ public class ProjectSdksModel implements SdkModel { @NotNull final Consumer updateTree, @Nullable Condition filter) { - Map downloadActions = createDownloadActions(parent, selectedSdk, updateTree, filter); - Map defaultAddActions = createAddActions(parent, selectedSdk, updateTree, filter); + Map downloadActions = createDownloadActions(filter); + Map defaultAddActions = createAddActions(filter); for (SdkType type : getAddableSdkTypes(filter)) { - AnAction downloadAction = downloadActions.get(type); + NewSdkAction downloadAction = downloadActions.get(type); if (downloadAction != null) { - group.add(downloadAction); + group.add(downloadAction.setOverrides(selectedSdk, parent, updateTree)); } - AnAction defaultAction = defaultAddActions.get(type); + NewSdkAction defaultAction = defaultAddActions.get(type); if (defaultAction != null) { - group.add(defaultAction); + group.add(defaultAction.setOverrides(selectedSdk, parent, updateTree)); } } } @@ -264,6 +263,10 @@ public class ProjectSdksModel implements SdkModel { public static abstract class NewSdkAction extends DumbAwareAction { private final SdkType mySdkType; + private Sdk mySelectedSdkOverride; + private JComponent myParentOverride; + private Consumer myCallbackOverride; + private NewSdkAction(@NotNull SdkType sdkType, @Nls(capitalization = Nls.Capitalization.Title) @Nullable String text, @Nullable Icon icon) { @@ -272,16 +275,37 @@ public class ProjectSdksModel implements SdkModel { } @NotNull - public SdkType getSdkType() { + NewSdkAction setOverrides(@Nullable Sdk selectedSdkFallback, + @NotNull JComponent parentFallback, + @NotNull Consumer callbackFallback) { + mySelectedSdkOverride = selectedSdkFallback; + myParentOverride = parentFallback; + myCallbackOverride = callbackFallback; + return this; + } + + @NotNull + public final SdkType getSdkType() { return mySdkType; } + + @Override + public final void actionPerformed(@NotNull AnActionEvent e) { + Sdk selectedSdk = mySelectedSdkOverride; + JComponent parent = myParentOverride; + Consumer callback = myCallbackOverride; + + if (callback == null || parent == null) return; + actionPerformed(selectedSdk, parent, callback); + } + + public abstract void actionPerformed(@Nullable Sdk selectedSdk, + @NotNull JComponent parent, + @NotNull Consumer callback); } @NotNull - public Map createDownloadActions(@NotNull final JComponent parent, - @Nullable final Sdk selectedSdk, - @NotNull final Consumer updateTree, - @Nullable Condition filter) { + public Map createDownloadActions(@Nullable Condition filter) { Map result = new LinkedHashMap<>(); for (final SdkType type : getAddableSdkTypes(filter)) { SdkDownload downloadExtension = SdkDownload.EP_NAME.findFirstSafe(it -> it.supportsDownload(type)); @@ -290,8 +314,10 @@ public class ProjectSdksModel implements SdkModel { String downloadText = ProjectBundle.message("sdk.configure.download.action", type.getPresentableName()); NewSdkAction downloadAction = new NewSdkAction(type, downloadText, downloadExtension.getIconForDownloadAction(type)) { @Override - public void actionPerformed(@NotNull AnActionEvent e) { - doDownload(downloadExtension, parent, selectedSdk, type, updateTree); + public void actionPerformed(@Nullable Sdk selectedSdk, + @NotNull JComponent parent, + @NotNull Consumer callback) { + doDownload(downloadExtension, parent, selectedSdk, type, callback); } }; @@ -301,21 +327,20 @@ public class ProjectSdksModel implements SdkModel { } @NotNull - public Map createAddActions(@NotNull final JComponent parent, - @Nullable final Sdk selectedSdk, - @NotNull final Consumer updateTree, - @Nullable Condition filter) { + public Map createAddActions(@Nullable Condition filter) { Map result = new LinkedHashMap<>(); for (final SdkType type : getAddableSdkTypes(filter)) { String addOnDiskText = ProjectBundle.message("sdk.configure.add.default.action", type.getPresentableName()); NewSdkAction addAction = new NewSdkAction(type, addOnDiskText, type.getIconForAddAction()) { @Override - public void actionPerformed(@NotNull AnActionEvent e) { + public void actionPerformed(@Nullable Sdk selectedSdk, + @NotNull JComponent parent, + @NotNull Consumer callback) { if (type.supportsCustomCreateUI()) { - type.showCustomCreateUI(ProjectSdksModel.this, parent, selectedSdk, sdk -> setupSdk(sdk, updateTree)); + type.showCustomCreateUI(ProjectSdksModel.this, parent, selectedSdk, sdk -> setupSdk(sdk, callback)); } else { - SdkConfigurationUtil.selectSdkHome(type, home -> addSdk(type, home, updateTree)); + SdkConfigurationUtil.selectSdkHome(type, home -> addSdk(type, home, callback)); } } }; diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaJBPopupComboPopup.java b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaJBPopupComboPopup.java index 59d901911eb8..d7664b0bf806 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaJBPopupComboPopup.java +++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaJBPopupComboPopup.java @@ -3,8 +3,6 @@ package com.intellij.ide.ui.laf.darcula.ui; import com.intellij.ide.DataManager; import com.intellij.openapi.actionSystem.CommonDataKeys; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.popup.JBPopupListener; import com.intellij.openapi.ui.popup.LightweightWindowEvent; @@ -87,7 +85,7 @@ public class DarculaJBPopupComboPopup implements ComboPopup, ComboBoxPopup.Co //noinspection unchecked T selectedItem = (T)myComboBox.getSelectedItem(); - myPopup = new ComboBoxPopup(this, selectedItem, value -> myComboBox.setSelectedItem(value)) { + myPopup = new ComboBoxPopup(this, selectedItem) { @Override public void cancel(InputEvent e) { if (e instanceof MouseEvent) { @@ -100,6 +98,7 @@ public class DarculaJBPopupComboPopup implements ComboPopup, ComboBoxPopup.Co super.cancel(e); } }; + myPopup.addItemSelectedListener(value -> myComboBox.setSelectedItem(value)); myPopup.addListener(new JBPopupListener() { @Override public void beforeShown(@NotNull LightweightWindowEvent event) { diff --git a/platform/platform-impl/src/com/intellij/ui/popup/list/ComboBoxPopup.java b/platform/platform-impl/src/com/intellij/ui/popup/list/ComboBoxPopup.java index 07de717017bd..ccf059645e8c 100644 --- a/platform/platform-impl/src/com/intellij/ui/popup/list/ComboBoxPopup.java +++ b/platform/platform-impl/src/com/intellij/ui/popup/list/ComboBoxPopup.java @@ -10,6 +10,7 @@ import com.intellij.ui.SimpleColoredComponent; import com.intellij.ui.TitledSeparator; import com.intellij.ui.components.JBList; import com.intellij.ui.popup.WizardPopup; + import java.util.function.Consumer; import com.intellij.util.ui.JBUI; import org.jetbrains.annotations.NotNull; @@ -27,9 +28,8 @@ public class ComboBoxPopup extends ListPopupImpl { private final Context myContext; public ComboBoxPopup(@NotNull Context context, - @Nullable T selectedItem, - @NotNull Consumer onItemSelected) { - this(context, null, popupStateFromContext(context, onItemSelected, selectedItem), null); + @Nullable T selectedItem) { + this(context, null, popupStateFromContext(context, selectedItem), null); } private ComboBoxPopup(@NotNull Context context, @@ -41,11 +41,15 @@ public class ComboBoxPopup extends ListPopupImpl { configurePopup(); } + public void addItemSelectedListener(@NotNull Consumer callback) { + //noinspection unchecked + ((MyBasePopupState)getStep()).addItemSelectedListener(callback); + } + @NotNull private static MyBasePopupState popupStateFromContext(@NotNull Context context, - @NotNull Consumer onItemSelected, @Nullable Object selectedItem) { - MyBasePopupState step = new MyBasePopupState(onItemSelected, + MyBasePopupState step = new MyBasePopupState(t -> {}, () -> context.getModel(), () -> context.getRenderer()) { @Override @@ -173,7 +177,7 @@ public class ComboBoxPopup extends ListPopupImpl { private static class MyBasePopupState extends BaseListPopupStep { private final JBList myProxyList = new JBList<>(); - private final Consumer myOnItemSelected; + private Consumer myOnItemSelected; private final Supplier> myGetComboboxModel; private final Supplier> myGetRenderer; @@ -186,6 +190,10 @@ public class ComboBoxPopup extends ListPopupImpl { myGetRenderer = getRenderer; } + private void addItemSelectedListener(@NotNull Consumer callback) { + myOnItemSelected = myOnItemSelected.andThen(callback); + } + @Nullable @Override @SuppressWarnings("rawtypes") @@ -195,7 +203,8 @@ public class ComboBoxPopup extends ListPopupImpl { //noinspection unchecked ListModel nextModel = ((ComboBoxPopupState)model).onChosen(selectedValue); if (nextModel != null) { - return new MyBasePopupState<>(myOnItemSelected, () -> nextModel, myGetRenderer); + return new MyBasePopupState<>(t -> myOnItemSelected.accept(t) /* mutable callback! */, + () -> nextModel, myGetRenderer); } }