All Downloads are FREE. Search and download functionalities are using the official Maven repository.

de.schlichtherle.key.passwd.swing.AuthenticationPanel Maven / Gradle / Ivy

/*
 * Copyright (C) 2006-2010 Schlichtherle IT Services
 *
 * 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 de.schlichtherle.key.passwd.swing;

import de.schlichtherle.io.*;
import de.schlichtherle.io.swing.*;

import java.awt.*;
import java.awt.event.*;
import java.lang.ref.*;
import java.util.*;

import javax.swing.*;
import javax.swing.text.*;

/**
 * A panel displaying a password panel or a key file panel in order to let
 * the user select an authentication method and enter the key.
 *
 * @author Christian Schlichtherle
 * @since TrueZIP 6.0
 * @version $Id: AuthenticationPanel.java 5e709f50671d 2010/11/05 11:52:07 christian $
 */
public class AuthenticationPanel extends JPanel {

    private static final String CLASS_NAME
            = "de.schlichtherle.key.passwd.swing.AuthenticationPanel";
    private static final ResourceBundle resources
            = ResourceBundle.getBundle(CLASS_NAME);
    private static final File BASE_DIR = new File(".", ArchiveDetector.NULL);

    private static SoftReference fileChooser;

    /** The password authentication method. */
    public static final int AUTH_PASSWD = 0;
    
    /** The key file authentication method. */
    public static final int AUTH_KEY_FILE = 1;

    /**
     * Creates a new authentication panel.
     * This version of the constructor does not remember the key file path.
     */
    public AuthenticationPanel() {
        initComponents();

        // Order is important here: The file combo box browser installs its
        // own editor, so we have to adjust the columns last.
        new FileComboBoxBrowser(keyFile).setDirectory(BASE_DIR);
        ((JTextField) keyFile.getEditor().getEditorComponent()).setColumns(30);
    }

    /**
     * Sets the panel which should be used to enter the password.
     *
     * @throws NullPointerException If {@code passwdPanel} is
     *         {@code null}.
     */
    public void setPasswdPanel(JPanel passwdPanel) {
        if (passwdPanel == null)
            throw new NullPointerException();

        passwdPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
        final String title = resources.getString("tab.passwd");
        if (title.equals(tabs.getTitleAt(AUTH_PASSWD)))
            tabs.removeTabAt(AUTH_PASSWD);
        tabs.insertTab(title, null, passwdPanel, null, AUTH_PASSWD); // NOI18N
        tabs.setSelectedIndex(AUTH_PASSWD);
        revalidate();
    }

    Document getKeyFileDocument() {
        return ((JTextComponent) keyFile.getEditor().getEditorComponent()).getDocument();
    }

    /**
     * Returns the path of the key file.
     * If the parameter {@code rememberPath} of the constructor was
     * {@code true}, then the returned path is remembered in a static
     * field for the next instance of this class.
     */
    public String getKeyFilePath() {
        return (String) keyFile.getSelectedItem();
    }

    private void setKeyFilePath(final String path) {
        final String oldPath = (String) keyFile.getSelectedItem();
        if (path == oldPath || path != null && path.equals(oldPath))
            return;

        keyFile.setSelectedItem(path);
        /*final Window window = SwingUtilities.getWindowAncestor(this);
        if (window != null)
            window.pack();*/
    }

    /**
     * Returns the authentication method selected by the user.
     *
     * @return {@code AUTH_PASSWD} or {@code AUTH_KEY_FILE}.
     */
    public int getAuthenticationMethod() {
        final int method = tabs.getSelectedIndex();
        switch (method) {
            case AUTH_PASSWD:
                assert resources.getString("tab.passwd").equals(tabs.getTitleAt(method));
                break;

            case AUTH_KEY_FILE:
                assert resources.getString("tab.keyFile").equals(tabs.getTitleAt(method));
                break;

            default:
                throw new AssertionError("Unsupported authentication method!");
        }
        return method;
    }

    /**
     * Return a {@code JFileChooser} to use within this panel.
     * The file chooser is stored in a cache for subsequent use.
     * If the JVM gets short of storage, the cache is emptied and a new
     * file chooser is instantiated on the next call to this method again.
     * In any way, the file chooser will always remember its current directory.
     * In addition, the returned file chooser has file hiding disabled.
     * Note that the file chooser is a plain javax.swing.FileChooser which
     * does not support archive browsing to prevent illegal recursion.
     */
    static javax.swing.JFileChooser getFileChooser() {
        final SoftReference ref = fileChooser; // cache
        javax.swing.JFileChooser fc = ref != null ? (javax.swing.JFileChooser) ref.get() : null;
        if (fc == null) {
            fc = new CustomFileChooser();
            fileChooser = new SoftReference(fc);
        }
        return fc;
    }

    /** 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.
     */
    // //GEN-BEGIN:initComponents
    private void initComponents() {
        java.awt.GridBagConstraints gridBagConstraints;

        tabs = new javax.swing.JTabbedPane();
        final javax.swing.JLabel keyFileLabel = new javax.swing.JLabel();

        setLayout(new java.awt.GridBagLayout());

        keyFilePanel.setLayout(new java.awt.GridBagLayout());

        keyFilePanel.setBorder(javax.swing.BorderFactory.createEmptyBorder(10, 10, 10, 10));
        keyFilePanel.addPanelListener(new de.schlichtherle.swing.event.PanelListener() {
            public void ancestorWindowShown(de.schlichtherle.swing.event.PanelEvent evt) {
                keyFilePanelAncestorWindowShown(evt);
            }
            public void ancestorWindowHidden(de.schlichtherle.swing.event.PanelEvent evt) {
            }
        });

        keyFileLabel.setDisplayedMnemonic(resources.getString("keyFile").charAt(0));
        keyFileLabel.setLabelFor(keyFile);
        keyFileLabel.setText(resources.getString("keyFile")); // NOI18N
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
        gridBagConstraints.insets = new java.awt.Insets(0, 0, 5, 0);
        keyFilePanel.add(keyFileLabel, gridBagConstraints);

        keyFile.setEditable(true);
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 1;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.weightx = 1.0;
        keyFilePanel.add(keyFile, gridBagConstraints);

        keyFileChooser.setIcon(UIManager.getIcon("FileView.directoryIcon"));
        keyFileChooser.setToolTipText(resources.getString("selectKeyFile.toolTip")); // NOI18N
        keyFileChooser.setName("keyFileChooser");
        keyFileChooser.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                keyFileChooserActionPerformed(evt);
            }
        });

        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 1;
        gridBagConstraints.gridy = 1;
        gridBagConstraints.insets = new java.awt.Insets(0, 10, 0, 0);
        keyFilePanel.add(keyFileChooser, gridBagConstraints);

        tabs.addTab(resources.getString("tab.keyFile"), keyFilePanel); // NOI18N

        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
        gridBagConstraints.weightx = 1.0;
        gridBagConstraints.weighty = 1.0;
        add(tabs, gridBagConstraints);

    }// //GEN-END:initComponents

    private void keyFileChooserActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_keyFileChooserActionPerformed
        final javax.swing.JFileChooser fc = getFileChooser();
        if (fc.showOpenDialog(this) == javax.swing.JFileChooser.APPROVE_OPTION) {
            final File file = new File(fc.getSelectedFile(), ArchiveDetector.NULL);
            final String baseDirPath = BASE_DIR.getCanOrAbsPath();
            String keyFilePath = file.getCanOrAbsPath();
            if (keyFilePath.startsWith(baseDirPath)) {
                assert keyFilePath.charAt(baseDirPath.length()) == File.separatorChar;
                keyFilePath = keyFilePath.substring(baseDirPath.length() + 1); // skip file separator
            }
            setKeyFilePath(keyFilePath);
        }
    }//GEN-LAST:event_keyFileChooserActionPerformed

    private void keyFilePanelAncestorWindowShown(de.schlichtherle.swing.event.PanelEvent evt) {//GEN-FIRST:event_keyFilePanelAncestorWindowShown
        // These are the things I hate Swing for: All I want to do here is to
        // set the focus to the passwd field in this panel when it shows.
        // However, this can't be done in the constructor since the panel is
        // not yet placed in a window which is actually showing.
        // Right, then we use this event listener to do it. This listener
        // method is called when the ancestor window is showing (and coding
        // the event generation was a less than trivial task).
        // But wait, simply setting the focus in this event listener here is
        // not possible on Linux because the containing window (now we have
        // one) didn't gain the focus yet.
        // Strangely enough, this works on Windows.
        // Even more strange, not even calling passwd.requestFocus() makes it
        // work on Linux!
        // So we add a window focus listener here and remove it when we
        // receive a Focus Gained Event.
        // But wait, then we still can't request the focus: This time it
        // doesn't work on Windows, while it works on Linux.
        // I still don't know the reason why, but it seems we're moving too
        // fast, so I have to post a new event to the event queue which finally
        // sets the focus.
        // But wait, requesting the focus could still fail for some strange,
        // undocumented reason - I wouldn't be surprised anymore.
        // So we add a conditional to select the entire contents of the field
        // only if we can really transfer the focus to it.
        // Otherwise, users could get easily confused.
        // If you carefully read the documentation for requestFocusInWindow()
        // however, then you know that even if it returns true, there is still
        // no guarantee that the focus gets actually transferred...
        // This mess is insane (and I can hardly abstain from writing down
        // all the other insulting scatology which comes to my mind)!
        final Window window = evt.getAncestorWindow();
        window.addWindowFocusListener(new WindowFocusListener() {
            public void windowGainedFocus(WindowEvent e) {
                window.removeWindowFocusListener(this);
                EventQueue.invokeLater(new Runnable() {
                    public void run() {
                        if (keyFile.requestFocusInWindow())
                            ((JTextComponent) keyFile.getEditor().getEditorComponent()).selectAll();
                    }
                });
            }

            public void windowLostFocus(WindowEvent e) {
            }
        });
    }//GEN-LAST:event_keyFilePanelAncestorWindowShown
        
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private final javax.swing.JComboBox keyFile = new javax.swing.JComboBox();
    private final javax.swing.JButton keyFileChooser = new javax.swing.JButton();
    private final de.schlichtherle.swing.EnhancedPanel keyFilePanel = new de.schlichtherle.swing.EnhancedPanel();
    private javax.swing.JTabbedPane tabs;
    // End of variables declaration//GEN-END:variables

    private static class CustomFileChooser extends javax.swing.JFileChooser {
        private static java.io.File lastCurrentDir = BASE_DIR;
        
        public CustomFileChooser() {
            super(lastCurrentDir);

            setDialogTitle(resources.getString("fileChooser.title"));
            setFileHidingEnabled(false);
        }

        public void setCurrentDirectory(java.io.File dir) {
            super.setCurrentDirectory(dir);
            lastCurrentDir = dir;
        }

        public java.io.File getCurrentDirectory() {
            return lastCurrentDir = super.getCurrentDirectory();
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy