/* * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.intellij.ide.startupWizard; import com.intellij.ide.plugins.IdeaPluginDescriptor; import com.intellij.openapi.extensions.PluginId; import com.intellij.openapi.options.ShowSettingsUtil; import com.intellij.openapi.util.text.StringUtil; import com.intellij.ui.ClickListener; import com.intellij.ui.CollectionListModel; import com.intellij.ui.wizard.WizardNavigationState; import com.intellij.ui.wizard.WizardStep; import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import java.awt.*; import java.awt.event.*; import java.util.ArrayList; import java.util.Collections; import java.util.List; /** * @author yole */ public class SelectPluginsStep extends WizardStep<StartupWizardModel> { private JPanel myRootPanel; private JList myPluginsList; private JTextPane myDescriptionArea; private JButton myEnableAllButton; private JButton myDisableAllButton; private final List<IdeaPluginDescriptor> myPlugins = new ArrayList<>(); private final StartupWizardModel myModel; private final String myRequirePlugin; private static final String[] ourSuffixes = new String[] { "integration", "support", "plugin" }; public SelectPluginsStep(@NotNull String title, @NotNull StartupWizardModel model, @Nullable String requirePlugin) { super(title, "Select the plugins to enable. Disabling unused plugins will improve IDE startup speed and performance.\n\nTo change plugin settings later, go to " + ShowSettingsUtil.getSettingsMenuName() + " | Plugins.", null); myModel = model; myRequirePlugin = requirePlugin; myPluginsList.setCellRenderer(new ListCellRenderer() { private final JCheckBox myCheckbox = new JCheckBox(); public Component getListCellRendererComponent(final JList list, final Object value, final int index, final boolean isSelected, final boolean cellHasFocus) { IdeaPluginDescriptor descriptor = (IdeaPluginDescriptor)value; myCheckbox.setEnabled(!myModel.isForceEnable(descriptor)); if (isSelected) { myCheckbox.setBackground(UIUtil.getListSelectionBackground()); myCheckbox.setForeground(UIUtil.getListSelectionForeground()); } else { myCheckbox.setBackground(UIUtil.getListBackground()); myCheckbox.setForeground(UIUtil.getListForeground()); } myCheckbox.setText(getAbbreviatedName(descriptor) + buildRequires(descriptor)); myCheckbox.setSelected(!myModel.isDisabledPlugin(descriptor)); return myCheckbox; } }); myPluginsList.addListSelectionListener(new ListSelectionListener() { public void valueChanged(final ListSelectionEvent e) { final IdeaPluginDescriptor pluginDescriptor = getSelectedPlugin(); if (pluginDescriptor != null) { final String description = pluginDescriptor.getDescription(); myDescriptionArea.setText(description == null || description.startsWith("<") ? description : UIUtil.toHtml(description, 5)); myDescriptionArea.moveCaretPosition(0); } else { myDescriptionArea.setText(UIUtil.toHtml("Select a plugin to see its description")); } } }); final int clickableArea = new JCheckBox("").getMinimumSize().width; new ClickListener() { @Override public boolean onClick(@NotNull MouseEvent e, int clickCount) { if (e.getX() < clickableArea) { toggleSelection(); } return true; } }.installOn(myPluginsList); myPluginsList.addKeyListener(new KeyAdapter() { public void keyTyped(final KeyEvent e) { if (e.getKeyChar() == ' ') { toggleSelection(); } } }); myEnableAllButton.addActionListener(new ActionListener() { public void actionPerformed(final ActionEvent e) { setAllPluginsEnabled(true); } }); myDisableAllButton.addActionListener(new ActionListener() { public void actionPerformed(final ActionEvent e) { setAllPluginsEnabled(false); } }); } private String buildRequires(final IdeaPluginDescriptor descriptor) { StringBuilder requiresBuffer = new StringBuilder(); for (PluginId id : StartupWizardModel.getNonOptionalDependencies(descriptor)) { final IdeaPluginDescriptor dependent = findPlugin(id); if (dependent != null) { String name = getAbbreviatedName(dependent); if (requiresBuffer.length() == 0) { requiresBuffer.append(" (requires "); } else { requiresBuffer.append(", "); } requiresBuffer.append(name); } } List<IdeaPluginDescriptor> requiredBy = myModel.getDependentsOnEarlierPages(descriptor, false); if (requiredBy.size() > 0) { if (requiresBuffer.length() > 0) { requiresBuffer.append(", "); } else { requiresBuffer.append(" ("); } requiresBuffer.append("required by "); requiresBuffer.append(StringUtil.join(requiredBy, ideaPluginDescriptor -> getAbbreviatedName(ideaPluginDescriptor), ", ")); } if (requiresBuffer.length() > 0) { requiresBuffer.append(")"); } return requiresBuffer.toString(); } private static String getAbbreviatedName(final IdeaPluginDescriptor descriptor) { final String name = descriptor.getName(); for (String suffix : ourSuffixes) { if (name.toLowerCase().endsWith(suffix)) { return name.substring(0, name.length() - suffix.length()).trim(); } } return name; } private void toggleSelection() { final IdeaPluginDescriptor descriptor = getSelectedPlugin(); if (descriptor == null || myModel.isForceEnable(descriptor)) return; boolean willDisable = !myModel.isDisabledPlugin(descriptor); final Object[] selection = myPluginsList.getSelectedValues(); for (Object o : selection) { IdeaPluginDescriptor desc = (IdeaPluginDescriptor) o; if (!willDisable) { myModel.setPluginEnabledWithDependencies(desc); } else { myModel.setPluginDisabledWithDependents(desc); } } myPluginsList.repaint(); } private void setAllPluginsEnabled(boolean value) { for(IdeaPluginDescriptor descriptor: myPlugins) { if (!value && myModel.isForceEnable(descriptor)) { continue; } myModel.setPluginEnabled(descriptor, value); } myPluginsList.repaint(); } @Nullable private IdeaPluginDescriptor findPlugin(final PluginId id) { for (IdeaPluginDescriptor plugin : myPlugins) { if (plugin.getPluginId().equals(id)) { return plugin; } } return null; } @Nullable private IdeaPluginDescriptor getSelectedPlugin() { final int leadSelectionIndex = myPluginsList.getSelectionModel().getLeadSelectionIndex(); return (leadSelectionIndex < 0) ? null : myPlugins.get(leadSelectionIndex); } public JComponent prepare(final WizardNavigationState state) { myRootPanel.revalidate(); myPluginsList.requestFocusInWindow(); return myRootPanel; } public void addPlugin(final IdeaPluginDescriptor pluginDescriptor) { myPlugins.add(pluginDescriptor); } public void fillPlugins() { Collections.sort(myPlugins, (o1, o2) -> StringUtil.compare(o1.getName(), o2.getName(), true)); myPluginsList.setModel(new CollectionListModel(myPlugins)); myPluginsList.setSelectedIndex(0); } @Nullable public String getRequirePlugin() { return myRequirePlugin; } public List<IdeaPluginDescriptor> getPlugins() { return myPlugins; } @Override public WizardStep onNext(final StartupWizardModel model) { final WizardStep next = super.onNext(model); if (next instanceof SelectPluginsStep) { final SelectPluginsStep selectPluginsStep = (SelectPluginsStep)next; final String id = selectPluginsStep.getRequirePlugin(); if (id != null && model.getDisabledPluginIds().contains(id) && !model.isLast(next)) { for (IdeaPluginDescriptor descriptor: selectPluginsStep.getPlugins()) { model.getDisabledPluginIds().add(descriptor.getPluginId().getIdString()); } return model.getNextFor(next); } } return next; } @Override public WizardStep onPrevious(final StartupWizardModel model) { final WizardStep prev = super.onPrevious(model); if (prev instanceof SelectPluginsStep) { final SelectPluginsStep selectPluginsStep = (SelectPluginsStep)prev; final String id = selectPluginsStep.getRequirePlugin(); if (id != null && model.getDisabledPluginIds().contains(id) && !model.isFirst(prev)) { return model.getPreviousFor(prev); } } return prev; } @Override public JComponent getPreferredFocusedComponent() { return myPluginsList; } @Override public String getHelpId() { return "plugin.configuration.wizard"; } }