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}