blob: 498391b8e9713406dced72f64e103b99430cf234 [file] [log] [blame]
/*
* Copyright 2000-2014 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.customize;
import com.intellij.CommonBundle;
import com.intellij.icons.AllIcons;
import com.intellij.ide.plugins.IdeaPluginDescriptor;
import com.intellij.ide.plugins.PluginManagerCore;
import com.intellij.ide.plugins.PluginNode;
import com.intellij.openapi.options.OptionsBundle;
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;
import java.util.List;
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 final int COLS = 3;
private static ScheduledExecutorService ourService = new ScheduledThreadPoolExecutor(4, ConcurrencyUtil.newNamedThreadFactory(
"FeaturedPlugins", true, Thread.NORM_PRIORITY));
public final AtomicBoolean myCanceled = new AtomicBoolean(false);
public CustomizeFeaturedPluginsStepPanel(PluginGroups pluginGroups) 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);
scrollPane.setBorder(null);
Map<String, String> config = pluginGroups.getFeaturedPlugins();
boolean isEmptyOrOffline = true;
List<IdeaPluginDescriptor> pluginsFromRepository = pluginGroups.getPluginsFromRepository();
for (Map.Entry<String, String> entry : config.entrySet()) {
JPanel groupPanel = new JPanel(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.fill = GridBagConstraints.BOTH;
gbc.anchor = GridBagConstraints.WEST;
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.weightx = 1;
String title = entry.getKey();
String s = entry.getValue();
int i = s.indexOf(":");
String topic = s.substring(0, i);
int j = s.indexOf(":", i + 1);
final String description = s.substring(i + 1, j);
final String pluginId = s.substring(j + 1);
IdeaPluginDescriptor foundDescriptor = null;
for (IdeaPluginDescriptor descriptor : pluginsFromRepository) {
if (descriptor.getPluginId().getIdString().equals(pluginId) && !PluginManagerCore.isBrokenPlugin(descriptor)) {
foundDescriptor = descriptor;
isEmptyOrOffline = false;
break;
}
}
if (foundDescriptor == null) continue;
final IdeaPluginDescriptor descriptor = foundDescriptor;
JLabel titleLabel = new JLabel("<html><body><h2 style=\"text-align:left;\">" + title + "</h2></body></html>");
JLabel topicLabel = new JLabel("<html><body><h4 style=\"text-align:left;\">" + topic + "</h4></body></html>");
JLabel descriptionLabel = new JLabel("<html><body><i>" + description + "</i></body></html>") {
@Override
public Dimension getPreferredSize() {
Dimension size = super.getPreferredSize();
size.width = Math.min(size.width, 200);
return size;
}
};
final CardLayout wrapperLayout = new CardLayout();
final JPanel buttonWrapper = new JPanel(wrapperLayout);
final JButton installButton = new JButton("Install");
final JProgressBar progressBar = new JProgressBar(0, 100);
progressBar.setStringPainted(true);
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, 0, 0));
linkWrapper.add(cancelLink);
progressPanel.add(linkWrapper);
JPanel buttonPanel = new JPanel(new VerticalFlowLayout(0, 0));
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
public void run() {
wrapperLayout.show(buttonWrapper, "progress");
}
});
}
@Override
public void processFinish() {
super.processFinish();
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
wrapperLayout.show(buttonWrapper, "button");
installButton.setEnabled(false);
installButton.setText("Installed");
}
});
}
@Override
public void setFraction(final double fraction) {
super.setFraction(fraction);
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
int value = (int)(100 * fraction + .5);
progressBar.setValue(value);
progressBar.setString(value + "%");
}
});
}
@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);
}
});
}
};
installButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
wrapperLayout.show(buttonWrapper, "progress");
ourService.schedule(new Runnable() {
@Override
public void run() {
try {
indicator.start();
PluginNode node = new PluginNode(descriptor.getPluginId());
node.setUrl(descriptor.getUrl());
PluginDownloader downloader = PluginDownloader.createDownloader(node);
downloader.prepareToInstall(indicator);
downloader.install();
indicator.processFinish();
}
catch (Exception ignored) {
if (!myCanceled.get()) {
onFail();
}
}
}
void onFail() {
//noinspection SSBasedInspection
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
indicator.stop();
wrapperLayout.show(buttonWrapper, "progress");
progressBar.setString("Cannot download plugin");
}
});
}
}, 0, TimeUnit.SECONDS);
}
});
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 = SMALL_GAP;
groupPanel.add(topicLabel, gbc);
groupPanel.add(descriptionLabel, gbc);
gbc.weighty = 1;
groupPanel.add(Box.createVerticalGlue(), gbc);
gbc.weighty = 0;
groupPanel.add(buttonWrapper, gbc);
gridPanel.add(groupPanel);
}
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(0, SMALL_GAP, 0, SMALL_GAP)));
cursor++;
}
if (isEmptyOrOffline) throw new OfflineException();
add(scrollPane);
}
@Override
public String getTitle() {
return "Featured plugins";
}
@Override
public String getHTMLHeader() {
return "<html><body><h2>Download featured plugins</h2>" +
"We have a few plugins in our repository that most users like to download. " +
"Perhaps, you need them too?</body></html>";
}
@Override
public String getHTMLFooter() {
return "New plugins can also be downloaded in "
+ CommonBundle.settingsTitle()
+ " | " + OptionsBundle.message("configurable.group.appearance.settings.display.name")
+ " | " + "Plugins";
}
public static class OfflineException extends Exception {};
}