blob: d1343f6e7ad7bdccdbeb6227cc82e477c6bc686e [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.netbeans.modules.ide.ergonomics.fod;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import static java.util.Objects.nonNull;
import java.util.Set;
import java.util.concurrent.Callable;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.GroupLayout;
import javax.swing.GroupLayout.Alignment;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComponent;
import javax.swing.JEditorPane;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.LayoutStyle.ComponentPlacement;
import javax.swing.SwingUtilities;
import org.netbeans.api.autoupdate.UpdateElement;
import org.netbeans.api.progress.ProgressHandle;
import org.netbeans.api.progress.ProgressHandleFactory;
import org.openide.awt.Mnemonics;
import org.openide.util.Exceptions;
import org.openide.util.NbBundle;
import org.openide.util.RequestProcessor.Task;
import org.openide.util.TaskListener;
import org.openide.modules.ModuleInfo;
import org.openide.modules.SpecificationVersion;
import org.openide.util.Lookup;
/**
* Provider for fake web module extenders. Able to download and enable the
* proper module as well as delegate to the proper configuration panel.
*
* @author Tomas Mysik
* @author Pavel Flaska
*/
public class ConfigurationPanel extends JPanel {
private static final long serialVersionUID = 27938464212508L;
final DownloadProgressMonitor progressMonitor = new DownloadProgressMonitor();
private FeatureInfo featureInfo;
private Callable<JComponent> callable;
private Collection<UpdateElement> featureInstall;
private final SpecificationVersion jdk = new SpecificationVersion(System.getProperty("java.specification.version"));
private HashSet<FeatureInfo.ExtraModuleInfo> extrasFilter;
public ConfigurationPanel(String displayName, final Callable<JComponent> callable, FeatureInfo info) {
this(callable);
setInfo(info, displayName, Collections.<UpdateElement>emptyList(), Collections.emptyList(), Collections.emptyMap(), false);
}
public ConfigurationPanel(final Callable<JComponent> callable) {
assert EventQueue.isDispatchThread();
initComponents();
this.featureInfo = null;
this.callable = callable;
setError(" "); // NOI18N
}
public void setInfo(FeatureInfo info, String displayName, Collection<UpdateElement> toInstall,
Collection<FeatureInfo.ExtraModuleInfo> missingModules,
Map<FeatureInfo.ExtraModuleInfo, FeatureInfo> extrasMap, boolean required) {
this.extrasFilter = new HashSet<>();
this.featureInfo = info;
this.featureInstall = toInstall;
boolean activateNow = toInstall.isEmpty() && missingModules.isEmpty();
Set<FeatureInfo.ExtraModuleInfo> extraModules = featureInfo.getExtraModules();
Collection<? extends ModuleInfo> lookupAll = Lookup.getDefault().lookupAll(ModuleInfo.class);
FindComponentModules findModules = new FindComponentModules(info);
Collection<UpdateElement> modulesToInstall = findModules.getModulesForInstall();
selectionsPanel.removeAll();
for (FeatureInfo.ExtraModuleInfo extraModule : extraModules) {
JCheckBox jCheckBox = new JCheckBox(extraModule.displayName());
for (ModuleInfo moduleInfo : lookupAll) {
if (extraModule.matches(moduleInfo.getCodeName())) {
jCheckBox.setText(moduleInfo.getDisplayName());
}
}
for (UpdateElement updateElement : modulesToInstall) {
if (extraModule.matches(updateElement.getCodeName())){
jCheckBox.setText(updateElement.getDisplayName());
}
}
if (extraModule.isRequiredFor(jdk)) {
jCheckBox.setSelected(true);
// jCheckBox.setEnabled(false);
extrasFilter.add(extraModule);
}
jCheckBox.addActionListener(e -> {
if (jCheckBox.isSelected()) {
extrasFilter.add(extraModule);
} else {
extrasFilter.remove(extraModule);
}
});
selectionsPanel.add(jCheckBox);
}
if (activateNow) {
infoLabel.setVisible(false);
downloadLabel.setVisible(false);
activateButton.setVisible(false);
downloadButton.setVisible(false);
activateButtonActionPerformed(null);
} else {
FeatureManager.logUI("ERGO_QUESTION", featureInfo.clusterName, displayName);
infoLabel.setVisible(true);
downloadLabel.setVisible(true);
activateButton.setVisible(true);
downloadButton.setVisible(true);
// collect descriptions from features contributing installed extras
List<String> downloadStringList = collectExtraModulesTextsFromFeatures(extrasMap.values(), required);
String lblDownloadMsg = generateDownloadMessageFromExtraModulesTexts(downloadStringList);
if (required) {
activateButton.setEnabled(false);
} else {
activateButton.setEnabled(true);
}
if (!missingModules.isEmpty()) {
StringBuilder sb = new StringBuilder();
for (FeatureInfo.ExtraModuleInfo s : missingModules) {
if (sb.length() > 0) {
sb.append(", "); // NOI18N
}
sb.append(s.displayName());
}
String list = sb.toString();
if (required) {
lblDownloadMsg = NbBundle.getMessage(ConfigurationPanel.class, "MSG_MissingRequiredModules", displayName, list);
activateButton.setEnabled(false);
} else {
lblDownloadMsg = NbBundle.getMessage(ConfigurationPanel.class, "MSG_MissingRecommendedModules", displayName, list);
}
downloadButton.setEnabled(false);
} else {
downloadButton.setEnabled(true);
}
String lblActivateMsg = NbBundle.getMessage(ConfigurationPanel.class, "LBL_EnableInfo", displayName);
String btnActivateMsg = NbBundle.getMessage(ConfigurationPanel.class, "LBL_Enable");
String btnDownloadMsg = NbBundle.getMessage(ConfigurationPanel.class, "LBL_Download");
org.openide.awt.Mnemonics.setLocalizedText(infoLabel, lblActivateMsg);
org.openide.awt.Mnemonics.setLocalizedText(activateButton, btnActivateMsg);
org.openide.awt.Mnemonics.setLocalizedText(downloadLabel, lblDownloadMsg);
org.openide.awt.Mnemonics.setLocalizedText(downloadButton, btnDownloadMsg);
}
}
/**
* Collect extra modules texts
*/
protected List<String> collectExtraModulesTextsFromFeatures(Collection<FeatureInfo> features, boolean required) {
List<String> descriptionsList = new ArrayList<>();
for (FeatureInfo fi : features) {
String s = required ? fi.getExtraModulesRequiredText(): fi.getExtraModulesRecommendedText();
if (nonNull(s) && !descriptionsList.contains(s)) {
descriptionsList.add(s);
}
}
return descriptionsList;
}
/**
* Generate download message from extra modules texts
* @param extraModulesTexts
* @return String Text to set in download label
*/
protected String generateDownloadMessageFromExtraModulesTexts(List<String> extraModulesTexts) {
StringBuilder sbDownload = new StringBuilder();
if (!extraModulesTexts.isEmpty()) {
sbDownload.append("<html><body>");
for (int i = 0; i < extraModulesTexts.size(); i++) {
sbDownload.append(extraModulesTexts.get(i));
if (extraModulesTexts.size() > 1 && i < extraModulesTexts.size() - 1) {
sbDownload.append("<br>");
}
}
sbDownload.append("</body></html>");
}
return sbDownload.toString();
}
@Override
public void removeNotify() {
super.removeNotify();
FeatureManager.logUI("ERGO_CLOSE");
}
public void setUpdateErrors(Collection<IOException> errors) {
if (errors.isEmpty()) {
return;
}
StringBuilder sb = new StringBuilder();
sb.append("<html>"); // NOI18N
for (IOException ex : errors) {
sb.append("<br/>"); // NOI18N
sb.append(ex.getLocalizedMessage());
}
sb.append("</html>"); // NOI18N
String updateError = NbBundle.getMessage(ConfigurationPanel.class, "ERR_UpdateComponents", sb.toString());
SwingUtilities.invokeLater(() -> {
remove(errorLabel);
progressPanel.removeAll();
progressPanel.add(errorLabel);
setError(updateError);
progressPanel.revalidate();
progressPanel.repaint();
});
}
void setError(String msg) {
assert SwingUtilities.isEventDispatchThread();
errorLabel.setText(msg);
}
/**
* This method is called from within the constructor to initialize the form.
* - * WARNING: Do NOT modify this code. The content of this method is
* always regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
errorLabel = BrokenProjectInfo.getErrorPane("dummy");
infoLabel = new JLabel();
activateButton = new JButton();
progressPanel = new JPanel();
downloadLabel = new JLabel();
downloadButton = new JButton();
selectionsPanel = new JPanel();
Mnemonics.setLocalizedText(infoLabel, "dummy"); // NOI18N
Mnemonics.setLocalizedText(activateButton, "dummy"); // NOI18N
activateButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
activateButtonActionPerformed(evt);
}
});
progressPanel.setLayout(new BoxLayout(progressPanel, BoxLayout.PAGE_AXIS));
Mnemonics.setLocalizedText(downloadLabel, NbBundle.getMessage(ConfigurationPanel.class, "ConfigurationPanel.downloadLabel.text")); // NOI18N
Mnemonics.setLocalizedText(downloadButton, NbBundle.getMessage(ConfigurationPanel.class, "ConfigurationPanel.downloadButton.text")); // NOI18N
downloadButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
downloadButtonActionPerformed(evt);
}
});
selectionsPanel.setLayout(new BoxLayout(selectionsPanel, BoxLayout.PAGE_AXIS));
GroupLayout layout = new GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(layout.createParallelGroup(Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(Alignment.LEADING)
.addComponent(progressPanel, GroupLayout.DEFAULT_SIZE, 374, Short.MAX_VALUE)
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(Alignment.LEADING)
.addComponent(errorLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
.addGroup(layout.createSequentialGroup()
.addComponent(downloadButton)
.addPreferredGap(ComponentPlacement.RELATED)
.addComponent(activateButton))
.addComponent(downloadLabel)
.addComponent(infoLabel)
.addComponent(selectionsPanel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
.addGap(0, 0, Short.MAX_VALUE)))
.addContainerGap())
);
layout.setVerticalGroup(layout.createParallelGroup(Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(errorLabel, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
.addPreferredGap(ComponentPlacement.RELATED)
.addComponent(infoLabel)
.addPreferredGap(ComponentPlacement.UNRELATED)
.addComponent(downloadLabel)
.addPreferredGap(ComponentPlacement.RELATED)
.addComponent(selectionsPanel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
.addPreferredGap(ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(Alignment.BASELINE)
.addComponent(activateButton)
.addComponent(downloadButton))
.addGap(19, 19, 19)
.addComponent(progressPanel, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addContainerGap())
);
}// </editor-fold>//GEN-END:initComponents
private void activateButtonActionPerformed(ActionEvent evt) {//GEN-FIRST:event_activateButtonActionPerformed
FeatureManager.logUI("ERGO_DOWNLOAD");
activateButton.setEnabled(false);
downloadButton.setEnabled(false);
selectionsPanel.setEnabled(false);
Task task = FeatureManager.getInstance().create(() -> {
ModulesInstaller.activateModules(false, progressMonitor, featureInfo, featureInstall, extrasFilter);
});
task.addTaskListener(onActivationFinished());
task.schedule(0);
}//GEN-LAST:event_activateButtonActionPerformed
private void downloadButtonActionPerformed(ActionEvent evt) {//GEN-FIRST:event_downloadButtonActionPerformed
FeatureManager.logUI("ERGO_DOWNLOAD");
activateButton.setEnabled(false);
downloadButton.setEnabled(false);
selectionsPanel.setEnabled(false);
Task task = FeatureManager.getInstance().create(() -> {
ModulesInstaller.activateModules(true, progressMonitor, featureInfo, Collections.emptyList(), extrasFilter);
});
task.addTaskListener(onActivationFinished());
task.schedule(0);
}//GEN-LAST:event_downloadButtonActionPerformed
private TaskListener onActivationFinished() {
return (task) -> {
if (!progressMonitor.error) {
SwingUtilities.invokeLater(new Runnable() {
private String msg;
public void run() {
ConfigurationPanel.this.removeAll();
ConfigurationPanel.this.setLayout(new BorderLayout());
try {
ConfigurationPanel.this.add(callable.call(), BorderLayout.CENTER);
} catch (Exception ex) {
// TODO: add warning panel
Exceptions.printStackTrace(ex);
}
ConfigurationPanel.this.invalidate();
ConfigurationPanel.this.revalidate();
ConfigurationPanel.this.repaint();
if (featureInfo != null && featureInfo.isPresent()) {
msg = NbBundle.getMessage(ConfigurationPanel.class, "MSG_EnableFailed");
} else {
msg = NbBundle.getMessage(ConfigurationPanel.class, "MSG_DownloadFailed");
}
setError(msg);
activateButton.setEnabled(true);
progressPanel.removeAll();
progressPanel.revalidate();
progressPanel.repaint();
}
});
}
};
}
// Variables declaration - do not modify//GEN-BEGIN:variables
private JButton activateButton;
private JButton downloadButton;
private JLabel downloadLabel;
private JEditorPane errorLabel;
private JLabel infoLabel;
private JPanel progressPanel;
private JPanel selectionsPanel;
// End of variables declaration//GEN-END:variables
private final class DownloadProgressMonitor implements ProgressMonitor {
boolean error = false;
public void onDownload(ProgressHandle progressHandle) {
updateProgress(progressHandle);
}
public void onValidate(ProgressHandle progressHandle) {
updateProgress(progressHandle);
}
public void onInstall(ProgressHandle progressHandle) {
updateProgress(progressHandle);
}
public void onEnable(ProgressHandle progressHandle) {
updateProgress(progressHandle);
}
private void updateProgress(final ProgressHandle progressHandle) {
final JLabel tmpMainLabel = ProgressHandleFactory.createMainLabelComponent(progressHandle);
final JComponent tmpProgressPanel = ProgressHandleFactory.createProgressComponent(progressHandle);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
progressPanel.removeAll();
progressPanel.add(tmpMainLabel);
progressPanel.add(Box.createRigidArea(new Dimension(0, 5)));
progressPanel.add(tmpProgressPanel);
progressPanel.revalidate();
progressPanel.repaint();
}
});
}
public void onError(final String message) {
error = true;
SwingUtilities.invokeLater(new Runnable() {
public void run() {
// TODO: mark as html
setError("<html>" + message + "</html>"); // NOI18N
progressPanel.removeAll();
progressPanel.add(errorLabel);
}
});
}
}
}