package edu.colostate.vchill;
import javax.swing.*;
import javax.swing.event.HyperlinkEvent;
import javax.swing.event.HyperlinkEvent.EventType;
import javax.swing.event.HyperlinkListener;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.*;
import java.net.URL;
import java.util.Arrays;
/**
* This class contains static methods for displaying various dialogs.
*
* @author Jochen Deyke
* @author Alexander Deyke
* @version 2007-09-10
*/
public final class DialogUtil {
private static final Config config = Config.getInstance();
/**
* The (default) parent for the dialogs to be displayed.
* Dialogs are automatically minimized and restored along with their parent,
* and modal dialogs prevent interaction with their parent.
*/
static Component parent = null;
/**
* Private default constructor prevents instantiation
*/
private DialogUtil() {
}
/**
* Shows an error message that blocks user interaction until cleared.
* The window title is "Error".
*
* @param message the actual message to display, or the url of the message to display
*/
public static void showErrorDialog(final String message) {
showErrorDialog("Error", message);
}
/**
* Shows an error message that blocks user interaction until cleared.
* The window title can be specified.
*
* @param title the title for the dialog box
* @param message the actual message to display, or the url of the message to display
*/
public static void showErrorDialog(final String title, final String message) {
showErrorDialog(parent, title, message);
}
/**
* Shows an error message that blocks user interaction until cleared.
* The window title can be specified.
*
* @param title the title for the dialog box
* @param message the actual message to display, or the url of the message to display
* @param parent the parent for the dialog
*/
public static void showErrorDialog(final Component parent, final String title, final String message) {
if (!config.isGUIEnabled()) { //text only
System.err.println("Error: " + title);
System.err.println(message);
} else if (message.startsWith("http://")) { //html
new HTMLDialog(parent, message, title, JOptionPane.ERROR_MESSAGE).setVisible(true);
} else { //normal dialog
JOptionPane.showMessageDialog(parent, message, title, JOptionPane.ERROR_MESSAGE);
}
}
/**
* Shows an informational message that does not interfere with
* program operation.
* The window title is "Help".
*
* @param message the actual message to display, or the url of the message to display
*/
public static void showHelpDialog(final String message) {
showHelpDialog("Help", message);
}
/**
* Shows an informational message that does not interfere with
* program operation.
* The window title can be specified.
*
* @param title the title for the dialog box
* @param message the actual message to display, or the url of the message to display
*/
public static void showHelpDialog(final String title, final String message) {
showHelpDialog(parent, title, message);
}
/**
* Shows an informational message that does not interfere with
* program operation.
* The window title can be specified.
*
* @param title the title for the dialog box
* @param message the actual message to display, or the url of the message to display
* @param parent the parent for the dialog
*/
public static void showHelpDialog(final Component parent, final String title, final String message) {
if (!config.isGUIEnabled()) { //text only
System.out.println("Help: " + title);
System.out.println(message);
} else if (message.startsWith("http://")) { //html
HTMLDialog dialog = new HTMLDialog(parent, message, title, JOptionPane.INFORMATION_MESSAGE);
dialog.setModal(false);
dialog.setAlwaysOnTop(true);
dialog.setVisible(true);
} else { //normal dialog
JDialog dialog = (new JOptionPane(message, JOptionPane.INFORMATION_MESSAGE)).createDialog(parent, title);
dialog.setModal(false);
dialog.setAlwaysOnTop(true);
dialog.setVisible(true);
}
}
/**
* Shows an informational message that does not interfere with
* program operation.
* The window title can be specified.
*
* @param title the title for the dialog box
* @param source the url of the message to display
*/
public static void showHelpDialog(final String title, final URL source) {
showHelpDialog(parent, title, source);
}
/**
* Shows an informational message that does not interfere with
* program operation.
* The window title can be specified.
*
* @param title the title for the dialog box
* @param source the url of the message to display
* @param parent the parent for the dialog
*/
public static void showHelpDialog(final Component parent, final String title, final URL source) {
if (!config.isGUIEnabled()) { //text only
System.out.println("Help: " + title);
System.out.println(source.toString());
} else { //html
HTMLDialog dialog = new HTMLDialog(parent, source, title, JOptionPane.INFORMATION_MESSAGE);
dialog.setModal(false);
dialog.setAlwaysOnTop(true);
dialog.setVisible(true);
}
}
/**
* Shows an informational message that blocks user interaction until cleared.
* The window title is "Information".
*
* @param message the actual message to display, or the url of the message to display
*/
public static void showInformationDialog(final String message) {
showInformationDialog("Information", message);
}
/**
* Shows an informational message that blocks user interaction until cleared.
* The window title can be specified.
*
* @param title the title for the dialog box
* @param message the actual message to display, or the url of the message to display
*/
public static void showInformationDialog(final String title, final String message) {
showInformationDialog(parent, title, message);
}
/**
* Shows an informational message that blocks user interaction until cleared.
* The window title can be specified.
*
* @param title the title for the dialog box
* @param message the actual message to display, or the url of the message to display
* @param parent the parent for the dialog
*/
public static void showInformationDialog(final Component parent, final String title, final String message) {
if (!config.isGUIEnabled()) { //text only
System.out.println("Information: " + title);
System.out.println(message);
} else if (message.startsWith("http://")) { //html
new HTMLDialog(parent, message, title, JOptionPane.INFORMATION_MESSAGE).setVisible(true);
} else { //normal dialog
JOptionPane.showMessageDialog(parent, message, title, JOptionPane.INFORMATION_MESSAGE);
}
}
/**
* Shows a dialog for obtaining a single line of input.
* The window title is "Input".
*
* @param prompt the string to prompt the user with
*/
public static String showInputDialog(final String prompt) {
return showInputDialog("Input", prompt);
}
/**
* Shows a dialog for obtaining a single line of input.
* The window title can be specified.
*
* @param title window title
* @param prompt the string to prompt the user with
*/
public static String showInputDialog(final String title, final String prompt) {
return showInputDialog(parent, title, prompt);
}
/**
* Shows a dialog for obtaining a single line of input.
* The window title can be specified.
*
* @param title window title
* @param prompt the string to prompt the user with
* @param parent the parent for the dialog
*/
public static String showInputDialog(final Component parent, final String title, final String prompt) {
if (!config.isGUIEnabled()) { //text only
System.out.println("Input: " + title);
System.out.println(prompt);
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
String result = null;
while (result == null) {
try {
result = in.readLine();
} catch (IOException ioe) {
System.err.println(ioe.toString());
}
}
return result;
} else { //normal dialog
JOptionPane pane = new JOptionPane(prompt, JOptionPane.QUESTION_MESSAGE, JOptionPane.OK_CANCEL_OPTION);
pane.setWantsInput(true);
JDialog dialog = pane.createDialog(parent, title);
dialog.pack();
dialog.setVisible(true);
Object value = pane.getInputValue();
if (value == JOptionPane.UNINITIALIZED_VALUE) {
return null;
}
return (String) value;
}
}
/**
* Shows a dialog for obtaining a single line of input.
* The window title can be specified.
*
* @param title window title
* @param prompt the string to prompt the user with
* @param content the default contents of the input field
*/
public static String showInputDialog(final String title, final String prompt, final String content) {
return showInputDialog(parent, title, prompt, content);
}
/**
* Shows a dialog for obtaining a single line of input.
* The window title can be specified.
*
* @param parent the parent for the dialog
* @param title window title
* @param prompt the string to prompt the user with
* @param content the default contents of the input field
*/
public static String showInputDialog(final Component parent, final String title, final String prompt, final String content) {
final JTextField text = new JTextField(content, 30);
JOptionPane pane = new JOptionPane(new Object[]{prompt, text}, JOptionPane.QUESTION_MESSAGE, JOptionPane.OK_CANCEL_OPTION);
pane.setWantsInput(false);
JDialog dialog = pane.createDialog(parent, title);
dialog.pack();
dialog.setVisible(true);
Integer value = (Integer) pane.getValue();
if (value == null || value.intValue() == JOptionPane.CANCEL_OPTION || value.intValue() == JOptionPane.CLOSED_OPTION) {
return null;
}
return text.getText();
}
/**
* Shows an input dialog that allows the user to enter multiple lines of text.
* The window title is "Input".
*
* @param prompt the string to prompt the user with
*/
public static String showMultilineInputDialog(final String prompt) {
return showMultilineInputDialog("Input", prompt);
}
/**
* Shows an input dialog that allows the user to enter multiple lines of text.
* The window title can be specified.
*
* @param title window title
* @param prompt the String to prompt the user with
*/
public static String showMultilineInputDialog(final String title, final String prompt) {
return showMultilineInputDialog(title, prompt, "");
}
/**
* Shows an input dialog that allows the user to enter multiple lines of text.
* The window title can be specified.
*
* @param title window title
* @param prompt the String to prompt the user with
* @param content the default contents of the input field
*/
public static String showMultilineInputDialog(final String title, final String prompt, final String content) {
return showMultilineInputDialog(parent, title, prompt, content);
}
/**
* Shows an input dialog that allows the user to enter multiple lines of text.
* The window title can be specified.
*
* @param parent the parent for the dialog
* @param title window title
* @param prompt the String to prompt the user with
* @param content the default contents of the input field
*/
public static String showMultilineInputDialog(final Component parent, final String title, final String prompt, final String content) {
final JTextArea text = new JTextArea(content, 20, 40);
JOptionPane pane = new JOptionPane(new Object[]{prompt, new JScrollPane(text)}, JOptionPane.QUESTION_MESSAGE, JOptionPane.OK_CANCEL_OPTION);
pane.setWantsInput(false);
JDialog dialog = pane.createDialog(parent, title);
dialog.pack();
dialog.setVisible(true);
Integer value = (Integer) pane.getValue();
if (value == null || value.intValue() == JOptionPane.CANCEL_OPTION || value.intValue() == JOptionPane.CLOSED_OPTION) {
return null;
}
return text.getText();
}
/**
* Shows an option dialog box.
* The window title is "Input".
*
* @param prompt the string to prompt the user with
* @param possibleValues array of options to display
*/
public static Object showOptionDialog(final String prompt, final Object[] possibleValues) {
return showOptionDialog("Input", prompt, possibleValues);
}
/**
* Shows an option dialog box.
* The window title can be specified.
*
* @param title window title
* @param prompt the string to prompt the user with
* @param possibleValues array of options to display
*/
public static Object showOptionDialog(final String title, final String prompt, final Object[] possibleValues) {
return showOptionDialog(parent, title, prompt, possibleValues);
}
/**
* Shows an option dialog box.
* The window title can be specified.
*
* @param parent the parent for the dialog
* @param title window title
* @param prompt the string to prompt the user with
* @param possibleValues array of options to display
*/
public static Object showOptionDialog(final Component parent, final String title, final String prompt, final Object[] possibleValues) {
return JOptionPane.showInputDialog(parent, prompt, title,
JOptionPane.QUESTION_MESSAGE, null, possibleValues, possibleValues[0]);
}
/**
* Shows an editable option dialog box.
* The window title is "Input".
*
* @param prompt the string to prompt the user with
* @param possibleValues array of options to display
* @return the toString()ed item the user selected, or whatever was typed in
*/
public static String showOptionInputDialog(final String prompt, final Object[] possibleValues) {
return showOptionInputDialog("Input", prompt, possibleValues, possibleValues[0]);
}
/**
* Shows an editable option dialog box.
* The window title can be specified.
*
* @param title window title
* @param prompt the string to prompt the user with
* @param possibleValues array of options to display
* @return the toString()ed item the user selected, or whatever was typed in
*/
public static String showOptionInputDialog(final String title, final String prompt, final Object[] possibleValues) {
return showOptionInputDialog(title, prompt, possibleValues, possibleValues[0]);
}
/**
* Shows an editable option dialog box.
* The window title can be specified.
*
* @param title window title
* @param prompt the string to prompt the user with
* @param possibleValues array of options to display
* @param defaultValue the initial contents of the combobox
* @return the toString()ed item the user selected, or whatever was typed in
*/
public static String showOptionInputDialog(final String title, final String prompt, final Object[] possibleValues, final Object defaultValue) {
return showOptionInputDialog(parent, title, prompt, possibleValues, defaultValue);
}
/**
* Shows an editable option dialog box.
* The window title can be specified.
*
* @param parent the parent for the dialog
* @param title window title
* @param prompt the string to prompt the user with
* @param possibleValues array of options to display
* @param defaultValue the initial contents of the combobox
* @return the toString()ed item the user selected, or whatever was typed in
*/
public static String showOptionInputDialog(final Component parent, final String title, final String prompt, final Object[] possibleValues, final Object defaultValue) {
final JComboBox box = new JComboBox(possibleValues);
box.setEditable(true);
box.setSelectedItem(defaultValue);
JOptionPane pane = new JOptionPane(new Object[]{prompt, box}, JOptionPane.QUESTION_MESSAGE, JOptionPane.OK_CANCEL_OPTION);
pane.setWantsInput(false);
JDialog dialog = pane.createDialog(parent, title);
dialog.pack();
dialog.setVisible(true);
Integer value = (Integer) pane.getValue();
if (value == null || value.intValue() == JOptionPane.CANCEL_OPTION || value.intValue() == JOptionPane.CLOSED_OPTION) {
return null;
}
return box.getSelectedItem().toString();
}
/**
* Shows a dialog for obtaining a single line of input with obscured echo.
* The window title is "Password".
*
* @param prompt the string to prompt the user with
*/
public static String showPasswordDialog(final String prompt) {
return showPasswordDialog("Password", prompt);
}
/**
* Shows a dialog for obtaining a single line of input with obscured echo.
* The window title can be specified.
*
* @param title window title
* @param prompt the string to prompt the user with
*/
public static String showPasswordDialog(final String title, final String prompt) {
return showPasswordDialog(parent, title, prompt, null);
}
/**
* Shows a dialog for obtaining a single line of input with obscured echo.
* The window title can be specified.
*
* @param title window title
* @param prompt the string to prompt the user with
* @param content the default contents of the input field
*/
public static String showPasswordDialog(final String title, final String prompt, final String content) {
return showPasswordDialog(parent, title, prompt, content);
}
/**
* Shows a dialog for obtaining a single line of input with obscured echo.
* The window title can be specified.
*
* @param parent the parent for the dialog
* @param title window title
* @param prompt the string to prompt the user with
* @param content the default contents of the input field
*/
public static String showPasswordDialog(final Component parent, final String title, final String prompt, final String content) {
if (!config.isGUIEnabled()) { //text only
System.out.println("Password: " + title);
char[] result = null;
while (result == null) {
try {
result = getPassword(System.in, prompt);
} catch (IOException ioe) {
System.err.println(ioe.toString());
}
}
return new String(result);
} else { //normal dialog
final JPasswordField text = new JPasswordField(content);
text.setEchoChar('*');
JOptionPane pane = new JOptionPane(new Object[]{prompt, text}, JOptionPane.QUESTION_MESSAGE, JOptionPane.OK_CANCEL_OPTION);
pane.setWantsInput(false);
JDialog dialog = pane.createDialog(parent, title);
dialog.pack();
dialog.setVisible(true);
Integer value = (Integer) pane.getValue();
if (value == null || value.intValue() == JOptionPane.CANCEL_OPTION || value.intValue() == JOptionPane.CLOSED_OPTION) {
return null;
}
return new String(text.getPassword());
}
}
/**
* Shows a dialog for obtaining two single lines of input, one with normal and one with obscured echo.
* The window title can be specified.
*
* @param title window title
* @param namePrompt the 1st string to prompt the user with
* @param nameContent the default contents of the 1st input field
* @param passPrompt the 2nd string to prompt the user with
* @param passContent the default contents of the 2nd input field
*/
public static String[] showLoginDialog(final String title, final String namePrompt, final String nameContent, final String passPrompt, final String passContent) {
return showLoginDialog(parent, title, namePrompt, nameContent, passPrompt, passContent);
}
/**
* Shows a dialog for obtaining two single lines of input, one with normal and one with obscured echo.
* The window title can be specified.
*
* @param parent the parent for the dialog
* @param title window title
* @param namePrompt the 1st string to prompt the user with
* @param nameContent the default contents of the 1st input field
* @param passPrompt the 2nd string to prompt the user with
* @param passContent the default contents of the 2nd input field
*/
public static String[] showLoginDialog(final Component parent, final String title, final String namePrompt, final String nameContent, final String passPrompt, final String passContent) {
if (!config.isGUIEnabled()) { //text only
System.out.println("If you need to obtain a signon, visit:\n http://chill.colostate.edu/cgi-bin/user_service");
System.out.println("Input: " + title);
System.out.println(namePrompt);
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
String nameResult = null;
while (nameResult == null) {
try {
nameResult = in.readLine();
} catch (IOException ioe) {
System.err.println(ioe.toString());
}
}
System.out.println("Password: " + title);
char[] passResult = null;
while (passResult == null) {
try {
passResult = getPassword(System.in, passPrompt);
} catch (IOException ioe) {
System.err.println(ioe.toString());
}
}
return new String[]{nameResult, new String(passResult)};
} else { //normal dialog
boolean properHTMLsupport = !System.getProperty("java.version").startsWith("1.5"); //need newer than 1.5 for proper support
final JTextField name = new JTextField(nameContent, 10);
final JPasswordField pass = new JPasswordField(passContent);
final JCheckBox rememberpass = new JCheckBox("Save Password");
if (ConfigUtil.getString("Password", null) != null) {
rememberpass.setSelected(true);
}
pass.setEchoChar('*');
final JPanel panel = new JPanel();
final JOptionPane pane = new JOptionPane(panel, JOptionPane.QUESTION_MESSAGE, JOptionPane.OK_CANCEL_OPTION);
panel.setLayout(new GridLayout(4, 2, 5, 10));
panel.add(new JLabel(namePrompt, SwingConstants.RIGHT));
panel.add(name);
panel.add(new JLabel(passPrompt, SwingConstants.RIGHT));
panel.add(pass);
panel.add(new JLabel(" ", SwingConstants.RIGHT));
panel.add(rememberpass);
panel.add(new JLabel("If you need a signon, visit:", SwingConstants.RIGHT));
if (properHTMLsupport) {
final JButton userserv = new JButton(new AbstractAction("User Services") {
/**
*
*/
private static final long serialVersionUID = -7826677105074146774L;
public void actionPerformed(final ActionEvent ae) {
showHelpDialog(pane, "User Services", "http://chill.colostate.edu/cgi-bin/user_service");
}
});
panel.add(userserv);
} else {
final JTextField url = new JTextField("http://chill.colostate.edu/cgi-bin/user_service", 15);
panel.add(url);
}
EventQueue.invokeLater(new Runnable() {
public void run() {
name.requestFocusInWindow();
}
});
name.addActionListener(new ActionListener() {
public void actionPerformed(final ActionEvent ae) {
pass.requestFocusInWindow();
}
});
pane.setWantsInput(false);
JDialog dialog = pane.createDialog(parent, title);
dialog.pack();
dialog.setVisible(true);
Integer value = (Integer) pane.getValue();
if (value == null || value.intValue() == JOptionPane.CANCEL_OPTION || value.intValue() == JOptionPane.CLOSED_OPTION) {
return null;
}
if (rememberpass.isSelected()) {
ConfigUtil.put("Password", new String(pass.getPassword()));
} else {
ConfigUtil.put("Password", "");
}
return new String[]{name.getText(), new String(pass.getPassword())};
}
}
/**
* Shows an warning message that blocks user interaction until cleared.
* The window title is "Warning".
*
* @param message the actual message to display, or the url of the message to display
*/
public static void showWarningDialog(final String message) {
showWarningDialog("Warning", message);
}
/**
* Shows an warning message that blocks user interaction until cleared.
* The window title can be specified.
*
* @param title the title for the dialog box
* @param message the actual message to display, or the url of the message to display
*/
public static void showWarningDialog(final String title, final String message) {
showWarningDialog(parent, title, message);
}
/**
* Shows an warning message that blocks user interaction until cleared.
* The window title can be specified.
*
* @param title the title for the dialog box
* @param message the actual message to display, or the url of the message to display
* @param parent the parent for the dialog
*/
public static void showWarningDialog(final Component parent, final String title, final String message) {
if (!config.isGUIEnabled()) { //text only
System.err.println("Warning: " + title);
System.err.println(message);
} else if (message.startsWith("http://")) { //html
new HTMLDialog(parent, message, title, JOptionPane.WARNING_MESSAGE).setVisible(true);
} else { //normal dialog
JOptionPane.showMessageDialog(parent, message, title, JOptionPane.WARNING_MESSAGE);
}
}
/**
* An <code>HTMLDialog</code> displays its message (an HTML page) in a scrollable <code>JEditorPane</code>.
* Clicking a link within that page opens another <code>HTMLDialog<code> instance.
*/
public static class HTMLDialog {
protected final JEditorPane text = new JEditorPane();
protected final JPanel root = new JPanel();
protected JOptionPane pane;
protected JDialog dialog;
protected boolean modal;
protected boolean alwaysOnTop;
/**
* Constructs an initially invisible HTMLDialog displaying the contents of the specified webpage.
* If the page cannot be loaded, the URL itself is instead shown as plain text.
*
* @param parent the parent for the dialog
* @param source the URL to load the message from
* @param title the title for the dialog
* @param type the messageType as in <code>JOptionDialog</code>
*/
public HTMLDialog(final Component parent, final String source, final String title, final int type) {
try {
this.init(parent, new URL(source), title, type);
} catch (IOException ioe) {
this.dialog = (this.pane = new JOptionPane(source, type)).createDialog(parent, title);
}
}
/**
* Constructs an initially invisible HTMLDialog displaying the contents of the specified webpage.
* If the page cannot be loaded, the URL itself is instead shown as plain text.
*
* @param parent the parent for the dialog
* @param source the URL to load the message from
* @param title the title for the dialog
* @param type the messageType as in <code>JOptionDialog</code>
*/
public HTMLDialog(final Component parent, final URL source, final String title, final int type) {
try {
this.init(parent, source, title, type);
} catch (IOException ioe) {
this.dialog = (this.pane = new JOptionPane(source, type)).createDialog(parent, title);
}
}
/**
* Does the actual construction work
*/
private void init(final Component parent, final URL source, final String title, final int type) throws IOException {
this.text.setContentType("text/html");
this.text.setEditable(false);
this.root.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
this.pane = new JOptionPane(this.root, type, JOptionPane.DEFAULT_OPTION);
pane.setWantsInput(false);
this.dialog = pane.createDialog(parent, title);
this.text.setPage(source); //throws IOException
this.text.addHyperlinkListener(new HyperlinkListener() {
public void hyperlinkUpdate(final HyperlinkEvent he) {
if (he.getEventType() == EventType.ACTIVATED) {
HTMLDialog d = new HTMLDialog(parent, he.getURL(), title, type);
d.setModal(modal);
d.setAlwaysOnTop(alwaysOnTop);
d.setVisible(true);
}
}
});
this.root.add(new JScrollPane(text));
this.root.setLayout(new BoxLayout(root, BoxLayout.Y_AXIS));
this.setPreferredSize(new Dimension(600, 450));
this.setModal(true);
this.setAlwaysOnTop(true);
this.dialog.setResizable(true);
this.dialog.setLocationRelativeTo(parent); //centered
}
public void setVisible(final boolean visible) {
this.dialog.setVisible(visible);
}
public void setPreferredSize(final Dimension dim) {
this.root.setPreferredSize(dim);
this.dialog.pack();
}
public void setModal(final boolean modal) {
this.dialog.setModal(this.modal = modal);
}
public void setAlwaysOnTop(final boolean alwaysOnTop) {
this.dialog.setAlwaysOnTop(this.alwaysOnTop = alwaysOnTop);
}
}
/**
* Open an exported file using the system default program - will hopefully be unnecessary with java 6
*
* @param filename the path/name of the exported file
*/
public static void open(final String filename) {
try {
final String osname = System.getProperty("os.name");
String command;
if (osname.startsWith("Windows")) { //ME not supported
if (osname.indexOf("9") == -1) command = "cmd /c start"; //nt, 2k, xp
else command = "start"; //9x
} else if (osname.equals("Linux")) {
command = "googleearth";
} else if (osname.equals("Mac OS X")) {
command = "open";
} else {
System.err.println("Operating system not supported");
command = "rm";
}
Runtime.getRuntime().exec(command + " " + filename);
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
//--------------------------------------------------------------------------------------------------------//
//** Textmode password reading from http://java.sun.com/developer/technicalArticles/Security/pwordmask/ **//
//************* Should be replaced with Java 6 password reading ASAP *************************************//
//--------------------------------------------------------------------------------------------------------//
/**
* Prompts the user for a password and attempts to mask input with "*"
*
* @param in stream to be used (e.g. System.in)
* @param prompt The prompt to display to the user.
* @return The password as entered by the user.
*/
@SuppressWarnings("fallthrough")
public static final char[] getPassword(InputStream in, final String prompt) throws IOException {
MaskingThread maskingthread = new MaskingThread(prompt);
Thread thread = new Thread(maskingthread, "MaskingThread");
thread.start();
char[] lineBuffer;
char[] buf;
int i;
buf = lineBuffer = new char[128];
int room = buf.length;
int offset = 0;
int c;
loop:
while (true) {
switch (c = in.read()) {
case -1:
case '\n':
break loop;
case '\r':
int c2 = in.read();
if ((c2 != '\n') && (c2 != -1)) {
if (!(in instanceof PushbackInputStream)) {
in = new PushbackInputStream(in);
}
((PushbackInputStream) in).unread(c2);
} else {
break loop;
}
default:
if (--room < 0) {
buf = new char[offset + 128];
room = buf.length - offset - 1;
System.arraycopy(lineBuffer, 0, buf, 0, offset);
Arrays.fill(lineBuffer, ' ');
lineBuffer = buf;
}
buf[offset++] = (char) c;
break;
}
}
maskingthread.stopMasking();
if (offset == 0) {
return null;
}
char[] ret = new char[offset];
System.arraycopy(buf, 0, ret, 0, offset);
Arrays.fill(buf, ' ');
return ret;
}
/**
* This class attempts to erase characters echoed to the console.
*/
private static class MaskingThread extends Thread {
private volatile boolean stop;
private char echochar = '*';
/**
* @param prompt The prompt displayed to the user
*/
public MaskingThread(String prompt) {
System.out.print(prompt);
}
/**
* Begin masking until asked to stop.
*/
public void run() {
int priority = Thread.currentThread().getPriority();
Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
try {
stop = true;
while (stop) {
System.out.print("\010" + echochar);
try {
Thread.currentThread();
// attempt masking at this rate
Thread.sleep(1);
} catch (InterruptedException iex) {
Thread.currentThread().interrupt();
return;
}
}
} finally { // restore the original priority
Thread.currentThread().setPriority(priority);
}
}
/**
* Instruct the thread to stop masking.
*/
public void stopMasking() {
this.stop = false;
}
}
//--------------------------------------------------------------------------------------------------------//
//** Textmode password reading from http://java.sun.com/developer/technicalArticles/Security/pwordmask/ **//
//************* Should be replaced with Java 6 password reading ASAP *************************************//
//--------------------------------------------------------------------------------------------------------//
}