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