/* * jSite - KeyDialog.java - Copyright © 2010–2014 David Roden * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ package de.todesbaum.jsite.gui; import java.awt.BorderLayout; import java.awt.Component; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.InputEvent; import java.awt.event.KeyEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.io.IOException; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.List; import javax.swing.AbstractAction; import javax.swing.Action; import javax.swing.BorderFactory; import javax.swing.DefaultListCellRenderer; import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JDialog; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JSeparator; import javax.swing.JTextField; import javax.swing.KeyStroke; import javax.swing.SwingConstants; import net.pterodactylus.util.swing.ComboBoxModelList; import de.todesbaum.jsite.application.Freenet7Interface; import de.todesbaum.jsite.application.Project; import de.todesbaum.jsite.i18n.I18n; import de.todesbaum.jsite.i18n.I18nContainer; import de.todesbaum.util.freenet.fcp2.wot.OwnIdentity; /** * A dialog that lets the user edit the private and public key for a project. * * @author David ‘Bombe’ Roden <bombe@freenetproject.org> */ public class KeyDialog extends JDialog { /** Interface to the freenet node. */ private final Freenet7Interface freenetInterface; /** The public key. */ private String publicKey; /** The private key. */ private String privateKey; /** The “OK” button’s action. */ private Action okAction; /** The “Cancel” button’s action. */ private Action cancelAction; /** The “Regenerate” button’s action. */ private Action generateAction; /** The “Copy from Project” action. */ private Action copyFromProjectAction; /** The “Copy from Identity” action. */ private Action copyFromIdentityAction; /** The text field for the private key. */ private JTextField privateKeyTextField; /** The text field for the public key. */ private JTextField publicKeyTextField; /** The select box for the projects. */ private JComboBox projectsComboBox; /** The select box for the own identities. */ private JComboBox ownIdentitiesComboBox; /** Whether the dialog was cancelled. */ private boolean cancelled; /** The list of projects. */ private final List<Project> projects = new ArrayList<Project>(); /** The list of own identities. */ private final List<OwnIdentity> ownIdentities = new ArrayList<OwnIdentity>(); /** * Creates a new key dialog. * * @param freenetInterface * Interface to the freenet node * @param parent * The parent frame */ public KeyDialog(Freenet7Interface freenetInterface, JFrame parent) { super(parent, I18n.getMessage("jsite.key-dialog.title"), true); this.freenetInterface = freenetInterface; addWindowListener(new WindowAdapter() { @Override @SuppressWarnings("synthetic-access") public void windowClosing(WindowEvent windowEvent) { actionCancel(); } }); initDialog(); } // // ACCESSORS // /** * Returns whether the dialog was cancelled. * * @return {@code true} if the dialog was cancelled, {@code false} otherwise */ public boolean wasCancelled() { return cancelled; } /** * Returns the public key. * * @return The public key */ public String getPublicKey() { return publicKey; } /** * Sets the public key. * * @param publicKey * The public key */ public void setPublicKey(String publicKey) { this.publicKey = publicKey; publicKeyTextField.setText(publicKey); pack(); } /** * Returns the private key. * * @return The private key */ public String getPrivateKey() { return privateKey; } /** * Sets the private key. * * @param privateKey * The private key */ public void setPrivateKey(String privateKey) { this.privateKey = privateKey; privateKeyTextField.setText(privateKey); pack(); } /** * Sets the projects to display and copy URIs from. * * @param projects * The list of projects */ public void setProjects(Collection<? extends Project> projects) { synchronized (this.projects) { this.projects.clear(); this.projects.addAll(projects); } projectsComboBox.setSelectedIndex(-1); } /** * Sets the own identities to display and copy URIs from. * * @param ownIdentities * The list of own identities */ public void setOwnIdentities(Collection<? extends OwnIdentity> ownIdentities) { synchronized (this.ownIdentities) { this.ownIdentities.clear(); this.ownIdentities.addAll(ownIdentities); Collections.sort(this.ownIdentities, new Comparator<OwnIdentity>() { @Override public int compare(OwnIdentity leftOwnIdentity, OwnIdentity rightOwnIdentity) { return leftOwnIdentity.getNickname().compareToIgnoreCase(rightOwnIdentity.getNickname()); } }); } int selectedIndex = -1; int index = 0; for (OwnIdentity ownIdentity : this.ownIdentities) { if (ownIdentity.getInsertUri().equals(privateKey) && ownIdentity.getRequestUri().equals(publicKey)) { selectedIndex = index; } index++; } ownIdentitiesComboBox.setSelectedIndex(selectedIndex); } // // ACTIONS // /** * {@inheritDoc} */ @Override public void pack() { super.pack(); Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); setLocation((screenSize.width - getWidth()) / 2, (screenSize.height - getHeight()) / 2); } // // PRIVATE METHODS // /** * Creates all necessary actions. */ private void createActions() { okAction = new AbstractAction(I18n.getMessage("jsite.general.ok")) { @Override @SuppressWarnings("synthetic-access") public void actionPerformed(ActionEvent actionEvent) { actionOk(); } }; okAction.putValue(Action.SHORT_DESCRIPTION, I18n.getMessage("jsite.key-dialog.button.ok.tooltip")); okAction.putValue(Action.MNEMONIC_KEY, KeyEvent.VK_ENTER); cancelAction = new AbstractAction(I18n.getMessage("jsite.general.cancel")) { @Override @SuppressWarnings("synthetic-access") public void actionPerformed(ActionEvent actionEvent) { actionCancel(); } }; cancelAction.putValue(Action.SHORT_DESCRIPTION, I18n.getMessage("jsite.key-dialog.button.cancel.tooltip")); cancelAction.putValue(Action.MNEMONIC_KEY, KeyEvent.VK_ESCAPE); copyFromProjectAction = new AbstractAction(I18n.getMessage("jsite.key-dialog.button.copy-from-project")) { @Override @SuppressWarnings("synthetic-access") public void actionPerformed(ActionEvent actionevent) { actionCopyFromProject(); } }; copyFromProjectAction.putValue(Action.SHORT_DESCRIPTION, I18n.getMessage("jsite.key-dialog.button.copy-from-project.tooltip")); copyFromProjectAction.putValue(Action.MNEMONIC_KEY, KeyEvent.VK_P); copyFromProjectAction.putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_P, InputEvent.CTRL_DOWN_MASK)); copyFromIdentityAction = new AbstractAction(I18n.getMessage("jsite.key-dialog.button.copy-from-identity")) { @Override @SuppressWarnings("synthetic-access") public void actionPerformed(ActionEvent actionevent) { actionCopyFromIdentity(); } }; copyFromIdentityAction.putValue(Action.SHORT_DESCRIPTION, I18n.getMessage("jsite.key-dialog.button.copy-from-identity.tooltip")); copyFromIdentityAction.putValue(Action.MNEMONIC_KEY, KeyEvent.VK_I); copyFromIdentityAction.putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_I, InputEvent.CTRL_DOWN_MASK)); generateAction = new AbstractAction(I18n.getMessage("jsite.key-dialog.button.generate")) { @Override @SuppressWarnings("synthetic-access") public void actionPerformed(ActionEvent actionEvent) { actionGenerate(); } }; generateAction.putValue(Action.SHORT_DESCRIPTION, I18n.getMessage("jsite.key-dialog.button.generate.tooltip")); generateAction.putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_R, InputEvent.CTRL_DOWN_MASK)); } /** * Initializes the dialog and all its components. */ private void initDialog() { createActions(); JPanel dialogPanel = new JPanel(new BorderLayout(12, 12)); dialogPanel.setBorder(BorderFactory.createEmptyBorder(12, 12, 12, 12)); JPanel contentPanel = new JPanel(new GridBagLayout()); dialogPanel.add(contentPanel, BorderLayout.CENTER); final JLabel keysLabel = new JLabel(I18n.getMessage("jsite.key-dialog.label.keys")); contentPanel.add(keysLabel, new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0)); final JLabel privateKeyLabel = new JLabel(I18n.getMessage("jsite.key-dialog.label.private-key")); contentPanel.add(privateKeyLabel, new GridBagConstraints(0, 1, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(12, 18, 0, 0), 0, 0)); privateKeyTextField = new JTextField(); contentPanel.add(privateKeyTextField, new GridBagConstraints(1, 1, 2, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(6, 12, 0, 0), 0, 0)); final JLabel publicKeyLabel = new JLabel(I18n.getMessage("jsite.key-dialog.label.public-key")); contentPanel.add(publicKeyLabel, new GridBagConstraints(0, 2, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(6, 18, 0, 0), 0, 0)); publicKeyTextField = new JTextField(); contentPanel.add(publicKeyTextField, new GridBagConstraints(1, 2, 2, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(6, 12, 0, 0), 0, 0)); final JLabel copyKeysLabel = new JLabel(I18n.getMessage("jsite.key-dialog.label.copy-keys")); contentPanel.add(copyKeysLabel, new GridBagConstraints(0, 3, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(12, 0, 0, 0), 0, 0)); final JLabel projectLabel = new JLabel(I18n.getMessage("jsite.key-dialog.label.project")); contentPanel.add(projectLabel, new GridBagConstraints(0, 4, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(12, 18, 0, 0), 0, 0)); synchronized (projects) { projectsComboBox = new JComboBox(new ComboBoxModelList<Project>(projects)); } projectsComboBox.addActionListener(new ActionListener() { @Override @SuppressWarnings("synthetic-access") public void actionPerformed(ActionEvent actionEvent) { copyFromProjectAction.setEnabled(projectsComboBox.getSelectedIndex() > -1); } }); contentPanel.add(projectsComboBox, new GridBagConstraints(1, 4, 1, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(6, 12, 0, 0), 0, 0)); JButton copyFromProjectButton = new JButton(copyFromProjectAction); contentPanel.add(copyFromProjectButton, new GridBagConstraints(2, 4, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_END, GridBagConstraints.HORIZONTAL, new Insets(6, 12, 0, 0), 0, 0)); final JLabel identityLabel = new JLabel(I18n.getMessage("jsite.key-dialog.label.identity")); contentPanel.add(identityLabel, new GridBagConstraints(0, 5, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(12, 18, 0, 0), 0, 0)); ownIdentitiesComboBox = new JComboBox(new ComboBoxModelList<OwnIdentity>(ownIdentities)); ownIdentitiesComboBox.addActionListener(new ActionListener() { @Override @SuppressWarnings("synthetic-access") public void actionPerformed(ActionEvent actionevent) { copyFromIdentityAction.setEnabled(ownIdentitiesComboBox.getSelectedIndex() > -1); } }); ownIdentitiesComboBox.setRenderer(new DefaultListCellRenderer() { @Override public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); if (value == null) { setText(""); } else { OwnIdentity ownIdentity = (OwnIdentity) value; setText(String.format("%s (%s)", ownIdentity.getNickname(), ownIdentity.getRequestUri().substring(0, ownIdentity.getRequestUri().indexOf(',')))); } return this; } }); contentPanel.add(ownIdentitiesComboBox, new GridBagConstraints(1, 5, 1, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(6, 12, 0, 0), 0, 0)); JButton copyFromIdentityButton = new JButton(copyFromIdentityAction); contentPanel.add(copyFromIdentityButton, new GridBagConstraints(2, 5, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_END, GridBagConstraints.HORIZONTAL, new Insets(6, 12, 0, 0), 0, 0)); final JLabel actionsLabel = new JLabel(I18n.getMessage("jsite.key-dialog.label.actions")); contentPanel.add(actionsLabel, new GridBagConstraints(0, 6, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(12, 0, 0, 0), 0, 0)); JPanel actionButtonPanel = new JPanel(new FlowLayout(FlowLayout.LEADING, 12, 12)); actionButtonPanel.setBorder(BorderFactory.createEmptyBorder(-12, -12, -12, -12)); contentPanel.add(actionButtonPanel, new GridBagConstraints(0, 7, 3, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(12, 18, 0, 0), 0, 0)); actionButtonPanel.add(new JButton(generateAction)); JPanel separatorPanel = new JPanel(new BorderLayout(12, 12)); dialogPanel.add(separatorPanel, BorderLayout.PAGE_END); separatorPanel.add(new JSeparator(SwingConstants.HORIZONTAL), BorderLayout.PAGE_START); JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.TRAILING, 12, 12)); buttonPanel.setBorder(BorderFactory.createEmptyBorder(-12, -12, -12, -12)); separatorPanel.add(buttonPanel, BorderLayout.CENTER); buttonPanel.add(new JButton(okAction)); buttonPanel.add(new JButton(cancelAction)); I18nContainer.getInstance().registerRunnable(new Runnable() { @Override public void run() { keysLabel.setText(I18n.getMessage("jsite.key-dialog.label.keys")); privateKeyLabel.setText(I18n.getMessage("jsite.key-dialog.label.private-key")); publicKeyLabel.setText(I18n.getMessage("jsite.key-dialog.label.public-key")); copyKeysLabel.setText(I18n.getMessage("jsite.key-dialog.label.copy-keys")); identityLabel.setText(I18n.getMessage("jsite.key-dialog.label.identity")); projectLabel.setText(I18n.getMessage("jsite.key-dialog.label.project")); actionsLabel.setText(I18n.getMessage("jsite.key-dialog.label.actions")); } }); getContentPane().add(dialogPanel, BorderLayout.CENTER); pack(); setResizable(false); } // // PRIVATE ACTIONS // /** * Quits the dialog, accepting all changes. */ private void actionOk() { publicKey = publicKeyTextField.getText(); privateKey = privateKeyTextField.getText(); cancelled = false; setVisible(false); } /** * Quits the dialog, discarding all changes. */ private void actionCancel() { cancelled = true; setVisible(false); } /** * Copies the public and private key from the selected project. */ private void actionCopyFromProject() { Project project = (Project) projectsComboBox.getSelectedItem(); if (project == null) { return; } setPublicKey(project.getRequestURI()); setPrivateKey(project.getInsertURI()); } /** * Copies the public and private key from the selected identity. */ private void actionCopyFromIdentity() { OwnIdentity ownIdentity = (OwnIdentity) ownIdentitiesComboBox.getSelectedItem(); if (ownIdentity == null) { return; } setPublicKey(ownIdentity.getRequestUri()); setPrivateKey(ownIdentity.getInsertUri()); } /** * Generates a new key pair. */ private void actionGenerate() { if (JOptionPane.showConfirmDialog(this, I18n.getMessage("jsite.project.warning.generate-new-key"), null, JOptionPane.OK_CANCEL_OPTION) == JOptionPane.CANCEL_OPTION) { return; } String[] keyPair = null; try { keyPair = freenetInterface.generateKeyPair(); } catch (IOException ioe1) { JOptionPane.showMessageDialog(this, MessageFormat.format(I18n.getMessage("jsite.project.keygen.io-error"), ioe1.getMessage()), null, JOptionPane.ERROR_MESSAGE); return; } publicKeyTextField.setText(keyPair[1].substring(keyPair[1].indexOf('@') + 1, keyPair[1].lastIndexOf('/'))); privateKeyTextField.setText(keyPair[0].substring(keyPair[0].indexOf('@') + 1, keyPair[0].lastIndexOf('/'))); pack(); } }