Source code: jpl2/common/gui/JPLToolkit.java
1 /***********************************************************************
2 * JavaPsionLink 2.0, a java implementation of the psion link protocol
3 * Copyright (C) 2002, 2003 John S Montgomery (john.montgomery@lineone.net)
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU Lesser General Public License as published by
7 * the Free Software Foundation; either version 2.1 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 ************************************************************************/
19 package jpl2.common.gui;
20
21 import jpl2.PsionLink;
22 import jpl2.link.gui.DragAndDrop;
23 import jpl2.link.gui.Images;
24 import jpl2.link.gui.PsionBrowserPane;
25 import jpl2.common.Preference;
26
27 import java.awt.*;
28 import java.awt.event.*;
29 import java.io.File;
30 import java.util.ResourceBundle;
31 import java.util.MissingResourceException;
32 import java.text.MessageFormat;
33 import java.lang.reflect.*;
34
35
36 /** A class for allowig the use of AWT or Swing, without needing to now
37 * the difference. This is so that under MacOS 9 we shall use AWT and have
38 * a native look and feel and under Linux we shall use swing and have the
39 * native look and feel too. Bizarre tho it sounds!
40 **/
41
42 public abstract class JPLToolkit {
43 private static JPLToolkit tk = null;
44 private static ResourceBundle resources = null;
45 private static Preference prefs = new Preference( ".jpl", "Java Psion Link 2.0 preference file" );
46 private boolean queryResult = false;
47 private String multipleQueryResult = null;
48 private Dialog dialog = null;
49
50 public static Preference getPreferences() {
51 return prefs;
52 }
53
54 public static ResourceBundle getResourceBundle() {
55 if ( resources == null ) {
56 try {
57 resources = ResourceBundle.getBundle( "jplres" );
58 }
59 catch( Exception e ) {
60 e.printStackTrace();
61 }
62 }
63 return resources;
64 }
65
66 public static String getResourceString( String key ) {
67 if ( key.startsWith( "@res:" ) ) {
68 key = key.substring( "@res:".length() );
69 try {
70 return getResourceBundle().getString( key );
71 }
72 catch( MissingResourceException mre ) {
73 //if ( PsionLink.DEBUG )
74 System.err.println( "no resource/translation for: " + key );
75 }
76 }
77
78 return key;
79 }
80
81 public static String getResourceString( String key, Object[] params ) {
82 String str = getResourceString( key );
83 return MessageFormat.format( str, params );
84 }
85
86 public static JPLToolkit getToolkit() {
87 if ( tk == null ) {
88 try {
89 if ( prefs.getPreference( "use_swing", true ) ) {
90 Class clazz = Class.forName( "jpl2.common.gui.SwingToolkit" );
91 tk = (JPLToolkit)clazz.newInstance();
92 }
93 }
94 catch( Throwable t ) {
95 }
96 if ( tk == null )
97 tk = new AWTToolkit();
98 }
99 return tk;
100 }
101
102 public static boolean isSwingToolkitAvailable() {
103 try {
104 Class clazz = Class.forName( "jpl2.common.gui.SwingToolkit" );
105 return true;
106 }
107 catch( Throwable t ) {
108 }
109 return false;
110 }
111
112 private boolean installDragAndDrop( String className, PsionLink link, PsionBrowserPane browserPane ) {
113 try {
114 Class clazz = Class.forName( className );
115 DragAndDrop dnd = (DragAndDrop)clazz.newInstance();
116 dnd.install( link, browserPane );
117 //System.out.println( "Installed: " + className );
118 return true;
119 }
120 catch( Throwable t ) {
121 //t.printStackTrace();
122
123 }
124 return false;
125 }
126
127 public void installDragAndDrop( PsionLink link, PsionBrowserPane browserPane ) {
128 if ( !installDragAndDrop( "jpl2.link.gui.JavaDragAndDrop", link, browserPane ) ) {
129 installDragAndDrop( "jpl2.link.gui.MacDragAndDrop", link, browserPane );
130 }
131 }
132
133 /** Get a list of installed fonts.
134 **/
135 public String[] getFonts() {
136 // see if we have access to the GraphicsEnvironment class
137 // to find out about fonts, or use the old way of doing things
138 try {
139 Class geClass = Class.forName( "java.awt.GraphicsEnvironment" );
140 // get the class and find the method getLocalGraphicsEnvironment()
141 Method getLGE = geClass.getDeclaredMethod( "getLocalGraphicsEnvironment", new Class[ 0 ] );
142 // static method, so no object needed
143 Object lge = getLGE.invoke( null, new Object[ 0 ] );
144 if ( PsionLink.DEBUG )
145 System.out.println( lge );
146
147 // get the method getAvailableFontFamilyNames()
148 Method getFontNames = geClass.getDeclaredMethod( "getAvailableFontFamilyNames", new Class[ 0 ] );
149 Object fontNames = getFontNames.invoke( lge, new Object[ 0 ] );
150
151 if ( PsionLink.DEBUG )
152 System.out.println( "using getAvailableFontFamilyNames()" );
153 return (String[])fontNames;
154 }
155 catch( Throwable t ) {
156 if ( PsionLink.DEBUG )
157 t.printStackTrace();
158 }
159 try {
160 // this seems to sometimes throw an exception
161 // on some systems (probably because it has been
162 // deprecated)
163 return Toolkit.getDefaultToolkit().getFontList();
164 }
165 catch( Throwable t ) {
166 if ( PsionLink.DEBUG )
167 t.printStackTrace();
168 }
169 return new String[] {
170 "Serif", "SansSerif", "Monospaced"
171 };
172 }
173
174 /** Attempt to set the modification date on a file.
175 * Returns true if date was changed.
176 **/
177 public static boolean setFileLastModified( File file, long modified ) {
178 // try 1.2+ way
179 try {
180 Class clazz = File.class;
181 Method method = clazz.getDeclaredMethod( "setLastModified", new Class[] { Long.TYPE } );
182 Object res = method.invoke( file, new Object[] { new Long( modified ) } );
183 return res.equals( Boolean.TRUE );
184 }
185 catch( Throwable t ) {
186 }
187
188 // try using MRJ
189 try {
190 Class clazz = Class.forName( "com.apple.mrj.MRJFileUtils" );
191 Method method = clazz.getDeclaredMethod( "setFileLastModified", new Class[] { java.io.File.class, Long.TYPE } );
192 Object res = method.invoke( null, new Object[] { file, new Long( modified ) } );
193 return res.equals( Boolean.TRUE );
194 }
195 catch( Throwable t ) {
196 }
197 return false;
198 }
199
200 /** Attempt to make a temporary file (which will hopefully be deleted at exit).
201 * Returns null if this system does not support the creation of temporary files.
202 **/
203 public static File createTemporaryFile( String prefix, String suffix ) {
204 // try 1.2+ way
205 try {
206 Class clazz = File.class;
207 Method method = clazz.getDeclaredMethod( "createTempFile", new Class[] { String.class, String.class } );
208 Object file = method.invoke( null, new Object[] { prefix, "." + suffix } );
209 method = clazz.getDeclaredMethod( "deleteOnExit", new Class[ 0 ] );
210 method.invoke( file, new Object[ 0 ] );
211 return (File)file;
212 }
213 catch( Throwable t ) {
214 }
215
216 // else do it the MRJ way
217 File parentDir = null;
218
219 try {
220 Class clazz = Class.forName( "com.apple.mrj.MRJFileUtils" );
221 Field field = clazz.getDeclaredField( "kTemporaryFolderType" );
222 // static field
223 Object mrjOsType = field.get( null );
224 Method method = clazz.getDeclaredMethod( "findFolder", new Class[] { Class.forName( "com.apple.mrj.MRJOSType" ) } );
225 parentDir = (File)method.invoke( null, new Object[] { mrjOsType } );
226 //"findFolder( MRJOSType )"
227
228 }
229 catch( Throwable t ) {
230 }
231
232 if ( parentDir != null ) {
233 // attempt file name as is
234 int num = -1;
235 File file = null;
236 // overwrite file
237 //do {
238 String name = prefix + ((num != -1)? Integer.toHexString( num ):"") + ((suffix != null)? "."+suffix:"");
239 file = new File( parentDir, name );
240 num++;
241 //}
242 //while( file.exists() );
243 return file;
244 }
245 return null;
246 }
247
248 /**
249 * Try to see if the file is hidden or not.
250 * @param file
251 * @return
252 */
253 public static boolean isHiddenFile( File file ) {
254 // try 1.2+ way
255 try {
256 Class clazz = File.class;
257 Method method = clazz.getDeclaredMethod( "isHidden", new Class[] {} );
258 Object result = method.invoke( file, new Object[ 0 ] );
259 return result.equals( Boolean.TRUE );
260 }
261 catch( Throwable t ) {
262 }
263 // otherwise assume it's not hidden
264 return false;
265 }
266
267 /** Returns either a java.awt.Frame or a javax.swing.JFrame
268 **/
269 public Frame makeFrame( String title ) {
270 Frame frame = makeFrameImp();
271 frame.setIconImage( Images.getImage( "icon.gif" ) );
272 frame.setTitle( getResourceString( title ) );
273 return frame;
274 }
275
276 protected abstract Frame makeFrameImp();
277
278 /** Returns either a java.awt.Dialog or a javax.swing.JDialog
279 **/
280 public Dialog makeDialog( Frame parent, String title, boolean modal ) {
281 Dialog dialog = makeDialogImp( parent, modal );
282 dialog.setTitle( getResourceString( title ) );
283 return dialog;
284 }
285
286 protected abstract Dialog makeDialogImp( Frame parent, boolean modal );
287
288 /** Adds a component to a window. In the case of swing getContentPane() must be used.
289 **/
290 public abstract void add( Window w, Component c );
291
292 /** Adds a component to a window. In the case of swing getContentPane() must be used.
293 **/
294 public abstract void add( Window w, Component c, Object constraints );
295
296 /** Sets a layout for a window. In the case of swing getContentPane() must be used.
297 **/
298 public abstract void setLayout( Window w, LayoutManager l );
299
300 /** Returns either a java.awt.Panel or a javax.swing.JPanel.
301 **/
302 public abstract Container makePanel();
303
304 /** Returns either a java.awt.Panel or a javax.swing.JPanel.
305 **/
306 public Container makeGroupPanel( String title ) {
307 return makeGroupPanelImp( getResourceString( title ) );
308 }
309
310 protected abstract Container makeGroupPanelImp( String title );
311
312 /** Returns either a java.awt.Button or a javax.swing.JButton.
313 **/
314 public Component makeButton( String text, String action, ActionListener listener ) {
315 return makeButtonImp( getResourceString( text ), action, listener );
316 }
317
318 protected abstract Component makeButtonImp( String text, String action, ActionListener listener );
319
320 /** Make the button the default on a dialog.
321 **/
322 public abstract void setDefaultButton( Dialog dialog, Component button );
323
324 /** Make the button the "cancel" button on a dialog. ie the button
325 * which dismisses the dialog without takign any action.
326 **/
327 public abstract void setCancelButton( Dialog dialog, Component button );
328
329 /** Associate a key press with the button. ie so a key can be pressed instead of
330 * using the mouse to press the button.
331 **/
332 public abstract void setButtonKey( Dialog dialog, Component button, int keyCode );
333
334 /** Make the button the default on a frame.
335 **/
336 public abstract void setDefaultButton( Frame frame, Component button );
337
338 /** Make the button the "cancel" button on a frame. ie the button
339 * which dismisses the frame without taking any action.
340 **/
341 public abstract void setCancelButton( Frame frame, Component button );
342
343 /** Associate a key press with the button. ie so a key can be pressed instead of
344 * using the mouse to press the button.
345 **/
346 public abstract void setButtonKey( Frame frame, Component button, int keyCode );
347
348 /** Returns either a java.awt.Label or a javax.swing.JLabel.
349 **/
350 public Component makeLabel( String text, int horizontalAlignment ) {
351 return makeLabelImp( getResourceString( text ), horizontalAlignment );
352 }
353
354 /** Returns either a java.awt.Label or a javax.swing.JLabel.
355 **/
356 public Component makeLabel( String text, Object[] params, int horizontalAlignment ) {
357 return makeLabelImp( getResourceString( text, params ), horizontalAlignment );
358 }
359
360 protected abstract Component makeLabelImp( String text, int horizontalAlignment );
361
362 /** Returns either a java.awt.Label or a javax.swing.JLabel.
363 **/
364 public Component makeLabel( String text ) {
365 return makeLabel( text, Label.LEFT );
366 }
367
368 /** Returns either a java.awt.Label or a javax.swing.JLabel.
369 **/
370 public Component makeLabel( String text, Object[] params ) {
371 return makeLabel( text, params, Label.LEFT );
372 }
373
374 /** Sets the text on what may be a button, label or a text field.
375 **/
376 public void setText( Component c, String text ) {
377 setTextImp( c, getResourceString( text ) );
378 }
379
380 /** Sets the text on what may be a button, label or a text field.
381 **/
382 public void setText( Component c, String text, Object[] params ) {
383 setTextImp( c, getResourceString( text, params ) );
384 }
385
386 protected abstract void setTextImp( Component c, String text );
387
388 /** Returns either a java.awt.MenuBar or a javax.swing.JMenuBar.
389 **/
390 public abstract Object makeMenuBar();
391
392 /** Sets a frames menu bar.
393 **/
394 public abstract void setMenuBar( Frame frame, Object menuBar );
395
396 /** Returns either a java.awt.Menu or a javax.swing.JMenu.
397 **/
398 public Object makeMenu( String label ) {
399 return makeMenuImp( getResourceString( label ) );
400 }
401
402 protected abstract Object makeMenuImp( String label );
403
404 /** Insert a seperator/divider into the menu.
405 **/
406 public abstract void addSeparator( Object menu );
407
408 /** Remove all items from a menu.
409 **/
410 public abstract void removeAll( Object menu );
411
412 /** Add a menu to a menu bar.
413 **/
414 public abstract void addMenu( Object menuBar, Object menu );
415
416 /** Set the help menu on a menu bar.
417 **/
418 public abstract void setHelpMenu( Object menuBar, Object menu );
419
420 /** Returns either a java.awt.MenuItem or a javax.swing.JMenuItem.
421 **/
422 public Object makeMenuItem( String label, MenuShortcut s, String action, ActionListener listener ) {
423 return makeMenuItemImp( getResourceString( label ), s, action, listener );
424 }
425
426 protected abstract Object makeMenuItemImp( String label, MenuShortcut s, String action, ActionListener listener );
427
428 /** Add a menu item to a menu.
429 **/
430 public abstract void addMenuItem( Object menu, Object menuItem );
431
432 /** Enable disable a menu/menuitem.
433 **/
434 public abstract void setEnabled( Object menuItem, boolean enabled );
435
436 /** Returns either a java.awt.ScrollPane of a javax.swing.JScrollPane.
437 **/
438 public abstract Container makeScrollPane( Component contents );
439
440 /** Returns the viewport size of a scrollpane.
441 **/
442 public abstract Dimension getViewportSize( Container scrollpane );
443
444 /** Returns the scroll position of a scrollpane.
445 **/
446 public abstract Point getScrollPosition( Container scrollpane );
447
448 /** Sets the scroll position of a scrollpane.
449 **/
450 public abstract void setScrollPosition( Container scrollpane, int x, int y );
451
452 /** Returns either a java.awt.Choice or a javax.swing.JComboBox.
453 **/
454 public abstract Component makeChoice( String[] items, ItemListener itemListener );
455
456 /** Set the items on a choice.
457 **/
458 public abstract void setChoiceItems( Component choice, String[] items );
459
460 /** Returns either a java.awt.List or a javax.swing.JList.
461 **/
462 public abstract Component makeList( String[] items, ItemListener itemListener );
463
464 /** Set the items on a list.
465 **/
466 public abstract void setListItems( Component list, String[] items );
467
468 /** Set the currently selected item on a choice.
469 **/
470 public abstract void setSelected( Component choice, String item );
471
472 /** Get the currently selected item on a choice.
473 **/
474 public abstract String getSelected( Component choice );
475
476 /** Get the currently selected item on a choice.
477 **/
478 public abstract int getSelectedIndex( Component choice );
479
480 /** Returns either a ProgressBar or a javax.swing.JProgressBar.
481 **/
482 public abstract Component makeProgressBar();
483
484 /** Set the max value on a progress bar.
485 **/
486 public abstract void setProgressBarMax( Component progressBar, int max );
487
488 /** Set the current value of a progress bar.
489 **/
490 public abstract void setProgressBarValue( Component progressBar, int value );
491
492 /** Returns either a java.awt.TextField or a javax.swing.JTextField.
493 **/
494 public abstract Component makeTextField( String text, int columns, TextListener listener );
495
496 public abstract void setEditable( Component textField, boolean editable );
497
498 /** Get the text from a text field.
499 **/
500 public abstract String getText( Component textField );
501
502 /** Returns either a java.awt.Checkbox or a javax.swing.JCheckBox
503 **/
504 public Component makeCheckBox( String label, ItemListener listener ) {
505 return makeCheckBoxImpl( getResourceString( label ), listener );
506 }
507
508 protected abstract Component makeCheckBoxImpl( String label, ItemListener listener );
509
510 /** Get the current state of a CheckBox
511 **/
512 public abstract boolean getCheckBoxState( Component checkBox );
513
514 /** Set the state of a CheckBox.
515 **/
516 public abstract void setCheckBoxState( Component checkBox, boolean state );
517
518 /** Under this setup can we create a folder/directory
519 * chooser?
520 **/
521 public abstract boolean canChooseFolders();
522
523 /** Display a dialog to allow the user to choose a folder (eg for
524 * where to download files to.
525 **/
526 public File chooseFolder( Frame parent, String title ) {
527 return chooseFolderImp( parent, getResourceString( title ) );
528 }
529
530 protected abstract File chooseFolderImp( Frame parent, String title );
531
532 /** Display a dialog to allow the user to save a file.
533 **/
534 public File chooseSaveFile( Frame parent, String title ) {
535 return chooseSaveFileImp( parent, getResourceString( title ) );
536 }
537
538 protected abstract File chooseSaveFileImp( Frame parent, String title );
539
540 /** Display a dialog to allow the user to open a file.
541 **/
542 public File chooseOpenFile( Frame parent, String title ) {
543 return chooseOpenFileImp( parent, getResourceString( title ) );
544 }
545
546 protected abstract File chooseOpenFileImp( Frame parent, String title );
547
548 /** Centre child relative to parent.
549 **/
550 public void centreWindow( Window parent, Window child ) {
551 Point p = parent.getLocation();
552 Dimension size = parent.getSize();
553 Dimension childSize = child.getSize();
554 int x = p.x + (size.width-childSize.width)/2;
555 int y = p.y + (size.height-childSize.height)/2;
556 child.setLocation( x, y );
557 }
558
559 /** Make a panel, containing multiple lines of text (as labels).
560 * divided by new lines (\n)
561 **/
562 public Container makeMultiLineLabel( String text ) {
563 text = getResourceString( text );
564 Container panel = makePanel();
565 java.util.StringTokenizer st = new java.util.StringTokenizer( text, "\n" );
566 java.util.Vector lines = new java.util.Vector();
567 while( st.hasMoreTokens() ) {
568 String token = st.nextToken();
569 Component label = makeLabel( token.trim() );
570 lines.addElement( label );
571 }
572 panel.setLayout( new GridLayout( lines.size(), 1, 5, 0 ) );
573 for ( int i = 0; i < lines.size(); i++ ) {
574 panel.add( (Component)lines.elementAt( i ) );
575 }
576 return panel;
577 }
578
579 /** Display a simple, yes/no dialog.
580 **/
581 // TODO make SwingToolkit override this to use JOptionPane
582 public synchronized boolean doQueryDialog( Frame frame, String title, String query ) {
583 queryResult = false;
584 dialog = makeDialog( frame, title, true );
585
586
587 ActionListener listener = new ActionListener() {
588 public void actionPerformed( ActionEvent ae ) {
589 if ( ae.getActionCommand().equals( "yes" ) )
590 queryResult = true;
591 dialog.setVisible( false );
592 }
593 };
594
595 Component label = makeMultiLineLabel( query );
596 Component yesButton = makeButton( "@res:yesButton", "yes", listener );
597 Component noButton = makeButton( "@res:noButton", "no", listener );
598
599 add( dialog, label, BorderLayout.CENTER );
600 Container c = makePanel();
601 c.add( noButton );
602 c.add( yesButton );
603 add( dialog, c, BorderLayout.SOUTH );
604
605 setButtonKey( dialog, yesButton, KeyEvent.VK_Y );
606 setButtonKey( dialog, noButton, KeyEvent.VK_N );
607
608 dialog.pack();
609 centreWindow( frame, dialog );
610 dialog.requestFocus();
611 dialog.show();
612
613 return queryResult;
614 }
615
616 /** A query dialog that may be one of many, hence it has a "yes to all" button, as well as a yes button.
617 * Returns either "yes", "no" or "yes all" depending on button pressed.
618 **/
619 // TODO make SwingToolkit override this to use JOptionPane
620 public synchronized String doMultipleQueryDialog( Frame frame, String title, String query ) {
621 multipleQueryResult = null;
622 dialog = makeDialog( frame, title, true );
623
624
625 ActionListener listener = new ActionListener() {
626 public void actionPerformed( ActionEvent ae ) {
627 multipleQueryResult = ae.getActionCommand();
628 dialog.setVisible( false );
629 }
630 };
631
632 Component label = makeMultiLineLabel( query );
633 Component yesButton = makeButton( "@res:yesButton", "yes", listener );
634 Component noButton = makeButton( "@res:noButton", "no", listener );
635 Component yesAllButton = makeButton( "@res:yesAllButton", "yes all", listener );
636
637 add( dialog, label, BorderLayout.CENTER );
638 Container c = makePanel();
639 c.add( noButton );
640 c.add( yesButton );
641 c.add( yesAllButton );
642 add( dialog, c, BorderLayout.SOUTH );
643
644 setButtonKey( dialog, yesButton, KeyEvent.VK_Y );
645 setButtonKey( dialog, yesAllButton, KeyEvent.VK_A );
646 setButtonKey( dialog, noButton, KeyEvent.VK_N );
647
648 dialog.pack();
649 centreWindow( frame, dialog );
650 dialog.requestFocus();
651 dialog.show();
652
653 return multipleQueryResult;
654 }
655
656 /** Display a simple dialog with a message and an ok/done button.
657 **/
658 // TODO make SwingToolkit override this to use JOptionPane
659 public synchronized void showMessageDialog( Frame frame, String title, String msg ) {
660 dialog = makeDialog( frame, title, true );
661
662 ActionListener listener = new ActionListener() {
663 public void actionPerformed( ActionEvent ae ) {
664 dialog.setVisible( false );
665 }
666 };
667
668 Component label = makeMultiLineLabel( msg );
669 Component doneButton = makeButton( "@res:doneButton", "done", listener );
670
671 add( dialog, label, BorderLayout.CENTER );
672 Container c = makePanel();
673 c.add( doneButton );
674 add( dialog, c, BorderLayout.SOUTH );
675
676 setDefaultButton( dialog, doneButton );
677
678 dialog.pack();
679 centreWindow( frame, dialog );
680 dialog.requestFocus();
681 dialog.show();
682 }
683
684 public synchronized String doTextInputDialog( Frame frame, String title, String msg, String text ) {
685
686 queryResult = false;
687 dialog = makeDialog( frame, title, true );
688
689
690 ActionListener listener = new ActionListener() {
691 public void actionPerformed( ActionEvent ae ) {
692 queryResult = ae.getActionCommand().equals( "done" );
693 dialog.setVisible( false );
694 }
695 };
696
697 Component label = makeMultiLineLabel( msg );
698 Component textField = makeTextField( text, Math.max( 20, text.length() ), null );
699 Component doneButton = makeButton( "@res:doneButton", "done", listener );
700 Component cancelButton = makeButton( "@res:cancelButton", "cancel", listener );
701
702 Container c = makePanel();
703 c.setLayout( new GridLayout( 2,1 ) );
704 c.add( label );
705 c.add( textField );
706 add( dialog, c, BorderLayout.CENTER );
707
708 c = makePanel();
709 c.add( cancelButton );
710 c.add( doneButton );
711 add( dialog, c, BorderLayout.SOUTH );
712
713 setDefaultButton( dialog, doneButton );
714 setButtonKey( dialog, cancelButton, KeyEvent.VK_ESCAPE );
715
716 dialog.pack();
717 centreWindow( frame, dialog );
718 dialog.requestFocus();
719 dialog.show();
720
721 return queryResult? getText( textField ) : null;
722 }
723
724 }