JComponent (@NotNull Consumer<? super PluginsGroupComponent> selectionListener) { MultiSelectionEventHandler eventHandler = new MultiSelectionEventHandler(); myInstalledPanel = new PluginsGroupComponent(eventHandler) { @Override protected @NotNull ListPluginComponent createListComponent(@NotNull IdeaPluginDescriptor descriptor, @NotNull PluginsGroup group) { return new ListPluginComponent(myPluginModel, descriptor, group, mySearchListener, false); } }; myInstalledPanel.setSelectionListener(selectionListener); myInstalledPanel.getAccessibleContext().setAccessibleName(IdeBundle.message("plugin.manager.installed.panel.accessible.name")); registerCopyProvider(myInstalledPanel); //noinspection ConstantConditions ((SearchUpDownPopupController)myInstalledSearchPanel.controller).setEventHandler(eventHandler); try { PluginLogo.startBatchMode(); PluginsGroup installing = new PluginsGroup(IdeBundle.message("plugins.configurable.installing"), PluginsGroupType.INSTALLING); installing.descriptors.addAll(MyPluginModel.getInstallingPlugins()); if (!installing.descriptors.isEmpty()) { installing.sortByName(); installing.titleWithCount(); myInstalledPanel.addGroup(installing); } PluginsGroup downloaded = new PluginsGroup(IdeBundle.message("plugins.configurable.downloaded"), PluginsGroupType.INSTALLED); downloaded.descriptors.addAll(InstalledPluginsState.getInstance().getInstalledPlugins()); Map<Boolean, List<IdeaPluginDescriptorImpl>> visiblePlugins = PluginManager .getVisiblePlugins(RegistryManager.getInstance().is("plugins.show.implementation.details")) .collect(Collectors.partitioningBy(IdeaPluginDescriptorImpl::isBundled)); List<IdeaPluginDescriptorImpl> nonBundledPlugins = visiblePlugins.get(Boolean.FALSE); downloaded.descriptors.addAll(nonBundledPlugins); LinkListener<Object> updateAllListener = new LinkListener<>() { @Override public void linkSelected(LinkLabel<Object> aSource, Object aLinkData) { myUpdateAll.setEnabled(false); myUpdateAllBundled.setEnabled(false); for (UIPluginGroup group : getInstalledGroups()) { if (group.excluded) { continue; } for (ListPluginComponent plugin : group.plugins) { plugin.updatePlugin(); } } } }; myUpdateAll.setListener(updateAllListener, null); downloaded.addRightAction(myUpdateAll); downloaded.addRightAction(myUpdateCounter); if (!downloaded.descriptors.isEmpty()) { downloaded.sortByName(); long enabledNonBundledCount = nonBundledPlugins.stream() .map(IdeaPluginDescriptorImpl::getPluginId) .filter(descriptor -> !PluginManagerCore.isDisabled(descriptor)) .count(); downloaded.titleWithCount(Math.toIntExact(enabledNonBundledCount)); myInstalledPanel.addGroup(downloaded); myPluginModel.addEnabledGroup(downloaded); } myPluginModel.setDownloadedGroup(myInstalledPanel, downloaded, installing); String defaultCategory = IdeBundle.message("plugins.configurable.other.bundled"); visiblePlugins.get(Boolean.TRUE) .stream() .collect(Collectors.groupingBy(descriptor -> StringUtil.defaultIfEmpty(descriptor.getDisplayCategory(), defaultCategory))) .entrySet() .stream() .map(entry -> new ComparablePluginsGroup(entry.getKey(), entry.getValue())) .sorted((o1, o2) -> defaultCategory.equals(o1.title) ? 1 : defaultCategory.equals(o2.title) ? -1 : o1.compareTo(o2)) .forEachOrdered(group -> { myInstalledPanel.addGroup(group); myPluginModel.addEnabledGroup(group); }); myUpdateAllBundled.setListener(updateAllListener, null); myBundledUpdateGroup.addRightAction(myUpdateAllBundled); myBundledUpdateGroup.addRightAction(myUpdateCounterBundled); myPluginUpdatesService.calculateUpdates(updates -> { if (ContainerUtil.isEmpty(updates)) { clearUpdates(myInstalledPanel); clearUpdates(myInstalledSearchPanel.getPanel()); } else { applyUpdates(myInstalledPanel, updates); applyUpdates(myInstalledSearchPanel.getPanel(), updates); } applyBundledUpdates(updates); selectionListener.accept(myInstalledPanel); }); } finally { PluginLogo.endBatchMode(); } return createScrollPane(myInstalledPanel, true); }