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