Start plugins wizard #19 usability improvements
authorVassiliy <vassiliy.kudryashov@jetbrains.com>
Mon, 21 Apr 2014 19:34:35 +0000 (23:34 +0400)
committerVassiliy <vassiliy.kudryashov@jetbrains.com>
Mon, 21 Apr 2014 19:35:20 +0000 (23:35 +0400)
platform/platform-impl/src/com/intellij/ide/customize/CustomizeFeaturedPluginsStepPanel.java
platform/platform-impl/src/com/intellij/ide/customize/CustomizeIDEWizardDialog.java
platform/platform-impl/src/com/intellij/ide/customize/CustomizePluginsStepPanel.java
platform/platform-impl/src/com/intellij/ide/customize/PluginGroups.java

index 186c7bdecb20240f1c09119673d5218abf3515c7..d3e340e3b1e2932b8b43029c2757239e6e01738c 100644 (file)
 package com.intellij.ide.customize;
 
 import com.intellij.CommonBundle;
+import com.intellij.icons.AllIcons;
 import com.intellij.ide.plugins.IdeaPluginDescriptor;
 import com.intellij.ide.plugins.PluginNode;
 import com.intellij.openapi.progress.util.ProgressIndicatorBase;
+import com.intellij.openapi.ui.VerticalFlowLayout;
 import com.intellij.openapi.updateSettings.impl.PluginDownloader;
+import com.intellij.ui.ColorUtil;
+import com.intellij.ui.JBColor;
+import com.intellij.ui.border.CustomLineBorder;
 import com.intellij.ui.components.JBScrollPane;
+import com.intellij.ui.components.labels.LinkLabel;
+import com.intellij.ui.components.labels.LinkListener;
 import com.intellij.util.ConcurrencyUtil;
 
 import javax.swing.*;
+import javax.swing.border.CompoundBorder;
 import java.awt.*;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
@@ -32,22 +40,29 @@ import java.util.Map;
 import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.ScheduledThreadPoolExecutor;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 public class CustomizeFeaturedPluginsStepPanel extends AbstractCustomizeWizardStep {
-  private static ScheduledExecutorService ourService = new ScheduledThreadPoolExecutor(4, ConcurrencyUtil.newNamedThreadFactory("FeaturedPlugins", true, Thread.NORM_PRIORITY));
+  private static final int COLS = 3;
+  private static ScheduledExecutorService ourService = new ScheduledThreadPoolExecutor(4, ConcurrencyUtil.newNamedThreadFactory(
+    "FeaturedPlugins", true, Thread.NORM_PRIORITY));
 
-  public CustomizeFeaturedPluginsStepPanel() {
-    setLayout(new GridLayout(0, 3, GAP, GAP));
-    JPanel gridPanel = new JPanel(new GridLayout(0, 3, GAP, GAP));
+  public final AtomicBoolean myCanceled = new AtomicBoolean(false);
+
+
+  public CustomizeFeaturedPluginsStepPanel() throws OfflineException {
+    setLayout(new GridLayout(1, 1));
+    JPanel gridPanel = new JPanel(new GridLayout(0, 3));
     JBScrollPane scrollPane =
       new JBScrollPane(gridPanel, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
     scrollPane.getVerticalScrollBar().setUnitIncrement(10);
 
     Map<String, String> config = PluginGroups.getInstance().getFeaturedPlugins();
+    boolean isEmptyOrOffline = true;
+    List<IdeaPluginDescriptor> pluginsFromRepository = PluginGroups.getInstance().getPluginsFromRepository();
     for (Map.Entry<String, String> entry : config.entrySet()) {
       JPanel groupPanel = new JPanel(new GridBagLayout());
       GridBagConstraints gbc = new GridBagConstraints();
-      gbc.insets = new Insets(0, 0, 10, 0);
       gbc.fill = GridBagConstraints.BOTH;
       gbc.anchor = GridBagConstraints.WEST;
       gbc.gridwidth = GridBagConstraints.REMAINDER;
@@ -61,10 +76,10 @@ public class CustomizeFeaturedPluginsStepPanel extends AbstractCustomizeWizardSt
       final String description = s.substring(i + 1, j);
       final String pluginId = s.substring(j + 1);
       IdeaPluginDescriptor foundDescriptor = null;
-      List<IdeaPluginDescriptor> pluginsFromRepository = PluginGroups.getInstance().getPluginsFromRepository();
       for (IdeaPluginDescriptor descriptor : pluginsFromRepository) {
         if (descriptor.getPluginId().getIdString().equals(pluginId)) {
           foundDescriptor = descriptor;
+          isEmptyOrOffline = false;
           break;
         }
       }
@@ -88,13 +103,26 @@ public class CustomizeFeaturedPluginsStepPanel extends AbstractCustomizeWizardSt
       final JButton installButton = new JButton("Install");
       final JProgressBar progressBar = new JProgressBar(0, 100);
       progressBar.setStringPainted(true);
-      buttonWrapper.add(installButton, "button");
-      buttonWrapper.add(progressBar, "progress");
+      JPanel progressPanel = new JPanel(new VerticalFlowLayout(true, false));
+      progressPanel.add(progressBar);
+      final LinkLabel cancelLink = new LinkLabel("Cancel", AllIcons.Actions.Cancel);
+      JPanel linkWrapper = new JPanel(new FlowLayout(FlowLayout.CENTER));
+      linkWrapper.add(cancelLink);
+      progressPanel.add(linkWrapper);
+
+      JPanel buttonPanel = new JPanel(new VerticalFlowLayout());
+      buttonPanel.add(installButton);
+
+      buttonWrapper.add(buttonPanel, "button");
+      buttonWrapper.add(progressPanel, "progress");
+
       wrapperLayout.show(buttonWrapper, "button");
 
       final ProgressIndicatorBase indicator = new ProgressIndicatorBase(true) {
+
         @Override
         public void start() {
+          myCanceled.set(false);
           super.start();
           SwingUtilities.invokeLater(new Runnable() {
             @Override
@@ -104,18 +132,15 @@ public class CustomizeFeaturedPluginsStepPanel extends AbstractCustomizeWizardSt
           });
         }
 
-        @Override
-        public void setIndeterminate(boolean indeterminate) {
-          super.setIndeterminate(indeterminate);
-        }
-
         @Override
         public void processFinish() {
           super.processFinish();
           SwingUtilities.invokeLater(new Runnable() {
             @Override
             public void run() {
-              progressBar.setString("Installed");
+              wrapperLayout.show(buttonWrapper, "button");
+              installButton.setEnabled(false);
+              installButton.setText("Installed");
             }
           });
         }
@@ -135,11 +160,14 @@ public class CustomizeFeaturedPluginsStepPanel extends AbstractCustomizeWizardSt
 
         @Override
         public void cancel() {
+          stop();
+          myCanceled.set(true);
           super.cancel();
           SwingUtilities.invokeLater(new Runnable() {
             @Override
             public void run() {
               wrapperLayout.show(buttonWrapper, "button");
+              progressBar.setValue(0);
             }
           });
         }
@@ -152,6 +180,7 @@ public class CustomizeFeaturedPluginsStepPanel extends AbstractCustomizeWizardSt
             @Override
             public void run() {
               try {
+                indicator.start();
                 PluginNode node = new PluginNode(descriptor.getPluginId());
                 node.setUrl(descriptor.getUrl());
                 PluginDownloader downloader = PluginDownloader.createDownloader(node);
@@ -160,7 +189,9 @@ public class CustomizeFeaturedPluginsStepPanel extends AbstractCustomizeWizardSt
                 indicator.processFinish();
               }
               catch (Exception ignored) {
-                onFail();
+                if (!myCanceled.get()) {
+                  onFail();
+                }
               }
             }
 
@@ -169,28 +200,48 @@ public class CustomizeFeaturedPluginsStepPanel extends AbstractCustomizeWizardSt
               SwingUtilities.invokeLater(new Runnable() {
                 @Override
                 public void run() {
+                  indicator.stop();
                   wrapperLayout.show(buttonWrapper, "progress");
                   progressBar.setString("Cannot download plugin");
                 }
               });
             }
           }, 0, TimeUnit.SECONDS);
-          //PluginGroups.getInstance().setFeaturedPluginEnabled(pluginId, installButton.isSelected());
         }
       });
+      cancelLink.setListener(new LinkListener() {
+        @Override
+        public void linkSelected(LinkLabel aSource, Object aLinkData) {
+          indicator.cancel();
+        }
+      }, null);
+      gbc.insets.bottom = -5;
       groupPanel.add(titleLabel, gbc);
+      gbc.insets.bottom = 10;
       groupPanel.add(topicLabel, gbc);
       groupPanel.add(descriptionLabel, gbc);
       gbc.weighty = 1;
       groupPanel.add(Box.createVerticalGlue(), gbc);
       gbc.weighty = 0;
       groupPanel.add(buttonWrapper, gbc);
-      gbc.weighty = 1;
-      groupPanel.add(Box.createVerticalGlue(), gbc);
-      groupPanel.setBorder(BorderFactory.createEmptyBorder(GAP, GAP, GAP, GAP));
       gridPanel.add(groupPanel);
     }
-    setLayout(new GridLayout(1, 1));
+    int cursor = 0;
+    Component[] components = gridPanel.getComponents();
+    int rowCount = components.length / COLS;
+    for (Component component : components) {
+      ((JComponent)component).setBorder(
+        new CompoundBorder(new CustomLineBorder(ColorUtil.withAlpha(JBColor.foreground(), .2), 0, 0, cursor / 3 < rowCount ? 1 : 0,
+                                                cursor % COLS != COLS - 1 ? 1 : 0) {
+          @Override
+          protected Color getColor() {
+            return ColorUtil.withAlpha(JBColor.foreground(), .2);
+          }
+        }, BorderFactory.createEmptyBorder(GAP, GAP, 0, GAP)));
+      cursor++;
+    }
+
+    if (isEmptyOrOffline) throw new OfflineException();
     add(scrollPane);
   }
 
@@ -210,4 +261,6 @@ public class CustomizeFeaturedPluginsStepPanel extends AbstractCustomizeWizardSt
   public String getHTMLFooter() {
     return "New plugins can also be downloaded in " + CommonBundle.settingsTitle() + " | Plugins";
   }
+
+  static class OfflineException extends Exception {};
 }
index 9b077846433bf8ab17be7ec8f6c92cffc21c8889..be3519eedff3afc4ea37a85232ebc0ac15d0650e 100644 (file)
@@ -70,7 +70,12 @@ public class CustomizeIDEWizardDialog extends DialogWrapper implements ActionLis
       mySteps.add(new CustomizeKeyboardSchemeStepPanel());
     }
     mySteps.add(new CustomizePluginsStepPanel());
-    mySteps.add(new CustomizeFeaturedPluginsStepPanel());
+    try {
+      mySteps.add(new CustomizeFeaturedPluginsStepPanel());
+    }
+    catch (CustomizeFeaturedPluginsStepPanel.OfflineException e) {
+      //skip featured step if we're offline
+    }
   }
 
   @Override
index 65b2987c85262805d8b6923ff5aedcc9b0110304..055a1d67e2cf5d89ed15af851f62d379212c95ee 100644 (file)
@@ -60,20 +60,19 @@ public class CustomizePluginsStepPanel extends AbstractCustomizeWizardStep imple
     add(scrollPane, MAIN);
     add(myCustomizePanel, CUSTOMIZE);
 
-    //PluginManager.loadDisabledPlugins(new File(PathManager.getConfigPath()).getPath(), myDisabledPluginIds);
-    //for (IdeaPluginDescriptor pluginDescriptor : myAllPlugins) {
-    //  if (pluginDescriptor.getPluginId().getIdString().equals("com.intellij")) {
-    ////    skip 'IDEA CORE' plugin
-        //continue;
-      //}
-    //  //PluginManager.initClassLoader(PluginGroups.class.getClassLoader(), (IdeaPluginDescriptorImpl)pluginDescriptor);
-    //}
     Map<String, List<String>> groups = PluginGroups.getInstance().getTree();
     for (Map.Entry<String, List<String>> entry : groups.entrySet()) {
       final String group = entry.getKey();
       if (PluginGroups.CORE.equals(group)) continue;
 
-      JPanel groupPanel = new JPanel(new GridBagLayout());
+      JPanel groupPanel = new JPanel(new GridBagLayout()) {
+        @Override
+        public Color getBackground() {
+          Color color = UIManager.getColor("Panel.background");
+          return isGroupEnabled(group)? color : ColorUtil.darker(color, 1);
+        }
+      };
+      gridPanel.setOpaque(true);
       GridBagConstraints gbc = new GridBagConstraints();
       gbc.insets = new Insets(0, 0, 10, 0);
       gbc.fill = GridBagConstraints.BOTH;
@@ -113,6 +112,7 @@ public class CustomizePluginsStepPanel extends AbstractCustomizeWizardStep imple
       }
       else {
         JPanel buttonsPanel = new JPanel(new GridLayout(1, 2, 10, 5));
+        buttonsPanel.setOpaque(false);
         LinkLabel customizeButton = createLink(CUSTOMIZE_COMMAND + ":" + group, CUSTOMIZE_TEXT_PROVIDER);
         buttonsPanel.add(customizeButton);
         LinkLabel disableAllButton = createLink(SWITCH_COMMAND + ":" + group, getGroupSwitchTextProvider(group));
@@ -213,22 +213,20 @@ public class CustomizePluginsStepPanel extends AbstractCustomizeWizardStep imple
     return null;
   }
 
-
-
-
-
-  private class IdSetPanel extends JPanel {
+  private class IdSetPanel extends JPanel implements LinkListener<String> {
     private JLabel myTitleLabel = new JLabel();
     private JPanel myContentPanel = new JPanel(new GridLayout(0, 3, 5, 5));
     private JButton mySaveButton = new JButton("Save Changes and Go Back");
+    private String myGroup;
 
     private IdSetPanel() {
       setLayout(new VerticalFlowLayout(VerticalFlowLayout.TOP, 0, GAP, true, false));
       add(myTitleLabel);
       add(myContentPanel);
-      JPanel buttonPanel = new JPanel(new BorderLayout());
-      buttonPanel.add(mySaveButton, BorderLayout.WEST);
-      buttonPanel.add(Box.createHorizontalGlue(), BorderLayout.CENTER);
+      JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.LEADING, 25, 5));
+      buttonPanel.add(mySaveButton);
+      buttonPanel.add(new LinkLabel<String>("Enable All", null, this, "enable"));
+      buttonPanel.add(new LinkLabel<String>("Disable All", null, this, "disable"));
       add(buttonPanel);
       mySaveButton.addActionListener(new ActionListener() {
         @Override
@@ -238,7 +236,19 @@ public class CustomizePluginsStepPanel extends AbstractCustomizeWizardStep imple
       });
     }
 
+    @Override
+    public void linkSelected(LinkLabel aSource, String command) {
+      if (myGroup == null) return;
+      boolean enable = "enable".equals(command);
+      List<IdSet> idSets = PluginGroups.getInstance().getSets(myGroup);
+      for (IdSet set : idSets) {
+        PluginGroups.getInstance().setIdSetEnabled(set, enable);
+      }
+      CustomizePluginsStepPanel.this.repaint();
+    }
+
     void update(String group) {
+      myGroup = group;
       myTitleLabel.setText("<html><body><h2 style=\"text-align:left;\">" + group + "</h2></body></html>");
       myContentPanel.removeAll();
       List<IdSet> idSets = PluginGroups.getInstance().getSets(group);
index c649cc1d0842b49d5abc897c7c2b032b4de8bf46..e3af6525cda506cb7240fb06b5712fbb815175c1 100644 (file)
@@ -32,7 +32,7 @@ import java.util.*;
 
 class PluginGroups {
   static final String CORE = "Core";
-  private static final int MAX_DESCR_LENGTH = 80;
+  private static final int MAX_DESCR_LENGTH = 50;
 
 
   private static PluginGroups instance = null;
@@ -62,7 +62,7 @@ class PluginGroups {
       myPluginsFromRepository.addAll(RepositoryHelper.loadPluginsFromRepository(null));
     }
     catch (Exception e) {
-      e.printStackTrace();
+      //OK, it's offline
     }
     PluginManager.loadDisabledPlugins(new File(PathManager.getConfigPath()).getPath(), myDisabledPluginIds);