/*
* RapidMiner
*
* Copyright (C) 2001-2014 by RapidMiner and the contributors
*
* Complete list of developers available at our web site:
*
* http://rapidminer.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see http://www.gnu.org/licenses/.
*/
package com.rapid_i.deployment.update.client;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JEditorPane;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.ScrollPaneConstants;
import javax.swing.SwingUtilities;
import javax.swing.event.HyperlinkEvent;
import javax.swing.event.HyperlinkListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import com.itextpdf.text.Font;
import com.rapidminer.deployment.client.wsimport.PackageDescriptor;
import com.rapidminer.deployment.client.wsimport.UpdateService;
import com.rapidminer.gui.tools.ExtendedJScrollPane;
import com.rapidminer.gui.tools.ResourceAction;
import com.rapidminer.gui.tools.ResourceLabel;
import com.rapidminer.gui.tools.SwingTools;
import com.rapidminer.gui.tools.dialogs.ButtonDialog;
import com.rapidminer.tools.I18N;
import com.rapidminer.tools.RMUrlHandler;
/**
* @author Venkatesh Umaashankar
*
*/
public class ConfirmLicensesDialog extends ButtonDialog {
private static final long serialVersionUID = 4276757146820898347L;
private JButton okButton;
private JEditorPane licensePane = new JEditorPane("text/html", "");
private static final int LIST_WIDTH = 330;
private JList selectedForInstallList;
private JList dependentPackages;
private ResourceLabel licenseLabel;
private Map<String, String> licenseNameToLicenseTextMap;
private static String LOADING_LICENSE_TEXT = "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">"
+ "<html xmlns=\"http://www.w3.org/1999/xhtml\" dir=\"ltr\" lang=\"en\" xml:lang=\"en\">" + "<head>" + "<table cellpadding=0 cellspacing=0>" + "<tr><td>"
+ "<img src=\"" + SwingTools.getIconPath("48/hourglass.png") + "\" /></td>" + "<td width=\"5\">" + "</td>" + "<td>" + I18N.getGUILabel("loading_license") + "</td></tr>" + "</table>" + "</head>" + "</html>";
private static String ERROR_LOADING_LICENSE_TEXCT = "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">"
+ "<html xmlns=\"http://www.w3.org/1999/xhtml\" dir=\"ltr\" lang=\"en\" xml:lang=\"en\">" + "<head>" + "<table cellpadding=0 cellspacing=0>" + "<tr><td>"
+ "<img src=\"" + SwingTools.getIconPath("48/error.png") + "\" /></td>" + "<td width=\"5\">" + "</td>" + "<td>" + I18N.getGUILabel("error_loading_license") + "</td></tr>" + "</table>" + "</head>" + "</html>";
// this variable checks if license loading has failed.
// If so we cannot allow the user to install the packages because he hasn't seen the license
private boolean licenseLoadingFailed = true;
private JCheckBox acceptReject;
public ConfirmLicensesDialog(HashMap<PackageDescriptor, HashSet<PackageDescriptor>> dependency, HashMap<String, String> licenseNameToLicenseTextMap) {
super("confirm_licenses", "updates");
setModal(true);
if (licenseNameToLicenseTextMap != null) {
this.licenseNameToLicenseTextMap = licenseNameToLicenseTextMap;
licenseLoadingFailed = false;
} else {
this.licenseNameToLicenseTextMap = new HashMap<String, String>();
}
JPanel main = new JPanel(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
c.fill = GridBagConstraints.BOTH;
c.anchor = GridBagConstraints.FIRST_LINE_START;
c.weightx = 0;
c.weighty = 1;
c.gridwidth = GridBagConstraints.RELATIVE;
c.gridx = 0;
c.weighty = 0;
c.insets = new Insets(0, 0, 2, 0);
ResourceLabel label = new ResourceLabel("selected_packages");
label.setFont(label.getFont().deriveFont(Font.BOLD));
main.add(label, c);
Set<PackageDescriptor> selectedPackages = dependency.keySet();
selectedForInstallList = new JList(selectedPackages.toArray());
label.setLabelFor(selectedForInstallList);
HashMap<PackageDescriptor, HashSet<PackageDescriptor>> invertedDependency = new HashMap<PackageDescriptor, HashSet<PackageDescriptor>>();
for (PackageDescriptor source : selectedPackages) {
for (PackageDescriptor dep : dependency.get(source)) {
if (!invertedDependency.containsKey(dep)) {
invertedDependency.put(dep, new HashSet<PackageDescriptor>());
invertedDependency.get(dep).add(source);
} else {
invertedDependency.get(dep).add(source);
}
}
}
Set<PackageDescriptor> depPackages = invertedDependency.keySet();
dependentPackages = new JList(depPackages.toArray());
c.gridx = 0;
c.gridy = GridBagConstraints.RELATIVE;
c.weighty = 1;
c.insets = new Insets(0, 0, 0, 0);
JScrollPane selectedForInstallPane = new ExtendedJScrollPane(selectedForInstallList);
selectedForInstallPane.setMinimumSize(new Dimension(LIST_WIDTH, 100));
selectedForInstallPane.setPreferredSize(new Dimension(LIST_WIDTH, 100));
selectedForInstallPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
selectedForInstallPane.setBorder(BorderFactory.createMatteBorder(1, 1, 1, 1, Color.LIGHT_GRAY));
selectedForInstallList.addListSelectionListener(new LicenseListSelectionListener(dependentPackages));
PackageListCellRenderer sourceCellRenderer = new PackageListCellRenderer(null);
selectedForInstallList.setCellRenderer(sourceCellRenderer);
main.add(selectedForInstallPane, c);
c.gridx = 0;
c.gridy = 2;
c.weighty = 0;
c.insets = new Insets(10, 0, 0, 0);
ResourceLabel dependentLabel = new ResourceLabel("dependent_packages");
dependentLabel.setFont(dependentLabel.getFont().deriveFont(Font.BOLD));
dependentLabel.setLabelFor(dependentPackages);
main.add(dependentLabel, c);
c.gridx = 0;
c.gridy = GridBagConstraints.RELATIVE;
c.weighty = 1;
c.insets = new Insets(0, 0, 0, 0);
JScrollPane dependentPackagesPane = new ExtendedJScrollPane(dependentPackages);
dependentPackagesPane.setMinimumSize(new Dimension(LIST_WIDTH, 100));
dependentPackagesPane.setPreferredSize(new Dimension(LIST_WIDTH, 100));
dependentPackagesPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
dependentPackagesPane.setBorder(BorderFactory.createMatteBorder(1, 1, 1, 1, Color.LIGHT_GRAY));
dependentPackages.addListSelectionListener(new LicenseListSelectionListener(selectedForInstallList));
PackageListCellRenderer depCellRenderer = new PackageListCellRenderer(invertedDependency);
dependentPackages.setCellRenderer(depCellRenderer);
main.add(dependentPackagesPane, c);
c.gridx = 1;
c.gridy = 0;
c.weighty = 0;
c.weightx = 1;
c.insets = new Insets(0, 10, 1, 0);
;
licenseLabel = new ResourceLabel("license_label");
main.add(licenseLabel, c);
c.gridx = 1;
c.gridy = GridBagConstraints.RELATIVE;
c.gridheight = 4;
c.insets = new Insets(0, 10, 1, 0);
licensePane.setEditable(false);
JScrollPane scrollPane = new JScrollPane(licensePane);
scrollPane.setPreferredSize(new Dimension(400, 400));
scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
scrollPane.setBorder(BorderFactory.createMatteBorder(1, 1, 1, 1, Color.LIGHT_GRAY));
main.add(scrollPane, c);
licensePane.addHyperlinkListener(new HyperlinkListener() {
@Override
public void hyperlinkUpdate(HyperlinkEvent e) {
if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
RMUrlHandler.handleUrl(e.getDescription());
}
}
});
acceptReject = new JCheckBox(new ResourceAction("accept_license") {
private static final long serialVersionUID = 1L;
@Override
public void actionPerformed(ActionEvent e) {
if (acceptReject.isSelected()) {
enableButtons();
} else {
okButton.setEnabled(false);
}
}
});
okButton = this.makeOkButton("update.install");
okButton.setText(I18N.getMessage(I18N.getGUIBundle(), "gui.action.update.install.label", selectedPackages.size() + depPackages.size()));
okButton.setEnabled(false);
layoutDefault(main, HUGE, acceptReject, okButton, makeCancelButton("skip_install"));
enableButtons();
}
private void setInitialSelection() {
selectedForInstallList.setSelectedIndex(0);
}
private void enableButtons() {
okButton.setEnabled(acceptReject.isSelected() && !licenseLoadingFailed);
acceptReject.setEnabled(!licenseLoadingFailed);
}
private void setLicensePaneContent(final PackageDescriptor desc) {
licenseLabel.setText(I18N.getMessage(I18N.getGUIBundle(), "gui.label.license_label.label", desc.getName()));
final String licenseName = desc.getLicenseName();
String licenseText = licenseNameToLicenseTextMap.get(licenseName);
if (licenseText != null) {
setLicenseText(licenseText);
} else {
licensePane.setText(LOADING_LICENSE_TEXT);
new Thread("fetching-license") { //TODO change to progress thread if running more than one progress thread at a time is possible
@Override
public void run() {
UpdateService service = null;
try {
service = UpdateManager.getService();
String licenseText = service.getLicenseTextHtml(licenseName);
licenseNameToLicenseTextMap.put(licenseName, licenseText);
licenseLoadingFailed = false;
setLicenseText(licenseText);
} catch (Exception e) {
licenseLoadingFailed = true;
setLicenseText(ERROR_LOADING_LICENSE_TEXCT);
}
enableButtons();
}
}.start();
}
}
private void setLicenseText(final String licenseText) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
licensePane.setText(licenseText);
licensePane.setCaretPosition(0);
}
});
}
/** Returns true iff the user chooses to confirm the license.
* @param licenseNameToLicenseTextMap2
* @param numberOfTotalPackages
* @param updateModel */
public static boolean confirm(HashMap<PackageDescriptor, HashSet<PackageDescriptor>> dependency, HashMap<String, String> licenseNameToLicenseTextMap) {
ConfirmLicensesDialog d = new ConfirmLicensesDialog(dependency, licenseNameToLicenseTextMap);
d.setInitialSelection();
d.setVisible(true);
return d.wasConfirmed();
}
private class LicenseListSelectionListener implements ListSelectionListener {
private JList otherList;
public LicenseListSelectionListener(JList otherList) {
this.otherList = otherList;
}
@Override
public void valueChanged(ListSelectionEvent e) {
if (!e.getValueIsAdjusting()) {
JList source = (JList) e.getSource();
if (!source.isSelectionEmpty()) {
/*
* clear selection in the other list
*/
if (!otherList.isSelectionEmpty()) {
otherList.clearSelection();
}
PackageDescriptor desc = null;
Object selectedValue = ((JList) source).getSelectedValue();
desc = (PackageDescriptor) selectedValue;
try {
setLicensePaneContent(desc);
} catch (Exception e1) {
SwingTools.showSimpleErrorMessage("error_installing_update", e1, e1.getMessage());
}
}
}
}
}
}