001: /*
002: * DefaultTextFieldHandler.java
003: *
004: * Copyright (C) 1998-2003 Peter Graves
005: * $Id: DefaultTextFieldHandler.java,v 1.4 2003/07/18 15:23:41 piso Exp $
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License
009: * as published by the Free Software Foundation; either version 2
010: * of the License, or (at your option) any later version.
011: *
012: * This program is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
015: * GNU General Public License for more details.
016: *
017: * You should have received a copy of the GNU General Public License
018: * along with this program; if not, write to the Free Software
019: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
020: */
021:
022: package org.armedbear.j;
023:
024: import java.awt.Color;
025: import java.awt.Container;
026: import java.awt.event.ActionEvent;
027: import java.awt.event.ActionListener;
028: import java.awt.event.KeyEvent;
029: import java.awt.event.TextEvent;
030: import java.awt.event.TextListener;
031: import java.util.List;
032: import javax.swing.JDialog;
033: import javax.swing.JMenuItem;
034: import javax.swing.JPopupMenu;
035:
036: public class DefaultTextFieldHandler implements Constants,
037: TextFieldHandler {
038: protected final Editor editor;
039: protected final HistoryTextField textField;
040:
041: protected List completions;
042: protected int index;
043:
044: private Expansion expansion;
045: private String savedText;
046: private String head;
047:
048: public DefaultTextFieldHandler(Editor editor,
049: HistoryTextField textField) {
050: this .editor = editor;
051: Debug.assertTrue(editor != null);
052: this .textField = textField;
053: }
054:
055: public DefaultTextFieldHandler(HistoryTextField textField) {
056: this (Editor.currentEditor(), textField);
057: }
058:
059: public void enter() {
060: }
061:
062: public void escape() {
063: Container c = textField.getParent();
064: while (true) {
065: if (c instanceof JDialog)
066: return;
067: if (c == null)
068: break;
069: c = c.getParent();
070: }
071: // Text field is not in a dialog box. We must be dealing with the
072: // location bar.
073: Debug.assertTrue(editor != null);
074: editor.ensureActive();
075: editor.setFocusToDisplay();
076: editor.updateLocation();
077: }
078:
079: public boolean wantTab() {
080: return false;
081: }
082:
083: public void tab() {
084: if (textField != null) {
085: String prefix = textField.getText();
086: String s = getCompletion(prefix);
087: if (s != null && !s.equals(prefix)) {
088: textField.setText(s);
089: textField.setCaretPosition(s.length());
090: }
091: }
092: }
093:
094: public void shiftTab() {
095: if (textField != null) {
096: String s = getPreviousCompletion();
097: if (s != null) {
098: String text = textField.getText();
099: if (!s.equals(text)) {
100: textField.setText(s);
101: textField.setCaretPosition(s.length());
102: }
103: }
104: }
105: }
106:
107: public void resetCompletions() {
108: completions = null;
109: }
110:
111: protected String getCompletion(String prefix) {
112: if (completions == null) {
113: completions = getCompletions(prefix);
114: index = 0;
115: }
116: if (completions == null || completions.size() == 0)
117: return null;
118: if (index >= completions.size())
119: index = 0;
120: return (String) completions.get(index++);
121: }
122:
123: private String getPreviousCompletion() {
124: if (completions != null && completions.size() > 1) {
125: index -= 2;
126: if (index < 0)
127: index += completions.size();
128: return (String) completions.get(index++);
129: }
130: return null;
131: }
132:
133: public List getCompletions(String prefix) {
134: return null;
135: }
136:
137: private void killLine() {
138: textField.setText(textField.getText().substring(0,
139: textField.getCaretPosition()));
140: }
141:
142: private void expand() {
143: if (expansion == null) {
144: // New expansion.
145: savedText = textField.getText();
146: int index = savedText.lastIndexOf(' ');
147: if (index >= 0) {
148: head = savedText.substring(0, index + 1);
149: expansion = textField.getHandler().getExpansion(
150: savedText.substring(index + 1));
151: } else {
152: Debug.assertTrue(head == null);
153: expansion = textField.getHandler().getExpansion(
154: savedText);
155: }
156: }
157: final String candidate = expansion.getNextCandidate();
158: if (candidate != null) {
159: if (head != null)
160: textField.setText(head.concat(candidate));
161: else
162: textField.setText(candidate);
163: }
164: }
165:
166: public void resetExpansion() {
167: expansion = null;
168: savedText = null;
169: head = null;
170: }
171:
172: public Expansion getExpansion(String prefix) {
173: return new Expansion(editor.getBuffer(), prefix, prefix);
174: }
175:
176: protected void reset() {
177: textField.resetHistory();
178: textField.getHandler().resetCompletions();
179: }
180:
181: public void keyPressed(KeyEvent e) {
182: TextFieldHandler handler = textField.getHandler();
183: if (handler == null)
184: return;
185: if (handler != this )
186: Debug.bug();
187: final char keyChar = e.getKeyChar();
188: final int keyCode = e.getKeyCode();
189: final int modifiers = e.getModifiers();
190: switch (keyCode) {
191: case KeyEvent.VK_ENTER:
192: resetExpansion();
193: // Make sure user can see what he typed.
194: textField.paintImmediately(0, 0, textField.getWidth(),
195: textField.getHeight());
196: e.consume();
197: handler.enter();
198: return;
199: case KeyEvent.VK_ESCAPE:
200: if (expansion != null) {
201: // Cancel expansion.
202: textField.setText(savedText);
203: resetExpansion();
204: // Consume key event so parent will ignore it.
205: e.consume();
206: } else
207: handler.escape();
208: return;
209: case KeyEvent.VK_TAB:
210: resetExpansion();
211: if (handler.wantTab()) {
212: if (modifiers == 0) {
213: e.consume();
214: handler.tab();
215: } else if (modifiers == SHIFT_MASK) {
216: e.consume();
217: handler.shiftTab();
218: }
219: }
220: return;
221: case KeyEvent.VK_UP:
222: case KeyEvent.VK_KP_UP:
223: resetExpansion();
224: textField.previousHistory();
225: return;
226: case KeyEvent.VK_P:
227: resetExpansion();
228: if (modifiers == CTRL_MASK)
229: textField.previousHistory();
230: else
231: reset();
232: return;
233: case KeyEvent.VK_DOWN:
234: case KeyEvent.VK_KP_DOWN:
235: resetExpansion();
236: if (modifiers == ALT_MASK)
237: showPopup();
238: else
239: textField.nextHistory();
240: return;
241: case KeyEvent.VK_N:
242: resetExpansion();
243: if (modifiers == CTRL_MASK)
244: textField.nextHistory();
245: else
246: reset();
247: return;
248: case KeyEvent.VK_SHIFT:
249: case KeyEvent.VK_CONTROL:
250: case KeyEvent.VK_META:
251: case KeyEvent.VK_ALT:
252: return;
253: default:
254: reset();
255: break;
256: }
257: KeyMapping mapping = editor.getKeyMapping(keyChar, keyCode,
258: modifiers);
259: if (mapping != null) {
260: Object command = mapping.getCommand();
261: if (command == "killLine")
262: killLine();
263: else if (command == "expand") {
264: expand();
265: return; // Don't call resetExpansion()!
266: }
267: }
268: resetExpansion();
269: }
270:
271: public void keyReleased(KeyEvent e) {
272: TextListener textListener = textField.getTextListener();
273: if (textListener != null)
274: textListener.textValueChanged(new TextEvent(this ,
275: TextEvent.TEXT_VALUE_CHANGED));
276: }
277:
278: public void keyTyped(KeyEvent e) {
279: }
280:
281: private void showPopup() {
282: if (textField == null)
283: return;
284: History history = textField.getHistory();
285: if (history == null)
286: return;
287: final String existing = textField.getText();
288: JPopupMenu popup = null;
289: for (int i = history.size(); i-- > 0;) {
290: String s = history.get(i);
291: if (s.equals(existing))
292: continue;
293: if (popup == null)
294: popup = new JPopupMenu();
295: JMenuItem menuItem = new JMenuItem();
296: menuItem.setText(history.get(i));
297: menuItem.setActionCommand(s);
298: menuItem.addActionListener(popupActionListener);
299: popup.add(menuItem);
300: }
301: if (popup != null)
302: popup.show(textField, 0, textField.getHeight());
303: }
304:
305: private ActionListener popupActionListener = new ActionListener() {
306: public void actionPerformed(ActionEvent e) {
307: textField.setText(e.getActionCommand());
308: enter();
309: }
310: };
311: }
|