001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.gui.widgets;
003
004import java.awt.KeyboardFocusManager;
005import java.awt.event.FocusEvent;
006import java.awt.event.FocusListener;
007
008import javax.swing.JTextArea;
009import javax.swing.text.Document;
010
011import org.openstreetmap.josm.gui.MainApplication;
012import org.openstreetmap.josm.gui.MapFrame;
013
014/**
015 * Subclass of {@link JTextArea} that adds a "native" context menu (cut/copy/paste/select all).
016 * @since 5886
017 */
018public class JosmTextArea extends JTextArea implements FocusListener {
019
020    /**
021     * Constructs a new {@code JosmTextArea}. A default model is set, the initial string
022     * is null, and rows/columns are set to 0.
023     */
024    public JosmTextArea() {
025        this(null, null, 0, 0);
026    }
027
028    /**
029     * Constructs a new {@code JosmTextArea} with the specified text displayed.
030     * A default model is created and rows/columns are set to 0.
031     *
032     * @param text the text to be displayed, or null
033     */
034    public JosmTextArea(String text) {
035        this(null, text, 0, 0);
036    }
037
038    /**
039     * Constructs a new {@code JosmTextArea} with the given document model, and defaults
040     * for all of the other arguments (null, 0, 0).
041     *
042     * @param doc  the model to use
043     */
044    public JosmTextArea(Document doc) {
045        this(doc, null, 0, 0);
046    }
047
048    /**
049     * Constructs a new empty {@code JosmTextArea} with the specified number of
050     * rows and columns. A default model is created, and the initial
051     * string is null.
052     *
053     * @param rows the number of rows >= 0
054     * @param columns the number of columns >= 0
055     * @throws IllegalArgumentException if the rows or columns
056     *  arguments are negative.
057     */
058    public JosmTextArea(int rows, int columns) {
059        this(null, null, rows, columns);
060    }
061
062    /**
063     * Constructs a new {@code JosmTextArea} with the specified text and number
064     * of rows and columns. A default model is created.
065     *
066     * @param text the text to be displayed, or null
067     * @param rows the number of rows >= 0
068     * @param columns the number of columns >= 0
069     * @throws IllegalArgumentException if the rows or columns
070     *  arguments are negative.
071     */
072    public JosmTextArea(String text, int rows, int columns) {
073        this(null, text, rows, columns);
074    }
075
076    /**
077     * Constructs a new {@code JosmTextArea} with the specified number of rows
078     * and columns, and the given model.  All of the constructors
079     * feed through this constructor.
080     *
081     * @param doc the model to use, or create a default one if null
082     * @param text the text to be displayed, null if none
083     * @param rows the number of rows >= 0
084     * @param columns the number of columns >= 0
085     * @throws IllegalArgumentException if the rows or columns
086     *  arguments are negative.
087     */
088    public JosmTextArea(Document doc, String text, int rows, int columns) {
089        super(doc, text, rows, columns);
090        TextContextualPopupMenu.enableMenuFor(this, true);
091        addFocusListener(this);
092    }
093
094    /**
095     * Restore default behaviour of focus transfer with TAB, overriden by {@link JTextArea}.
096     * @return {@code this}
097     * @since 11308
098     */
099    public JosmTextArea transferFocusOnTab() {
100        // http://stackoverflow.com/a/525867/2257172
101        setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, null);
102        setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, null);
103        return this;
104    }
105
106    @Override
107    public void focusGained(FocusEvent e) {
108        MapFrame map = MainApplication.getMap();
109        if (map != null) {
110            map.keyDetector.setEnabled(false);
111        }
112    }
113
114    @Override
115    public void focusLost(FocusEvent e) {
116        MapFrame map = MainApplication.getMap();
117        if (map != null) {
118            map.keyDetector.setEnabled(true);
119        }
120    }
121}