// License: GPL. For details, see LICENSE file. package org.openstreetmap.josm.gui.widgets; import java.awt.event.ActionEvent; import java.awt.event.FocusEvent; import java.awt.event.FocusListener; import java.beans.PropertyChangeListener; import javax.swing.Action; import javax.swing.JPasswordField; import javax.swing.TransferHandler; import javax.swing.text.Document; import javax.swing.text.JTextComponent; import org.openstreetmap.josm.Main; /** * A subclass of {@link JPasswordField} to implement a workaround to * <a href="https://bugs.openjdk.java.net/browse/JDK-6322854">JDK bug 6322854</a>. * * @see <a href="https://josm.openstreetmap.de/ticket/8404">https://josm.openstreetmap.de/ticket/8404</a> * @see <a href="https://hg.netbeans.org/main/rev/33cb2e81b640">https://hg.netbeans.org/main/rev/33cb2e81b640</a> * @since 5752 */ public class JosmPasswordField extends JPasswordField implements FocusListener { /** * Constructs a new <code>JosmPasswordField</code>, * with a default document, <code>null</code> starting * text string, and 0 column width. */ public JosmPasswordField() { workaroundJdkBug6322854(this); addFocusListener(this); } /** * Constructs a new <code>JosmPasswordField</code> that uses the * given text storage model and the given number of columns. * This is the constructor through which the other constructors feed. * The echo character is set to '*', but may be changed by the current * Look and Feel. If the document model is * <code>null</code>, a default one will be created. * * @param doc the text storage to use * @param txt the text to be displayed, <code>null</code> if none * @param columns the number of columns to use to calculate * the preferred width >= 0; if columns is set to zero, the * preferred width will be whatever naturally results from * the component implementation */ public JosmPasswordField(Document doc, String txt, int columns) { super(doc, txt, columns); workaroundJdkBug6322854(this); addFocusListener(this); } /** * Constructs a new empty <code>JosmPasswordField</code> with the specified * number of columns. A default model is created, and the initial string * is set to <code>null</code>. * * @param columns the number of columns >= 0 */ public JosmPasswordField(int columns) { super(columns); workaroundJdkBug6322854(this); addFocusListener(this); } /** * Constructs a new <code>JPasswordField</code> initialized with * the specified text and columns. The document model is set to * the default. * * @param text the text to be displayed, <code>null</code> if none * @param columns the number of columns >= 0 */ public JosmPasswordField(String text, int columns) { super(text, columns); workaroundJdkBug6322854(this); addFocusListener(this); } /** * Constructs a new <code>JosmPasswordField</code> initialized * with the specified text. The document model is set to the * default, and the number of columns to 0. * * @param text the text to be displayed, <code>null</code> if none */ public JosmPasswordField(String text) { super(text); workaroundJdkBug6322854(this); addFocusListener(this); } @Override public void focusGained(FocusEvent e) { if (Main.map != null) { Main.map.keyDetector.setEnabled(false); } } @Override public void focusLost(FocusEvent e) { if (Main.map != null) { Main.map.keyDetector.setEnabled(true); } } /** * Implements a workaround to <a href="https://bugs.openjdk.java.net/browse/JDK-6322854">JDK bug 6322854</a>. * This method can be deleted after Oracle decides to fix this bug... * @param text The {@link JTextComponent} to protect. */ public static final void workaroundJdkBug6322854(final JTextComponent text) { if (text != null) { text.getActionMap().put("paste", new Action() { private final Action pasteAction = TransferHandler.getPasteAction(); @Override public void actionPerformed(ActionEvent e) { try { pasteAction.actionPerformed(e); } catch (NullPointerException npe) { // NOPMD Main.error(npe, "NullPointerException occured because of JDK bug 6322854. " +"Copy/Paste operation has not been performed. Please complain to Oracle: "+ "https://bugs.openjdk.java.net/browse/JDK-6322854"); } } @Override public void setEnabled(boolean b) { pasteAction.setEnabled(b); } @Override public void removePropertyChangeListener(PropertyChangeListener listener) { pasteAction.removePropertyChangeListener(listener); } @Override public void putValue(String key, Object value) { pasteAction.putValue(key, value); } @Override public boolean isEnabled() { return pasteAction.isEnabled(); } @Override public Object getValue(String key) { return pasteAction.getValue(key); } @Override public void addPropertyChangeListener(PropertyChangeListener listener) { pasteAction.addPropertyChangeListener(listener); } }); } } }