void () { myInstalledSearchGroup = new DefaultActionGroup(); for (InstalledSearchOption option : InstalledSearchOption.values()) { myInstalledSearchGroup.add(new InstalledSearchOptionAction(option)); } myInstalledTab = new PluginsTab() { @Override protected void createSearchTextField(int flyDelay) { super.createSearchTextField(flyDelay); JBTextField textField = mySearchTextField.getTextEditor(); textField.putClientProperty("search.extension", ExtendableTextComponent.Extension .create(AllIcons.Actions.More, AllIcons.Actions.More, IdeBundle.message("plugins.configurable.search.options"), // TODO: icon () -> showRightBottomPopup(textField, IdeBundle.message("plugins.configurable.show"), myInstalledSearchGroup))); textField.putClientProperty("JTextField.variant", null); textField.putClientProperty("JTextField.variant", "search"); mySearchTextField.setHistoryPropertyName("InstalledPluginsSearchHistory"); } @Override protected @NotNull PluginDetailsPageComponent createDetailsPanel(@NotNull LinkListener<Object> searchListener) { PluginDetailsPageComponent detailPanel = new PluginDetailsPageComponent(myPluginModel, searchListener, false); myPluginModel.addDetailPanel(detailPanel); return detailPanel; } @Override protected @NotNull JComponent createPluginsPanel(@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); } @Override protected void updateMainSelection(@NotNull Consumer<? super PluginsGroupComponent> selectionListener) { selectionListener.accept(myInstalledPanel); } @Override public void hideSearchPanel() { super.hideSearchPanel(); if (myInstalledSearchSetState) { for (AnAction action : myInstalledSearchGroup.getChildren(null)) { ((InstalledSearchOptionAction)action).setState(null); } } myPluginModel.setInvalidFixCallback(null); } @Override protected void onSearchReset() { PluginManagerUsageCollector.searchReset(); } @Override protected @NotNull SearchResultPanel createSearchPanel(@NotNull Consumer<? super PluginsGroupComponent> selectionListener) { SearchUpDownPopupController installedController = new SearchUpDownPopupController(mySearchTextField) { @Override protected @NotNull @NonNls List<String> getAttributes() { return Arrays .asList( "/downloaded", "/outdated", "/enabled", "/disabled", "/invalid", "/bundled", SearchWords.VENDOR.getValue(), SearchWords.TAG.getValue() ); } @Override protected @Nullable SortedSet<String> getValues(@NotNull String attribute) { return SearchWords.VENDOR.getValue().equals(attribute) ? myPluginModel.getVendors() : SearchWords.TAG.getValue().equals(attribute) ? myPluginModel.getTags() : null; } @Override protected void showPopupForQuery() { showSearchPanel(mySearchTextField.getText()); } }; MultiSelectionEventHandler eventHandler = new MultiSelectionEventHandler(); installedController.setSearchResultEventHandler(eventHandler); PluginsGroupComponent panel = new PluginsGroupComponent(eventHandler) { @Override protected @NotNull ListPluginComponent createListComponent(@NotNull IdeaPluginDescriptor descriptor, @NotNull PluginsGroup group) { return new ListPluginComponent(myPluginModel, descriptor, group, mySearchListener, false); } }; panel.setSelectionListener(selectionListener); registerCopyProvider(panel); myInstalledSearchCallback = updateAction -> { List<String> queries = new ArrayList<>(); new SearchQueryParser.Installed(mySearchTextField.getText()) { @Override protected void addToSearchQuery(@NotNull String query) { queries.add(query); } @Override protected void handleAttribute(@NotNull String name, @NotNull String value) { if (!updateAction.myState) { queries.add(name + (value.isEmpty() ? "" : SearchQueryParser.wrapAttribute(value))); } } }; if (updateAction.myState) { for (AnAction action : myInstalledSearchGroup.getChildren(null)) { if (action != updateAction) { ((InstalledSearchOptionAction)action).myState = false; } } queries.add(updateAction.getQuery()); } else { queries.remove(updateAction.getQuery()); } try { myInstalledSearchSetState = false; String query = StringUtil.join(queries, " "); mySearchTextField.setTextIgnoreEvents(query); if (query.isEmpty()) { myInstalledTab.hideSearchPanel(); } else { myInstalledTab.showSearchPanel(query); } } finally { myInstalledSearchSetState = true; } }; myInstalledSearchPanel = new SearchResultPanel(installedController, panel, false, 0, 0) { @Override protected void setEmptyText(@NotNull String query) { myPanel.getEmptyText().setText(IdeBundle.message("plugins.configurable.nothing.found")); if (query.contains("/downloaded") || query.contains("/outdated") || query.contains("/enabled") || query.contains("/disabled") || query.contains("/invalid") || query.contains("/bundled")) { return; } myPanel.getEmptyText().appendSecondaryText(IdeBundle.message("plugins.configurable.search.in.marketplace"), SimpleTextAttributes.LINK_PLAIN_ATTRIBUTES, e -> myTabHeaderComponent.setSelectionWithEvents(MARKETPLACE_TAB)); } @Override protected void handleQuery(@NotNull String query, @NotNull PluginsGroup result) { myPluginModel.setInvalidFixCallback(null); SearchQueryParser.Installed parser = new SearchQueryParser.Installed(query); if (myInstalledSearchSetState) { for (AnAction action : myInstalledSearchGroup.getChildren(null)) { ((InstalledSearchOptionAction)action).setState(parser); } } List<IdeaPluginDescriptor> descriptors = myPluginModel.getInstalledDescriptors(); if (!parser.vendors.isEmpty()) { for (Iterator<IdeaPluginDescriptor> I = descriptors.iterator(); I.hasNext(); ) { if (!MyPluginModel.isVendor(I.next(), parser.vendors)) { I.remove(); } } } if (!parser.tags.isEmpty()) { for (Iterator<IdeaPluginDescriptor> I = descriptors.iterator(); I.hasNext(); ) { if (!ContainerUtil.intersects(getTags(I.next()), parser.tags)) { I.remove(); } } } for (Iterator<IdeaPluginDescriptor> I = descriptors.iterator(); I.hasNext(); ) { IdeaPluginDescriptor descriptor = I.next(); if (parser.attributes) { if (parser.enabled && (!myPluginModel.isEnabled(descriptor) || myPluginModel.hasErrors(descriptor))) { I.remove(); continue; } if (parser.disabled && (myPluginModel.isEnabled(descriptor) || myPluginModel.hasErrors(descriptor))) { I.remove(); continue; } if (parser.bundled && !descriptor.isBundled()) { I.remove(); continue; } if (parser.downloaded && descriptor.isBundled()) { I.remove(); continue; } if (parser.invalid && !myPluginModel.hasErrors(descriptor)) { I.remove(); continue; } if (parser.needUpdate && !PluginUpdatesService.isNeedUpdate(descriptor)) { I.remove(); continue; } } if (parser.searchQuery != null && !containsQuery(descriptor, parser.searchQuery)) { I.remove(); } } result.descriptors.addAll(descriptors); PluginManagerUsageCollector.performInstalledTabSearch(ProjectUtil.getActiveProject(), parser, result.descriptors); if (!result.descriptors.isEmpty()) { if (parser.invalid) { myPluginModel.setInvalidFixCallback(() -> { PluginsGroup group = myInstalledSearchPanel.getGroup(); if (group.ui == null) { myPluginModel.setInvalidFixCallback(null); return; } PluginsGroupComponent resultPanel = myInstalledSearchPanel.getPanel(); for (IdeaPluginDescriptor descriptor : new ArrayList<>(group.descriptors)) { if (!myPluginModel.hasErrors(descriptor)) { resultPanel.removeFromGroup(group, descriptor); } } group.titleWithCount(); myInstalledSearchPanel.fullRepaint(); if (group.descriptors.isEmpty()) { myPluginModel.setInvalidFixCallback(null); myInstalledSearchPanel.removeGroup(); } }); } else if (parser.needUpdate) { result.rightAction = new LinkLabelButton<>(IdeBundle.message("plugin.manager.update.all"), null, (__, ___) -> { result.rightAction.setEnabled(false); for (ListPluginComponent plugin : result.ui.plugins) { plugin.updatePlugin(); } }); } Collection<IdeaPluginDescriptor> updates = PluginUpdatesService.getUpdates(); if (!ContainerUtil.isEmpty(updates)) { myPostFillGroupCallback = () -> { applyUpdates(myPanel, updates); selectionListener.accept(myInstalledPanel); }; } } } }; return myInstalledSearchPanel; } }; myPluginModel.setCancelInstallCallback(descriptor -> { if (myInstalledSearchPanel == null) { return; } PluginsGroup group = myInstalledSearchPanel.getGroup(); if (group.ui != null && group.ui.findComponent(descriptor) != null) { myInstalledSearchPanel.getPanel().removeFromGroup(group, descriptor); group.titleWithCount(); myInstalledSearchPanel.fullRepaint(); if (group.descriptors.isEmpty()) { myInstalledSearchPanel.removeGroup(); } } }); }