/** * Copyright (C) 2001-2017 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.rapidminer.gui.dialog; import java.awt.BorderLayout; import java.awt.FlowLayout; import java.awt.event.ActionEvent; import java.awt.event.AdjustmentEvent; import java.awt.event.AdjustmentListener; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.Properties; import java.util.logging.Level; import javax.swing.BorderFactory; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComponent; import javax.swing.JDialog; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JScrollBar; import javax.swing.JScrollPane; import javax.swing.JTextArea; import javax.swing.SwingUtilities; import javax.swing.WindowConstants; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import com.rapidminer.RapidMiner; import com.rapidminer.RapidMiner.ExitMode; import com.rapidminer.core.license.ProductConstraintManager; import com.rapidminer.gui.license.LicenseTools; import com.rapidminer.gui.look.Colors; import com.rapidminer.gui.tools.ExtendedJScrollPane; import com.rapidminer.gui.tools.ResourceAction; import com.rapidminer.gui.tools.SwingTools; import com.rapidminer.gui.tools.components.FixedWidthLabel; import com.rapidminer.gui.tools.dialogs.ButtonDialog; import com.rapidminer.repository.RepositoryException; import com.rapidminer.tools.FileSystemService; import com.rapidminer.tools.I18N; import com.rapidminer.tools.LogService; import com.rapidminer.tools.Tools; /** * Dialog to display the EULA text. User must accept the EULA before RapidMiner can be used. * * @author Michael Knopf */ public class EULADialog extends ButtonDialog implements AdjustmentListener, ChangeListener { private static final long serialVersionUID = 1067725913323338148L; private static final String DEFAULT_EULA = "EULA_EN.txt"; /** * Should be adjusted whenever the EULA is updated. */ private static final String ACCEPT_PROPERTY = "rapidminer.eula.v6.accepted"; private final JButton acceptButton; private final JCheckBox acceptCheckBox; private final JTextArea eulaText; private final JScrollPane scrollPane; /** * Simple confirm dialog to be used instead of the ConfirmDialog extending the ButtonDialog * class. This is necessary, since the ButtonDialog family does not support specifying owner * components. * * @author Michael Knopf */ private class ConfirmDialog extends JDialog { private static final long serialVersionUID = 1L; public static final int YES_OPTION = JOptionPane.YES_OPTION; public static final int NO_OPTION = JOptionPane.NO_OPTION; private int returnCode = NO_OPTION; /** * Constructor. */ public ConfirmDialog() { super(EULADialog.this, I18N.getMessage(I18N.getGUIBundle(), "gui.dialog.eula.title"), true); // setup info panel (using the same layout as the ButtonDialog class) JLabel message = new FixedWidthLabel(420, I18N.getMessage(I18N.getGUIBundle(), "gui.dialog.confirm.decline_eula.message", LicenseTools.translateProductName(ProductConstraintManager.INSTANCE.getActiveLicense()))); JLabel icon = new JLabel(SwingTools.createIcon("48/" + I18N.getMessage(I18N.getGUIBundle(), "gui.dialog.eula.icon"))); JPanel messagePanel = new JPanel(new BorderLayout(20, 0)); messagePanel.setBorder(BorderFactory.createEmptyBorder(12, 16, 16, 4)); messagePanel.add(icon, BorderLayout.WEST); messagePanel.add(message, BorderLayout.CENTER); // setup button panel JButton quitRapidMinerButton = new JButton(new ResourceAction("decline_eula_confirm", LicenseTools.translateProductName(ProductConstraintManager.INSTANCE.getActiveLicense())) { private static final long serialVersionUID = 1L; @Override public void actionPerformed(ActionEvent e) { ConfirmDialog.this.returnCode = YES_OPTION; ConfirmDialog.this.setVisible(false); } }); JButton goBackButton = new JButton(new ResourceAction("decline_eula_go_back") { private static final long serialVersionUID = 1L; @Override public void actionPerformed(ActionEvent e) { ConfirmDialog.this.returnCode = NO_OPTION; ConfirmDialog.this.setVisible(false); } }); JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT, ButtonDialog.GAP, ButtonDialog.GAP)); buttonPanel.add(goBackButton); buttonPanel.add(quitRapidMinerButton); // again, mimic ButtonDialog's layout this.setLayout(new BorderLayout(ButtonDialog.GAP, ButtonDialog.GAP)); this.setResizable(false); this.add(messagePanel, BorderLayout.CENTER); this.add(buttonPanel, BorderLayout.SOUTH); this.pack(); this.setLocationRelativeTo(EULADialog.this); } /** * Returns the user selection. */ public int getReturnOption() { return this.returnCode; } } /** * Constructor. */ public EULADialog() { super(null, "eula", ModalityType.TOOLKIT_MODAL, new Object[] { LicenseTools .translateProductName(ProductConstraintManager.INSTANCE.getActiveLicense()) }); this.acceptButton = this.makeAcceptButton(); this.acceptButton.setEnabled(false); this.acceptCheckBox = new JCheckBox(I18N.getGUILabel("read_eula")); this.acceptCheckBox.setEnabled(false); this.eulaText = new JTextArea(); this.eulaText.setColumns(60); this.eulaText.setRows(15); this.eulaText.setLineWrap(true); this.eulaText.setWrapStyleWord(true); this.eulaText.setEditable(false); this.eulaText.setText(this.loadEULA()); eulaText.setBorder(null); this.scrollPane = new ExtendedJScrollPane(this.eulaText); scrollPane.setBorder(BorderFactory.createLineBorder(Colors.TEXTFIELD_BORDER)); this.layoutDefault(this.makeContentPanel(), this.acceptButton, this.makeDeclineButton()); this.setResizable(false); this.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); // add listeners (must be added after doing the layout) this.acceptCheckBox.addChangeListener(this); this.scrollPane.getVerticalScrollBar().addAdjustmentListener(this); } /** * Loads translated EULA text. If the file cannot be found a default text is loaded (the English * version of the EULA). */ private String loadEULA() { // look up location of EULA file String pathToEula = I18N.getMessage(I18N.getGUIBundle(), "gui.resource.eula_file"); String eulaText = null; // read EULA text try (InputStream inputStream = Tools.getResourceInputStream(pathToEula)) { eulaText = Tools.readTextFile(inputStream); } catch (IOException | RepositoryException e1) { // loading the translated EULA failed, load default text instead LogService.getRoot().log(Level.WARNING, "com.rapidminer.gui.dialog.EULADialog.cannot_open_translated_eula"); try (InputStream inputStream = Tools.getResourceInputStream(DEFAULT_EULA)) { eulaText = Tools.readTextFile(inputStream); } catch (IOException | RepositoryException e2) { // loading the default EULA failed (this should never happen) LogService.getRoot().log(Level.SEVERE, "com.rapidminer.gui.dialog.EULADialog.cannot_open_default_eula"); } } return eulaText; } /** * Creates a button to accept the EULA. Invokes storage of the corresponding property. */ private JButton makeAcceptButton() { ResourceAction action = new ResourceAction("accept_eula") { private static final long serialVersionUID = 3102243518938674477L; @Override public void actionPerformed(ActionEvent e) { // store decision and close dialog EULADialog.setEULAAccepted(true); dispose(); } }; return new JButton(action); } /** * Creates the content panel consisting of a scrollable text area to display the EULA text and a * check box to accept it. */ private JComponent makeContentPanel() { JPanel panel = new JPanel(); panel.setLayout(new BorderLayout()); // add text area with scroll pane panel.add(this.scrollPane, BorderLayout.CENTER); // scroll to tohe top of the document SwingUtilities.invokeLater(new Runnable() { @Override public void run() { scrollPane.getVerticalScrollBar().setValue(0); } }); // add check box to enable accept button panel.add(this.acceptCheckBox, BorderLayout.SOUTH); return panel; } /** * Creates a button to decline the EULA. A confirmation dialog is shown before RapidMiner is * closed. */ private JButton makeDeclineButton() { ResourceAction action = new ResourceAction("decline_eula") { private static final long serialVersionUID = 3102243518938674477L; @Override public void actionPerformed(ActionEvent e) { ConfirmDialog dialog = new ConfirmDialog(); dialog.setVisible(true); dialog.requestFocusInWindow(); if (dialog.getReturnOption() == ConfirmDialog.YES_OPTION) { RapidMiner.quit(ExitMode.NORMAL); } } }; return new JButton(action); } /** * Listens to changes of the check box, enables the accept button when the check box is active. */ @Override public void stateChanged(ChangeEvent e) { if (e.getSource() == this.acceptCheckBox) { this.acceptButton.setEnabled(this.acceptCheckBox.isSelected()); } } /** * Listens to changes of the scroll bar of the text are showing the EULA text, enables the check * box once the user scrolled to the end of the document. */ @Override public void adjustmentValueChanged(AdjustmentEvent e) { JScrollBar scrollBar = this.scrollPane.getVerticalScrollBar(); if (e.getSource() == scrollBar) { // the maximum value of the scroll bar assumes that the content is // not visible anymore, since this is not the case when scrolling // to the end of the document (the last part is still visible), // we have to include the visible amount in the comparison int currentValue = scrollBar.getValue() + scrollBar.getVisibleAmount(); if (currentValue >= scrollBar.getMaximum()) { // the user scrolled to the end of the document this.acceptCheckBox.setEnabled(true); this.acceptCheckBox.requestFocusInWindow(); } } } /** * Looks up the users' decision to accept/decline the current EULA in the "eula.properties" * file. * * @return True if the EULA was accepted, false otherwise. */ public static boolean getEULAAccepted() { File eulaPropertiesFile = FileSystemService.getUserConfigFile("eula.properties"); Properties eulaProperties = new Properties(); // if the property file already exists, load its contents if (eulaPropertiesFile.exists()) { try (FileInputStream in = new FileInputStream(eulaPropertiesFile)) { eulaProperties.load(in); } catch (IOException e) { LogService.getRoot().log(Level.WARNING, "com.rapidminer.gui.dialog.EULADialog.loading_properties_failed", e); } // check and return property String accepted = eulaProperties.getProperty(ACCEPT_PROPERTY); return Tools.booleanValue(accepted, false); } else { // property cannot be set return false; } } /** * Stores the users' decision to accept/decline the current EULA in the "eula.properties" file. * * @param accepted * Indicates whether the user accepted the EULA. */ public static void setEULAAccepted(boolean accepted) { File eulaPropertiesFile = FileSystemService.getUserConfigFile("eula.properties"); Properties eulaProperties = new Properties(); // if the property file already exists, load its contents if (eulaPropertiesFile.exists()) { try (FileInputStream in = new FileInputStream(eulaPropertiesFile)) { eulaProperties.load(in); } catch (IOException e) { LogService.getRoot().log(Level.WARNING, "com.rapidminer.gui.dialog.EULADialog.loading_properties_failed", e); } } // set the acceptance property eulaProperties.setProperty(ACCEPT_PROPERTY, accepted ? "true" : "false"); // store properties try (FileOutputStream out = new FileOutputStream(eulaPropertiesFile)) { eulaProperties.store(out, "RapidMiner EULA Properties"); } catch (IOException e) { LogService.getRoot().log(Level.WARNING, "com.rapidminer.gui.dialog.EULADialog.storing_properties_failed", e); } } }