001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.gui.widgets; 003 004import java.awt.event.ActionEvent; 005import java.beans.PropertyChangeListener; 006 007import javax.swing.Action; 008import javax.swing.JPasswordField; 009import javax.swing.TransferHandler; 010import javax.swing.text.Document; 011import javax.swing.text.JTextComponent; 012 013import org.openstreetmap.josm.Main; 014 015/** 016 * A subclass of {@link JPasswordField} to implement a workaround to 017 * <a href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6322854">JDK bug 6322854</a>. 018 * This class can be deleted after Oracle decides to fix this bug... 019 * 020 * @since 5752 021 * @see <a href="http://josm.openstreetmap.de/ticket/8404">http://josm.openstreetmap.de/ticket/8404</a> 022 * @see <a href="http://hg.netbeans.org/main/rev/33cb2e81b640">http://hg.netbeans.org/main/rev/33cb2e81b640</a> 023 */ 024public class JosmPasswordField extends JPasswordField { 025 026 /** 027 * Constructs a new <code>JosmPasswordField</code>, 028 * with a default document, <code>null</code> starting 029 * text string, and 0 column width. 030 */ 031 public JosmPasswordField() { 032 workaroundJdkBug6322854(this); 033 } 034 035 /** 036 * Constructs a new <code>JosmPasswordField</code> that uses the 037 * given text storage model and the given number of columns. 038 * This is the constructor through which the other constructors feed. 039 * The echo character is set to '*', but may be changed by the current 040 * Look and Feel. If the document model is 041 * <code>null</code>, a default one will be created. 042 * 043 * @param doc the text storage to use 044 * @param txt the text to be displayed, <code>null</code> if none 045 * @param columns the number of columns to use to calculate 046 * the preferred width >= 0; if columns is set to zero, the 047 * preferred width will be whatever naturally results from 048 * the component implementation 049 */ 050 public JosmPasswordField(Document doc, String txt, int columns) { 051 super(doc, txt, columns); 052 workaroundJdkBug6322854(this); 053 } 054 055 /** 056 * Constructs a new empty <code>JosmPasswordField</code> with the specified 057 * number of columns. A default model is created, and the initial string 058 * is set to <code>null</code>. 059 * 060 * @param columns the number of columns >= 0 061 */ 062 public JosmPasswordField(int columns) { 063 super(columns); 064 workaroundJdkBug6322854(this); 065 } 066 067 /** 068 * Constructs a new <code>JPasswordField</code> initialized with 069 * the specified text and columns. The document model is set to 070 * the default. 071 * 072 * @param text the text to be displayed, <code>null</code> if none 073 * @param columns the number of columns >= 0 074 */ 075 public JosmPasswordField(String text, int columns) { 076 super(text, columns); 077 workaroundJdkBug6322854(this); 078 } 079 080 /** 081 * Constructs a new <code>JosmPasswordField</code> initialized 082 * with the specified text. The document model is set to the 083 * default, and the number of columns to 0. 084 * 085 * @param text the text to be displayed, <code>null</code> if none 086 */ 087 public JosmPasswordField(String text) { 088 super(text); 089 workaroundJdkBug6322854(this); 090 } 091 092 /** 093 * Implements a workaround to <a href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6322854">JDK bug 6322854</a>. 094 * @param text The {@link JTextComponent} to protect. 095 */ 096 public static final void workaroundJdkBug6322854(final JTextComponent text) { 097 if (text != null) { 098 text.getActionMap().put("paste", new Action() { 099 100 private final Action pasteAction = TransferHandler.getPasteAction(); 101 102 @Override 103 public void actionPerformed(ActionEvent e) { 104 try { 105 pasteAction.actionPerformed(e); 106 } catch (NullPointerException npe) { 107 Main.error("NullPointerException occured because of JDK bug 6322854. " 108 +"Copy/Paste operation has not been performed. Please complain to Oracle: "+ 109 "http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6322854"); 110 } 111 } 112 113 @Override 114 public void setEnabled(boolean b) { 115 pasteAction.setEnabled(b); 116 } 117 118 @Override 119 public void removePropertyChangeListener(PropertyChangeListener listener) { 120 pasteAction.removePropertyChangeListener(listener); 121 } 122 123 @Override 124 public void putValue(String key, Object value) { 125 pasteAction.putValue(key, value); 126 } 127 128 @Override 129 public boolean isEnabled() { 130 return pasteAction.isEnabled(); 131 } 132 133 @Override 134 public Object getValue(String key) { 135 return pasteAction.getValue(key); 136 } 137 138 @Override 139 public void addPropertyChangeListener(PropertyChangeListener listener) { 140 pasteAction.addPropertyChangeListener(listener); 141 } 142 }); 143 } 144 } 145}