KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > armedbear > j > OpenFileTextFieldHandler


1 /*
2  * OpenFileTextFieldHandler.java
3  *
4  * Copyright (C) 1998-2004 Peter Graves
5  * $Id: OpenFileTextFieldHandler.java,v 1.54 2004/09/20 00:44:11 piso Exp $
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20  */

21
22 package org.armedbear.j;
23
24 import gnu.regexp.RE;
25 import gnu.regexp.REMatch;
26 import gnu.regexp.UncheckedRE;
27 import java.awt.Component JavaDoc;
28 import java.awt.event.InputEvent JavaDoc;
29 import java.awt.event.KeyEvent JavaDoc;
30 import java.awt.event.MouseEvent JavaDoc;
31 import java.awt.event.MouseListener JavaDoc;
32 import java.lang.reflect.Method JavaDoc;
33 import java.util.ArrayList JavaDoc;
34 import java.util.List JavaDoc;
35 import javax.swing.JList JavaDoc;
36 import javax.swing.JPopupMenu JavaDoc;
37 import javax.swing.JScrollPane JavaDoc;
38 import javax.swing.MenuElement JavaDoc;
39 import javax.swing.MenuSelectionManager JavaDoc;
40 import javax.swing.SwingUtilities JavaDoc;
41 import org.armedbear.j.mail.MailCommands;
42
43 public final class OpenFileTextFieldHandler extends DefaultTextFieldHandler
44     implements Constants, MouseListener JavaDoc
45 {
46     private static final boolean filenamesIgnoreCase =
47         Platform.isPlatformWindows();
48
49     private String JavaDoc title = "Open File";
50
51     // Options.
52
private boolean allowRemote = true;
53     private boolean fileMustExist = false;
54     private boolean checkBuffers = true;
55     private boolean checkSourcePath = true;
56
57     private Object JavaDoc returned;
58     private String JavaDoc encoding;
59
60     private JPopupMenu JavaDoc popup;
61     private JList JavaDoc listbox;
62
63     private String JavaDoc originalText;
64     private String JavaDoc originalPrefix;
65
66     public OpenFileTextFieldHandler(Editor editor, HistoryTextField textField)
67     {
68         super(editor, textField);
69         textField.addMouseListener(this);
70     }
71
72     public final void setTitle(String JavaDoc s)
73     {
74         title = s;
75     }
76
77     public final void setAllowRemote(boolean b)
78     {
79         allowRemote = b;
80     }
81
82     public final void setFileMustExist(boolean b)
83     {
84         fileMustExist = b;
85     }
86
87     public final void setCheckBuffers(boolean b)
88     {
89         checkBuffers = b;
90     }
91
92     public final void setCheckSourcePath(boolean b)
93     {
94         checkSourcePath = b;
95     }
96
97     public void enter()
98     {
99         final Buffer buffer = editor.getBuffer();
100         String JavaDoc entry = textField.getText();
101         if (!entry.equals(buffer.getFileNameForDisplay()))
102             saveHistory();
103         entry = preprocess(entry);
104         if (encoding != null && !Utilities.isSupportedEncoding(encoding)) {
105             FastStringBuffer sb =
106                 new FastStringBuffer("Unsupported encoding \"");
107             sb.append(encoding);
108             sb.append('"');
109             error(sb.toString());
110             return;
111         }
112         File currentDir = buffer.getCompletionDirectory();
113         if (entry.length() == 0) {
114             returned = currentDir;
115             done();
116             return;
117         }
118         // Aliases.
119
String JavaDoc value = editor.getAlias(entry);
120         if (value != null)
121             entry = value;
122         if (entry.startsWith("pop://") || entry.startsWith("{") ||
123             entry.startsWith("mailbox:")) {
124             MailCommands.openMailbox(editor, entry);
125             editor.ensureActive();
126             editor.setFocusToDisplay();
127             editor.updateLocation();
128             editor.updateDisplay();
129             return;
130         }
131         File candidate = null;
132         if (Utilities.isFilenameAbsolute(entry)) {
133             candidate = File.getInstance(currentDir, entry);
134             if (candidate == null) {
135                 error("Invalid path");
136                 return;
137             }
138         } else if (entry.startsWith("./") || entry.startsWith(".\\")) {
139             // Path specified is relative to current directory (even if remote).
140
candidate = File.getInstance(currentDir, entry);
141             if (candidate == null) {
142                 error("Invalid path");
143                 return;
144             }
145         }
146         if (candidate != null) {
147             if (candidate.isRemote()) {
148                 if (!allowRemote) {
149                     error("File is remote");
150                     return;
151                 }
152             } else {
153                 // Not remote.
154
if (!candidate.exists()) {
155                     if (fileMustExist) {
156                         error("File not found");
157                         return;
158                     }
159                     if (!checkParentDirectory(candidate, title)) {
160                         editor.setFocusToDisplay();
161                         editor.updateLocation();
162                         return;
163                     }
164                 }
165             }
166             returned = candidate;
167             done();
168             return;
169         }
170         // Not absolute. Look in current directory.
171
candidate = File.getInstance(currentDir, entry);
172         if (candidate != null && candidate.exists()) {
173             returned = candidate;
174             done();
175             return;
176         }
177         // Not in current directory. Look for a match in one of the current
178
// buffers.
179
if (checkBuffers) {
180             for (BufferIterator it = new BufferIterator(); it.hasNext();) {
181                 Buffer buf = it.nextBuffer();
182                 if (buf.getFile() == null)
183                     continue;
184                 boolean found;
185                 if (filenamesIgnoreCase)
186                     found = buf.getFile().getName().equalsIgnoreCase(entry);
187                 else
188                     found = buf.getFile().getName().equals(entry);
189                 if (found) {
190                     returned = buf;
191                     done();
192                     return;
193                 }
194             }
195         }
196         // Not currently in a buffer. Look in source and include paths as
197
// appropriate.
198
if (checkSourcePath) {
199             candidate = Utilities.findFile(editor, entry);
200             if (candidate != null) {
201                 returned = candidate;
202                 done();
203                 return;
204             }
205         }
206         // Not found in source or include path.
207
if (allowRemote) {
208             if (entry.startsWith("www.")) {
209                 returned = File.getInstance("http://".concat(entry));
210                 done();
211                 return;
212             }
213             if (entry.startsWith("ftp.")) {
214                 returned = File.getInstance("ftp://".concat(entry));
215                 done();
216                 return;
217             }
218         }
219         // We failed. Use current directory.
220
if (currentDir.isRemote())
221             currentDir = Directories.getUserHomeDirectory();
222         candidate = File.getInstance(currentDir, entry);
223         if (candidate == null) {
224             error("Invalid path");
225             return;
226         }
227         if (fileMustExist && !candidate.exists()) {
228             error("File not found");
229             return;
230         }
231         if (!checkParentDirectory(candidate, title)) {
232             editor.setFocusToDisplay();
233             editor.updateLocation();
234             return;
235         }
236         returned = candidate;
237         done();
238     }
239
240     private String JavaDoc preprocess(String JavaDoc s)
241     {
242         encoding = null;
243         s = s.trim();
244         if (s.startsWith("-e ")) {
245             s = s.substring(3).trim();
246             int index = s.indexOf(' ');
247             encoding = s.substring(0, index);
248             return s.substring(index+1).trim();
249         }
250         int index = s.indexOf(" -e ");
251         if (index < 0)
252             return s; // No encoding specified.
253
encoding = s.substring(index+4).trim();
254         return s.substring(0, index).trim();
255     }
256
257     private boolean checkParentDirectory(File file, String JavaDoc context)
258     {
259         File parentDir = file.getParentFile();
260         if (parentDir != null && parentDir.isDirectory())
261             return true;
262         FastStringBuffer sb = new FastStringBuffer("Invalid path \"");
263         sb.append(file.canonicalPath());
264         sb.append('"');
265         MessageDialog.showMessageDialog(sb.toString(), context);
266         return false;
267     }
268
269     private void done()
270     {
271         Object JavaDoc owner = textField.getOwner();
272         if (owner instanceof OpenFileDialog) {
273             OpenFileDialog dialog = (OpenFileDialog) owner;
274             dialog.setResult(returned);
275             dialog.ok();
276             return;
277         }
278         Debug.assertTrue(editor != null);
279         Buffer buf = null;
280         if (returned instanceof Buffer) {
281             buf = (Buffer) returned;
282         } else if (returned instanceof File) {
283             File file = (File) returned;
284             file.setEncoding(encoding);
285             if (file instanceof HttpFile) {
286                 if (Editor.getModeList().modeAccepts(IMAGE_MODE, file.getName())) {
287                     buf = Editor.getBufferList().findBuffer(file);
288                     if (buf == null)
289                         buf = new RemoteBuffer(file);
290                 } else if (Editor.preferences().getBooleanProperty(Property.ENABLE_WEB)) {
291                     int modeId =
292                         Editor.getModeList().getModeIdForFileName(file.getName());
293                     if (modeId < 0 || modeId == HTML_MODE) {
294                         if (editor.getMode() instanceof WebMode) {
295                             // Current buffer is already a web buffer.
296
buf = editor.getBuffer();
297                             Debug.assertTrue(buf instanceof WebBuffer);
298                             ((WebBuffer)buf).saveHistory(buf.getFile(),
299                                                          buf.getAbsoluteOffset(editor.getDot()),
300                                                          ((WebBuffer)buf).getContentType());
301                             // If we don't call setCache(null), go() will use the
302
// existing cache.
303
buf.setCache(null);
304                             ((WebBuffer)buf).go(file, 0, null);
305                         } else {
306                             // Look for existing buffer.
307
for (BufferIterator it = new BufferIterator(); it.hasNext();) {
308                                 Buffer b = it.nextBuffer();
309                                 if (b instanceof WebBuffer && b.getFile().equals(file)) {
310                                     buf = b;
311                                     break;
312                                 }
313                             }
314                             if (buf == null) {
315                                 // Existing buffer not found.
316
buf = WebBuffer.createWebBuffer(file, null, null);
317                             }
318                         }
319                     }
320                 }
321             }
322             if (buf == null)
323                 buf = editor.openFile(file);
324         }
325         Editor.setCurrentEditor(editor);
326         if (buf != null && buf != editor.getBuffer()) {
327             editor.makeNext(buf);
328             editor.switchToBuffer(buf);
329         }
330         if (Editor.getEditorList().contains(editor)) {
331             editor.ensureActive();
332             editor.setFocusToDisplay();
333             editor.updateLocation();
334             editor.updateDisplay();
335         }
336     }
337
338     private void saveHistory()
339     {
340         final History history = textField.getHistory();
341         if (history != null) {
342             String JavaDoc entry = textField.getText().trim();
343             if (entry.length() > 0) {
344                 history.append(entry);
345                 history.save();
346             }
347         }
348     }
349
350     public void escape()
351     {
352         if (popup != null) {
353             Debug.bug();
354             popup.setVisible(false);
355             popup = null;
356         }
357         Object JavaDoc owner = textField.getOwner();
358         if (owner instanceof OpenFileDialog) {
359             OpenFileDialog dialog = (OpenFileDialog) owner;
360             dialog.cancel();
361         } else {
362             // Using location bar.
363
editor.setFocusToDisplay();
364             editor.updateLocation();
365             editor.ensureActive();
366         }
367     }
368
369     public boolean wantTab()
370     {
371         return true;
372     }
373
374     public void tab()
375     {
376         final String JavaDoc entry = textField.getText();
377         if (entry.startsWith("http:") || entry.startsWith("https:") ||
378             entry.startsWith("ftp:"))
379             return;
380         final File dir = editor.getCompletionDirectory();
381         if (dir == null)
382             return;
383         String JavaDoc prefix = null;
384         if (Utilities.isFilenameAbsolute(entry) || entry.startsWith("..")) {
385             File file = File.getInstance(dir, entry);
386             if (file != null) {
387                 if (file.isRemote())
388                     prefix = file.netPath();
389                 else if (dir.isRemote())
390                     prefix = file.netPath();
391                 else
392                     prefix = file.canonicalPath();
393                 if (entry.endsWith(LocalFile.getSeparator()))
394                     prefix = prefix.concat(LocalFile.getSeparator());
395             }
396         } else
397             prefix = entry;
398         if (prefix == null)
399             return;
400         editor.setWaitCursor();
401         final boolean showCompletionList;
402         if (textField.getOwner() instanceof OpenFileDialog) {
403             showCompletionList = false;
404         } else {
405             showCompletionList = Editor.preferences().getBooleanProperty(
406                 Property.SHOW_COMPLETION_LIST);
407         }
408         if (showCompletionList) {
409             if (popup == null) {
410                 long start = System.currentTimeMillis();
411                 completions = getCompletions(prefix);
412                 long elapsed = System.currentTimeMillis() - start;
413                 Log.debug("getCompletions " + elapsed + " ms " +
414                           completions.size() + " completions");
415                 index = 0;
416                 originalText = textField.getText();
417                 originalPrefix = prefix;
418                 if (completions.size() == 1) {
419                     String JavaDoc s = (String JavaDoc) completions.get(0);
420                     textField.setText(s);
421                     Runnable JavaDoc r = new Runnable JavaDoc() {
422                         public void run()
423                         {
424                             textField.setCaretPosition(textField.getText().length());
425                         }
426                     };
427                     SwingUtilities.invokeLater(r);
428                 } else if (completions.size() > 1)
429                     showCompletionsPopup();
430             } else
431                 tabPopup(+1, true);
432         } else {
433             // No completion list.
434
while (true) {
435                 String JavaDoc s = getCompletion(prefix);
436                 if (s == null)
437                     break;
438                 if (s.equals(entry)) {
439                     // Only one possible completion. Accept it and continue.
440
prefix = entry;
441                     reset();
442                     File file = File.getInstance(dir, entry);
443                     if (file != null && file.isDirectory())
444                         continue;
445                     else
446                         break;
447                 }
448                 // More than one possible completion. Present the current one
449
// and let the user decide what to do next.
450
textField.setText(s);
451                 textField.setCaretPosition(s.length());
452                 break;
453             }
454         }
455         editor.setDefaultCursor();
456     }
457
458     public List JavaDoc getCompletions(String JavaDoc prefix)
459     {
460         final File dir = editor.getCompletionDirectory();
461         ArrayList JavaDoc completions = new ArrayList JavaDoc();
462         final String JavaDoc sourcePath = checkSourcePath ? getSourcePath() : null;
463         prefix = File.normalize(prefix);
464         boolean ignoreCase = Platform.isPlatformWindows() ||
465             Editor.preferences().getBooleanProperty(
466                 Property.FILENAME_COMPLETIONS_IGNORE_CASE);
467         FilenameCompletion completion =
468             new FilenameCompletion(dir, prefix, sourcePath, ignoreCase);
469         final File currentDirectory = getCurrentDirectory();
470         List JavaDoc files = completion.listFiles();
471         if (files != null) {
472             for (int i = 0, limit = files.size(); i < limit; i++) {
473                 final File file = (File) files.get(i);
474                 final String JavaDoc name = getNameForFile(file, currentDirectory);
475                 if (file.isDirectory()) {
476                     addCompletion(completions, name.concat(file.getSeparator()),
477                                   ignoreCase);
478                     continue;
479                 }
480                 if (isExcluded(name))
481                     continue;
482                 addCompletion(completions, name, ignoreCase);
483             }
484         }
485         if (checkBuffers && !Utilities.isFilenameAbsolute(prefix) &&
486             prefix.indexOf(LocalFile.getSeparatorChar()) < 0) {
487             // Short name.
488
addCompletionsFromBufferList(completions, prefix, currentDirectory,
489                                          ignoreCase);
490         }
491         return completions;
492     }
493
494     private void addCompletionsFromBufferList(List JavaDoc list, String JavaDoc prefix,
495         File currentDirectory, boolean ignoreCase)
496     {
497         for (BufferIterator it = new BufferIterator(); it.hasNext();) {
498             Buffer buf = it.nextBuffer();
499             if (buf.getType() != Buffer.TYPE_NORMAL)
500                 continue;
501             if (buf == editor.getBuffer())
502                 continue;
503             File file = buf.getFile();
504             if (file != null) {
505                 boolean isMatch = false;
506                 if (ignoreCase)
507                     isMatch = file.getName().regionMatches(true, 0, prefix, 0,
508                         prefix.length());
509                 else
510                     isMatch = file.getName().startsWith(prefix);
511                 if (isMatch)
512                     addCompletion(list, getNameForFile(file, currentDirectory),
513                                   ignoreCase);
514             }
515         }
516     }
517
518     // Returns file.netPath(), file.canonicalPath(), or file.getName(),
519
// depending on the situation.
520
private String JavaDoc getNameForFile(File file, File currentDirectory)
521     {
522         String JavaDoc name;
523         if (currentDirectory != null) {
524             if (currentDirectory.isLocal()) {
525                 if (file.isRemote())
526                     name = file.netPath();
527                 else if (currentDirectory.equals(file.getParentFile()))
528                     name = file.getName();
529                 else
530                     name = file.canonicalPath();
531             } else {
532                 // Current directory is remote. There might be local as well as
533
// remote completions, so we need to use the net path.
534
name = file.netPath();
535             }
536         } else {
537             if (file.isRemote())
538                 name = file.netPath();
539             else
540                 name = file.canonicalPath();
541         }
542         return name;
543     }
544
545     // Add string to list if it's not already there.
546
private void addCompletion(List JavaDoc list, String JavaDoc s, boolean ignoreCase)
547     {
548         if (s != null) {
549             for (int i = list.size(); i-- > 0;) {
550                 if (ignoreCase) {
551                     if (s.equalsIgnoreCase((String JavaDoc)list.get(i)))
552                         return;
553                 } else if (s.equals((String JavaDoc)list.get(i)))
554                     return;
555             }
556             // Didn't find it.
557
list.add(s);
558         }
559     }
560
561     private boolean isExcluded(String JavaDoc pathname)
562     {
563         final int length = pathname.length();
564         if (length > 0) {
565             if (pathname.charAt(length - 1) == '~')
566                 return true;
567         }
568         String JavaDoc extension = Utilities.getExtension(pathname);
569         if (Platform.isPlatformWindows())
570             extension = extension.toLowerCase();
571         if (extension.equals(".class") ||
572             extension.equals(".cls") ||
573             extension.equals(".abcl"))
574         {
575             return true;
576         }
577         if (Platform.isPlatformWindows()) {
578             if (extension.equals(".obj") ||
579                 extension.equals(".exe"))
580             {
581                 return true;
582             }
583         }
584         return false;
585     }
586
587     // Returns null if there is no file associated with the current buffer.
588
private File getCurrentDirectory()
589     {
590         File file = editor.getBuffer().getFile();
591         if (file == null)
592             return null;
593         if (file.isDirectory())
594             return file;
595         return file.getParentFile();
596     }
597
598     private String JavaDoc getSourcePath()
599     {
600         ArrayList JavaDoc dirs = new ArrayList JavaDoc();
601         // We want to search the mode-specific source path first.
602
String JavaDoc sourcePathForMode =
603             editor.getBuffer().getStringProperty(Property.SOURCE_PATH);
604         if (sourcePathForMode != null)
605             dirs.addAll(Utilities.getDirectoriesInPath(sourcePathForMode));
606         // Append any additional directories from the global source path.
607
String JavaDoc globalSourcePath =
608             Editor.preferences().getStringProperty(Property.SOURCE_PATH);
609         if (globalSourcePath != null) {
610             List JavaDoc list = Utilities.getDirectoriesInPath(globalSourcePath);
611             for (int i = 0; i < list.size(); i++) {
612                 String JavaDoc s = (String JavaDoc) list.get(i);
613                 if (!dirs.contains(s))
614                     dirs.add(s);
615             }
616         }
617         // Reconstruct source path string.
618
FastStringBuffer sb = new FastStringBuffer();
619         for (int i = 0; i < dirs.size(); i++) {
620             sb.append((String JavaDoc)dirs.get(i));
621             sb.append(LocalFile.getPathSeparatorChar());
622         }
623         // Remove extra path separator at end of string.
624
if (sb.length() > 0)
625             sb.setLength(sb.length() - 1);
626         return sb.toString();
627     }
628
629     private final void error(String JavaDoc message)
630     {
631         MessageDialog.showMessageDialog(editor, message, title);
632         editor.setFocusToDisplay();
633         editor.updateLocation();
634     }
635
636     private void showCompletionsPopup()
637     {
638         String JavaDoc[] array = new String JavaDoc[completions.size()];
639         completions.toArray(array);
640         popup = new JPopupMenu JavaDoc();
641         popup.add(new CompletionsList(array));
642         popup.show(textField, 0, textField.getHeight());
643         final String JavaDoc completion = (String JavaDoc) completions.get(0);
644         Runnable JavaDoc r = new Runnable JavaDoc() {
645             public void run()
646             {
647                 updateTextField(completion);
648             }
649         };
650         SwingUtilities.invokeLater(r);
651     }
652
653     private void tabPopup(int n, boolean wrap)
654     {
655         int count = listbox.getModel().getSize();
656         if (count == 0) {
657             Debug.bug();
658             return;
659         }
660         int index = listbox.getSelectedIndex();
661         int i = index + n;
662         if (wrap) {
663             if (i >= count)
664                 i = 0;
665             else if (i < 0)
666                 i = count - 1;
667         } else {
668             if (i >= count || i < 0)
669                 i = index;
670         }
671         if (i != index) {
672             listbox.setSelectedIndex(i);
673             listbox.ensureIndexIsVisible(i);
674             String JavaDoc completion = (String JavaDoc) listbox.getSelectedValue();
675             updateTextField(completion);
676         }
677     }
678
679     private void updateTextField(String JavaDoc completion)
680     {
681         if (completion == null)
682             return;
683         textField.setText(completion);
684         if (Editor.preferences().getBooleanProperty(Property.SELECT_COMPLETION)) {
685             if (originalText != null && originalText.length() > 0) {
686                 boolean ignoreCase =
687                     Editor.preferences().getBooleanProperty(
688                         Property.FILENAME_COMPLETIONS_IGNORE_CASE);
689                 boolean select =
690                     completion.regionMatches(ignoreCase, 0, originalPrefix, 0,
691                                              originalPrefix.length());
692                 if (select) {
693                     textField.setCaretPosition(originalPrefix.length());
694                     textField.moveCaretPosition(completion.length());
695                     textField.getCaret().setVisible(false);
696                 } else {
697                     char c = originalText.charAt(0);
698                     if (c == '/' || c == '\\') {
699                         int index;
700                         if (ignoreCase) {
701                             index = completion.toLowerCase().lastIndexOf(
702                                 originalText.toLowerCase());
703                         } else {
704                             index = completion.lastIndexOf(originalText);
705                         }
706                         if (index >= 0) {
707                             textField.setCaretPosition(index + originalText.length());
708                             textField.moveCaretPosition(completion.length());
709                             textField.getCaret().setVisible(false);
710                         }
711                     } else {
712                         RE re = new UncheckedRE("[\\/]".concat(originalText),
713                                                 ignoreCase ? RE.REG_ICASE : 0);
714                         REMatch lastMatch = null;
715                         int index = 0;
716                         while (true) {
717                             REMatch match = re.getMatch(completion, index);
718                             if (match != null) {
719                                 lastMatch = match;
720                                 index = match.getEndIndex();
721                             } else
722                                 break;
723                         }
724                         if (lastMatch != null) {
725                             textField.setCaretPosition(index);
726                             textField.moveCaretPosition(completion.length());
727                             textField.getCaret().setVisible(false);
728                         }
729                     }
730                 }
731             }
732         }
733     }
734
735     private void enterPopup()
736     {
737         popup.setVisible(false);
738         popup = null;
739         File file = File.getInstance(editor.getCompletionDirectory(),
740             textField.getText());
741         if (file == null || file.isDirectory()) {
742             textField.requestFocus();
743             end();
744         } else {
745             editor.repaintNow();
746             enter();
747         }
748     }
749
750     private void end()
751     {
752         Runnable JavaDoc r = new Runnable JavaDoc() {
753             public void run()
754             {
755                 textField.setCaretPosition(textField.getText().length());
756                 textField.getCaret().setVisible(true);
757             }
758         };
759         SwingUtilities.invokeLater(r);
760     }
761
762     private void left()
763     {
764         reset();
765         final int pos;
766         final int start = textField.getSelectionStart();
767         if (start != textField.getSelectionEnd())
768             pos = start;
769         else
770             pos = Math.max(0, textField.getCaretPosition() - 1);
771         textField.requestFocus();
772         Runnable JavaDoc r = new Runnable JavaDoc() {
773             public void run()
774             {
775                 textField.setCaretPosition(pos);
776                 textField.getCaret().setVisible(true);
777             }
778         };
779         SwingUtilities.invokeLater(r);
780     }
781
782     protected void reset()
783     {
784         if (popup != null) {
785             popup.setVisible(false);
786             popup = null;
787         }
788         super.reset();
789     }
790
791     private class CompletionsList extends JScrollPane JavaDoc implements MenuElement JavaDoc,
792         MouseListener JavaDoc
793     {
794         public CompletionsList(String JavaDoc[] completions)
795         {
796             super(listbox = new JList JavaDoc(completions));
797             listbox.setFont(textField.getFont());
798             if (completions.length < 8)
799                 listbox.setVisibleRowCount(completions.length);
800             listbox.setFocusTraversalKeysEnabled(false);
801             listbox.setSelectedIndex(0);
802             listbox.addMouseListener(this);
803         }
804
805         public void processMouseEvent(MouseEvent JavaDoc e, MenuElement JavaDoc[] path,
806             MenuSelectionManager JavaDoc manager) {}
807
808         public void processKeyEvent(KeyEvent JavaDoc e, MenuElement JavaDoc[] path,
809             MenuSelectionManager JavaDoc manager)
810         {
811             final int keyCode = e.getKeyCode();
812             final int modifiers = e.getModifiers();
813             final int id = e.getID();
814             if (id == KeyEvent.KEY_PRESSED) {
815                 switch (keyCode) {
816                     case KeyEvent.VK_TAB:
817                         if (modifiers == 0)
818                             tabPopup(+1, true);
819                         else if (modifiers == SHIFT_MASK)
820                             tabPopup(-1, true);
821                         e.consume();
822                         return;
823                     case KeyEvent.VK_ENTER: {
824                         enterPopup();
825                         e.consume();
826                         return;
827                     }
828                     case KeyEvent.VK_DELETE:
829                     case KeyEvent.VK_ESCAPE: {
830                         popup.setVisible(false);
831                         popup = null;
832                         textField.setText(originalText);
833                         originalText = null;
834                         originalPrefix = null;
835                         textField.requestFocus();
836                         end();
837                         e.consume();
838                         return;
839                     }
840                     case KeyEvent.VK_UP:
841                     case KeyEvent.VK_KP_UP:
842                         tabPopup(-1, false);
843                         e.consume();
844                         break;
845                     case KeyEvent.VK_DOWN:
846                     case KeyEvent.VK_KP_DOWN:
847                         tabPopup(+1, false);
848                         e.consume();
849                         break;
850                     case KeyEvent.VK_LEFT:
851                     case KeyEvent.VK_KP_LEFT:
852                         left();
853                         e.consume();
854                         return;
855                     case KeyEvent.VK_END:
856                     case KeyEvent.VK_RIGHT:
857                     case KeyEvent.VK_KP_RIGHT:
858                         reset();
859                         originalText = null;
860                         originalPrefix = null;
861                         textField.requestFocus();
862                         end();
863                         e.consume();
864                         return;
865                     case KeyEvent.VK_SHIFT:
866                         break;
867                     default:
868                         break;
869                 }
870             } else if (id == KeyEvent.KEY_TYPED) {
871                 // Forward event to textfield.
872
keyTyped(e);
873             }
874             super.processKeyEvent(e);
875         }
876
877         public void menuSelectionChanged(boolean isIncluded) {}
878
879         public MenuElement JavaDoc[] getSubElements()
880         {
881             return new MenuElement JavaDoc[0];
882         }
883
884         public Component JavaDoc getComponent()
885         {
886             return this;
887         }
888
889         public void mouseClicked(MouseEvent JavaDoc e)
890         {
891             enterPopup();
892         }
893
894         public void mousePressed(MouseEvent JavaDoc e)
895         {
896             // Mask off the bits we don't care about (Java 1.4).
897
int modifiers = e.getModifiers() & 0x1f;
898             if (modifiers == InputEvent.BUTTON1_MASK || modifiers == InputEvent.BUTTON2_MASK) {
899                 listbox.setSelectedIndex(listbox.locationToIndex(e.getPoint()));
900                 String JavaDoc s = (String JavaDoc) listbox.getSelectedValue();
901                 textField.setText(s);
902             }
903         }
904
905         public void mouseReleased(MouseEvent JavaDoc e) {}
906
907         public void mouseEntered(MouseEvent JavaDoc e) {}
908
909         public void mouseExited(MouseEvent JavaDoc e) {}
910     }
911
912     public void keyPressed(KeyEvent JavaDoc e)
913     {
914         if (popup != null) {
915             int modifiers = e.getModifiers();
916             switch (e.getKeyCode()) {
917                 case KeyEvent.VK_ENTER:
918                     enterPopup();
919                     e.consume();
920                     return;
921                 case KeyEvent.VK_ESCAPE:
922                     popup.setVisible(false);
923                     popup = null;
924                     textField.setText(originalText);
925                     originalText = null;
926                     originalPrefix = null;
927                     textField.requestFocus();
928                     e.consume();
929                     return;
930                 case KeyEvent.VK_TAB:
931                     if (modifiers == 0)
932                         tabPopup(+1, true);
933                     else if (modifiers == SHIFT_MASK)
934                         tabPopup(-1, true);
935                     e.consume();
936                     return;
937                 case KeyEvent.VK_UP:
938                 case KeyEvent.VK_KP_UP:
939                     if (modifiers == 0) {
940                         tabPopup(-1, false);
941                         e.consume();
942                         return;
943                     }
944                     break;
945                 case KeyEvent.VK_DOWN:
946                 case KeyEvent.VK_KP_DOWN:
947                     if (modifiers == 0) {
948                         tabPopup(+1, false);
949                         e.consume();
950                         return;
951                     }
952                     break;
953                 case KeyEvent.VK_RIGHT:
954                 case KeyEvent.VK_KP_RIGHT:
955                 case KeyEvent.VK_END:
956                     textField.getCaret().setVisible(true);
957                     break;
958                 default:
959                     break;
960             }
961         } else {
962             switch (e.getKeyCode()) {
963                 case KeyEvent.VK_LEFT:
964                 case KeyEvent.VK_KP_LEFT:
965                 case KeyEvent.VK_RIGHT:
966                 case KeyEvent.VK_KP_RIGHT:
967                     textField.getCaret().setVisible(true);
968                     originalText = null;
969                     originalPrefix = null;
970                     break;
971             }
972         }
973         super.keyPressed(e);
974     }
975
976     public void keyTyped(KeyEvent JavaDoc e)
977     {
978         char c = e.getKeyChar();
979         if (c == 8) {
980             // backspace
981
textField.getCaret().setVisible(true);
982             return;
983         }
984         if ((e.getModifiers() & (ALT_MASK | CTRL_MASK | META_MASK)) != 0) {
985             e.consume();
986             return;
987         }
988         if (c >= ' ' && c != 127) {
989             if (popup != null) {
990                 popup.setVisible(false);
991                 popup = null;
992             }
993             String JavaDoc text = textField.getText();
994             if (textField.getSelectionStart() != textField.getSelectionEnd()) {
995                 if (originalText != null) {
996                     text = originalText;
997                     originalText = null;
998                     originalPrefix = null;
999                 } else {
1000                    FastStringBuffer sb =
1001                        new FastStringBuffer(text.substring(0,
1002                            textField.getSelectionStart()));
1003                    sb.append(text.substring(textField.getSelectionEnd()));
1004                    text = sb.toString();
1005                    textField.setCaretPosition(textField.getSelectionStart());
1006                }
1007            }
1008            // Insert (or append) typed char.
1009
final int pos = Math.min(textField.getCaretPosition(), text.length());
1010            FastStringBuffer sb = new FastStringBuffer(text.substring(0, pos));
1011            sb.append(c);
1012            if (pos < text.length())
1013                sb.append(text.substring(pos));
1014            textField.setText(sb.toString());
1015            textField.requestFocus();
1016            Runnable JavaDoc r = new Runnable JavaDoc() {
1017                public void run()
1018                {
1019                    int caretPos;
1020                    final String JavaDoc s = textField.getText();
1021                    if (s != null)
1022                        caretPos = Math.min(pos + 1, s.length());
1023                    else
1024                        caretPos = 0;
1025                    textField.setCaretPosition(caretPos);
1026                    textField.getCaret().setVisible(true);
1027                }
1028            };
1029            SwingUtilities.invokeLater(r);
1030        }
1031        e.consume();
1032    }
1033
1034    public void mousePressed(MouseEvent JavaDoc e)
1035    {
1036        Editor.setCurrentEditor(editor);
1037        originalText = null;
1038        originalPrefix = null;
1039    }
1040
1041    public void mouseReleased(MouseEvent JavaDoc e) {}
1042
1043    public void mouseClicked(MouseEvent JavaDoc e) {}
1044
1045    public void mouseEntered(MouseEvent JavaDoc e) {}
1046
1047    public void mouseExited(MouseEvent JavaDoc e) {}
1048}
1049
Popular Tags