1 /*
2 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package sun.awt.X11;
27
28 import java.awt.*;
29 import javax.swing.*;
30 import java.awt.event.*;
31 import java.awt.peer.*;
32 import java.io.*;
33 import java.util.Locale;
34 import java.util.Arrays;
35 import com.sun.java.swing.plaf.motif.*;
36 import javax.swing.plaf.ComponentUI;
37 import java.security.AccessController;
38 import java.security.PrivilegedAction;
39 import sun.util.logging.PlatformLogger;
40 import sun.awt.AWTAccessor;
41
42 class XFileDialogPeer extends XDialogPeer implements FileDialogPeer, ActionListener, ItemListener, KeyEventDispatcher, XChoicePeerListener {
43 private static final PlatformLogger log = PlatformLogger.getLogger("sun.awt.X11.XFileDialogPeer");
44
45 FileDialog target;
46
47 // This variable holds value exactly the same as value of the 'target.file' variable except:
48 // 1) is changed to null after quit (see handleQuitButton())
49 // 2) keep the same value if 'target.file' is incorrect (see setFile())
50 // It's not clear HOW we used it
51 // We should think about existence of this variable
52 String file;
53
54 String dir;
55
56 String title;
57 int mode;
58 FilenameFilter filter;
59
60 private static final int PATH_CHOICE_WIDTH = 20;
61
62 // Seems that the purpose of this variable is cashing of 'target.file' variable in order to help method show()
63 // We should think about using 'target.file' instead of 'savedFile'
64 // Perhaps, 'target.file' just more correct (see target.setFile())
65 String savedFile;
66
67 // Holds value of the directory which was chosen before
68 // We use it in order to restore previously selected directory
69 // at the time of the next showing of the file dialog
70 String savedDir;
71 // Holds value of the system property 'user.dir'
72 // in order to init current directory
73 String userDir;
74
75 Dialog fileDialog;
76
77 GridBagLayout gbl;
78 GridBagLayout gblButtons;
79 GridBagConstraints gbc;
80
81 // ************** Components in the fileDialogWindow ***************
82
83 TextField filterField;
84
85 // This variable holds the current text of the file which user select through the navigation
86 // It's important that updating of this variable must be correct
87 // since this value is used at the time of the file dialog closing
88 // Namely, we invoke target.setFile() and then user can get this value
89 // We update this field in cases:
90 // - ITEM_STATE_CHANGED was triggered on the file list component: set to the current selected item
91 // - at the time of the 'show': set to savedFile
92 // - at the time of the programmatically setting: set to new value
93 TextField selectionField;
94
95 List directoryList;
96
97 // This is the list component which is used for the showing of the file list of the current directory
98 List fileList;
99
100 Panel buttons;
101 Button openButton;
102 Button filterButton;
103 Button cancelButton;
104 Choice pathChoice;
105 TextField pathField;
106 Panel pathPanel;
107
108 String cancelButtonText = null;
109 String enterFileNameLabelText = null;
110 String filesLabelText= null;
111 String foldersLabelText= null;
112 String pathLabelText= null;
113 String filterLabelText= null;
114 String openButtonText= null;
115 String saveButtonText= null;
116 String actionButtonText= null;
117
118
119 void installStrings() {
120 Locale l = target.getLocale();
121 UIDefaults uid = XToolkit.getUIDefaults();
122 cancelButtonText = uid.getString("FileChooser.cancelButtonText",l);
123 enterFileNameLabelText = uid.getString("FileChooser.enterFileNameLabelText",l);
124 filesLabelText = uid.getString("FileChooser.filesLabelText",l);
125 foldersLabelText = uid.getString("FileChooser.foldersLabelText",l);
126 pathLabelText = uid.getString("FileChooser.pathLabelText",l);
127 filterLabelText = uid.getString("FileChooser.filterLabelText",l);
128 openButtonText = uid.getString("FileChooser.openButtonText",l);
129 saveButtonText = uid.getString("FileChooser.saveButtonText",l);
130
131 }
132
133 XFileDialogPeer(FileDialog target) {
134 super((Dialog)target);
135 this.target = target;
136 }
137
138 private void init(FileDialog target) {
139 fileDialog = target; //new Dialog(target, target.getTitle(), false);
140 this.title = target.getTitle();
141 this.mode = target.getMode();
142 this.target = target;
143 this.filter = target.getFilenameFilter();
144
145 savedFile = target.getFile();
146 savedDir = target.getDirectory();
147 // Shouldn't save 'user.dir' to 'savedDir'
148 // since getDirectory() will be incorrect after handleCancel
149 userDir = (String)AccessController.doPrivileged(
150 new PrivilegedAction() {
151 public Object run() {
152 return System.getProperty("user.dir");
153 }
154 });
155
156 installStrings();
157 gbl = new GridBagLayout();
158 gblButtons = new GridBagLayout();
159 gbc = new GridBagConstraints();
160 fileDialog.setLayout(gbl);
161
162 // create components
163 buttons = new Panel();
164 buttons.setLayout(gblButtons);
165 actionButtonText = (target.getMode() == FileDialog.SAVE) ? saveButtonText : openButtonText;
166 openButton = new Button(actionButtonText);
167
168 filterButton = new Button(filterLabelText);
169 cancelButton = new Button(cancelButtonText);
170 directoryList = new List();
171 fileList = new List();
172 filterField = new TextField();
173 selectionField = new TextField();
174
175 boolean isMultipleMode =
176 AWTAccessor.getFileDialogAccessor().isMultipleMode(target);
177 fileList.setMultipleMode(isMultipleMode);
178
179 // the insets used by the components in the fileDialog
180 Insets noInset = new Insets(0, 0, 0, 0);
181 Insets textFieldInset = new Insets(0, 8, 0, 8);
182 Insets leftListInset = new Insets(0, 8, 0, 4);
183 Insets rightListInset = new Insets(0, 4, 0, 8);
184 Insets separatorInset = new Insets(8, 0, 0, 0);
185 Insets labelInset = new Insets(0, 8, 0, 0);
186 Insets buttonsInset = new Insets(10, 8, 10, 8);
187
188 // add components to GridBagLayout "gbl"
189
190 Font f = new Font(Font.DIALOG, Font.PLAIN, 12);
191
192 Label label = new Label(pathLabelText);
193 label.setFont(f);
194 addComponent(label, gbl, gbc, 0, 0, 1,
195 GridBagConstraints.WEST, (Container)fileDialog,
196 1, 0, GridBagConstraints.NONE, labelInset);
197
198 // Fixed 6260650: FileDialog.getDirectory() does not return null when file dialog is cancelled
199 // After showing we should display 'user.dir' as current directory
200 // if user didn't set directory programatically
201 pathField = new TextField(savedDir != null ? savedDir : userDir);
202
203 pathChoice = new Choice() {
204 public Dimension getPreferredSize() {
205 return new Dimension(PATH_CHOICE_WIDTH, pathField.getPreferredSize().height);
206 }
207 };
208 pathPanel = new Panel();
209 pathPanel.setLayout(new BorderLayout());
210
211 pathPanel.add(pathField,BorderLayout.CENTER);
212 pathPanel.add(pathChoice,BorderLayout.EAST);
213 //addComponent(pathField, gbl, gbc, 0, 1, 2,
214 // GridBagConstraints.WEST, (Container)fileDialog,
215 // 1, 0, GridBagConstraints.HORIZONTAL, textFieldInset);
216 //addComponent(pathChoice, gbl, gbc, 1, 1, GridBagConstraints.RELATIVE,
217 // GridBagConstraints.WEST, (Container)fileDialog,
218 // 1, 0, GridBagConstraints.HORIZONTAL, textFieldInset);
219 addComponent(pathPanel, gbl, gbc, 0, 1, 2,
220 GridBagConstraints.WEST, (Container)fileDialog,
221 1, 0, GridBagConstraints.HORIZONTAL, textFieldInset);
222
223
224
225 label = new Label(filterLabelText);
226
227 label.setFont(f);
228 addComponent(label, gbl, gbc, 0, 2, 1,
229 GridBagConstraints.WEST, (Container)fileDialog,
230 1, 0, GridBagConstraints.NONE, labelInset);
231 addComponent(filterField, gbl, gbc, 0, 3, 2,
232 GridBagConstraints.WEST, (Container)fileDialog,
233 1, 0, GridBagConstraints.HORIZONTAL, textFieldInset);
234
235 label = new Label(foldersLabelText);
236
237 label.setFont(f);
238 addComponent(label, gbl, gbc, 0, 4, 1,
239 GridBagConstraints.WEST, (Container)fileDialog,
240 1, 0, GridBagConstraints.NONE, labelInset);
241
242 label = new Label(filesLabelText);
243
244 label.setFont(f);
245 addComponent(label, gbl, gbc, 1, 4, 1,
246 GridBagConstraints.WEST, (Container)fileDialog,
247 1, 0, GridBagConstraints.NONE, labelInset);
248 addComponent(directoryList, gbl, gbc, 0, 5, 1,
249 GridBagConstraints.WEST, (Container)fileDialog,
250 1, 1, GridBagConstraints.BOTH, leftListInset);
251 addComponent(fileList, gbl, gbc, 1, 5, 1,
252 GridBagConstraints.WEST, (Container)fileDialog,
253 1, 1, GridBagConstraints.BOTH, rightListInset);
254
255 label = new Label(enterFileNameLabelText);
256
257 label.setFont(f);
258 addComponent(label, gbl, gbc, 0, 6, 1,
259 GridBagConstraints.WEST, (Container)fileDialog,
260 1, 0, GridBagConstraints.NONE, labelInset);
261 addComponent(selectionField, gbl, gbc, 0, 7, 2,
262 GridBagConstraints.WEST, (Container)fileDialog,
263 1, 0, GridBagConstraints.HORIZONTAL, textFieldInset);
264 addComponent(new Separator(fileDialog.size().width, 2, Separator.HORIZONTAL), gbl, gbc, 0, 8, 15,
265 GridBagConstraints.WEST, (Container)fileDialog,
266 1, 0, GridBagConstraints.HORIZONTAL, separatorInset);
267
268 // add buttons to GridBagLayout Buttons
269 addComponent(openButton, gblButtons, gbc, 0, 0, 1,
270 GridBagConstraints.WEST, (Container)buttons,
271 1, 0, GridBagConstraints.NONE, noInset);
272 addComponent(filterButton, gblButtons, gbc, 1, 0, 1,
273 GridBagConstraints.CENTER, (Container)buttons,
274 1, 0, GridBagConstraints.NONE, noInset);
275 addComponent(cancelButton, gblButtons, gbc, 2, 0, 1,
276 GridBagConstraints.EAST, (Container)buttons,
277 1, 0, GridBagConstraints.NONE, noInset);
278
279 // add ButtonPanel to the GridBagLayout of this class
280 addComponent(buttons, gbl, gbc, 0, 9, 2,
281 GridBagConstraints.WEST, (Container)fileDialog,
282 1, 0, GridBagConstraints.HORIZONTAL, buttonsInset);
283
284 fileDialog.setSize(400, 400);
285
286 // Update choice's popup width
287 XChoicePeer choicePeer = (XChoicePeer)pathChoice.getPeer();
288 choicePeer.setDrawSelectedItem(false);
289 choicePeer.setAlignUnder(pathField);
290
291 filterField.addActionListener(this);
292 selectionField.addActionListener(this);
293 directoryList.addActionListener(this);
294 directoryList.addItemListener(this);
295 fileList.addItemListener(this);
296 fileList.addActionListener(this);
297 openButton.addActionListener(this);
298 filterButton.addActionListener(this);
299 cancelButton.addActionListener(this);
300 pathChoice.addItemListener(this);
301 pathField.addActionListener(this);
302
303 // b6227750 FileDialog is not disposed when clicking the 'close' (X) button on the top right corner, XToolkit
304 target.addWindowListener(
305 new WindowAdapter(){
306 public void windowClosing(WindowEvent e){
307 handleCancel();
308 }
309 }
310 );
311
312 // 6259434 PIT: Choice in FileDialog is not responding to keyboard interactions, XToolkit
313 pathChoice.addItemListener(this);
314
315 }
316
317 public void updateMinimumSize() {
318 }
319
320 public void updateIconImages() {
321 if (winAttr.icons == null){
322 winAttr.iconsInherited = false;
323 winAttr.icons = getDefaultIconInfo();
324 setIconHints(winAttr.icons);
325 }
326 }
327
328 /**
329 * add Component comp to the container cont.
330 * add the component to the correct GridBagLayout
331 */
332 void addComponent(Component comp, GridBagLayout gb, GridBagConstraints c, int gridx,
333 int gridy, int gridwidth, int anchor, Container cont, int weightx, int weighty,
334 int fill, Insets in) {
335 c.gridx = gridx;
336 c.gridy = gridy;
337 c.gridwidth = gridwidth;
338 c.anchor = anchor;
339 c.weightx = weightx;
340 c.weighty = weighty;
341 c.fill = fill;
342 c.insets = in;
343 gb.setConstraints(comp, c);
344 cont.add(comp);
345 }
346
347 /**
348 * get fileName
349 */
350 String getFileName(String str) {
351 if (str == null) {
352 return "";
353 }
354
355 int index = str.lastIndexOf('/');
356
357 if (index == -1) {
358 return str;
359 } else {
360 return str.substring(index + 1);
361 }
362 }
363
364 /** handleFilter
365 *
366 */
367 void handleFilter(String f) {
368
369 if (f == null) {
370 return;
371 }
372 setFilterEntry(dir,f);
373
374 // Fixed within 6259434: PIT: Choice in FileDialog is not responding to keyboard interactions, XToolkit
375 // Here we restoring Motif behaviour
376 directoryList.select(0);
377 if (fileList.getItemCount() != 0) {
378 fileList.requestFocus();
379 } else {
380 directoryList.requestFocus();
381 }
382 }
383
384 /**
385 * handle the selection event
386 */
387 void handleSelection(String file) {
388
389 int index = file.lastIndexOf(java.io.File.separatorChar);
390
391 if (index == -1) {
392 savedDir = this.dir;
393 savedFile = file;
394 } else {
395 savedDir = file.substring(0, index+1);
396 savedFile = file.substring(index+1);
397 }
398
399 String[] fileNames = fileList.getSelectedItems();
400 int filesNumber = (fileNames != null) ? fileNames.length : 0;
401 File[] files = new File[filesNumber];
402 for (int i = 0; i < filesNumber; i++) {
403 files[i] = new File(savedDir, fileNames[i]);
404 }
405
406 AWTAccessor.FileDialogAccessor fileDialogAccessor = AWTAccessor.getFileDialogAccessor();
407
408 fileDialogAccessor.setDirectory(target, savedDir);
409 fileDialogAccessor.setFile(target, savedFile);
410 fileDialogAccessor.setFiles(target, files);
411 }
412
413 /**
414 * handle the cancel event
415 */
416 void handleCancel() {
417 KeyboardFocusManager.getCurrentKeyboardFocusManager()
418 .removeKeyEventDispatcher(this);
419
420 setSelectionField(null);
421 setFilterField(null);
422 directoryList.clear();
423 fileList.clear();
424
425 AWTAccessor.FileDialogAccessor fileDialogAccessor = AWTAccessor.getFileDialogAccessor();
426
427 fileDialogAccessor.setDirectory(target, null);
428 fileDialogAccessor.setFile(target, null);
429 fileDialogAccessor.setFiles(target, null);
430
431 handleQuitButton();
432 }
433
434 /**
435 * handle the quit event
436 */
437 void handleQuitButton() {
438 dir = null;
439 file = null;
440 target.hide();
441 }
442
443 /**
444 * set the entry of the new dir with f
445 */
446 void setFilterEntry(String d, String f) {
447 File fe = new File(d);
448
449 if (fe.isDirectory() && fe.canRead()) {
450 // Fixed 6260659: File Name set programmatically in FileDialog is overridden during navigation, XToolkit
451 // Here we restoring Motif behaviour
452 setSelectionField(target.getFile());
453
454 if (f.equals("")) {
455 f = "*";
456 setFilterField(f);
457 } else {
458 setFilterField(f);
459 }
460 String l[];
461
462 if (f.equals("*")) {
463 l = fe.list();
464 } else {
465 // REMIND: fileDialogFilter is not implemented yet
466 FileDialogFilter ff = new FileDialogFilter(f);
467 l = fe.list(ff);
468 }
469 // Fixed 6358953: handling was added in case of I/O error happens
470 if (l == null) {
471 this.dir = getParentDirectory();
472 return;
473 }
474 directoryList.clear();
475 fileList.clear();
476 directoryList.setVisible(false);
477 fileList.setVisible(false);
478
479 directoryList.addItem("..");
480 Arrays.sort(l);
481 for (int i = 0 ; i < l.length ; i++) {
482 File file = new File(d + l[i]);
483 if (file.isDirectory()) {
484 directoryList.addItem(l[i] + "/");
485 } else {
486 if (filter != null) {
487 if (filter.accept(new File(l[i]),l[i])) fileList.addItem(l[i]);
488 }
489 else fileList.addItem(l[i]);
490 }
491 }
492 this.dir = d;
493
494 pathField.setText(dir);
495
496 // Some code was removed
497 // Now we do updating of the pathChoice at the time of the choice opening
498
499 target.setDirectory(this.dir);
500 directoryList.setVisible(true);
501 fileList.setVisible(true);
502 }
503 }
504
505
506 String[] getDirList(String dir) {
507 if (!dir.endsWith("/"))
508 dir = dir + "/";
509 char[] charr = dir.toCharArray();
510 int numSlashes = 0;
511 for (int i=0;i<charr.length;i++) {
512 if (charr[i] == '/')
513 numSlashes++;
514 }
515 String[] starr = new String[numSlashes];
516 int j=0;
517 for (int i=charr.length-1;i>=0;i--) {
518 if (charr[i] == '/')
519 {
520 starr[j++] = new String(charr,0,i+1);
521 }
522 }
523 return starr;
524 }
525
526 /**
527 * set the text in the selectionField
528 */
529 void setSelectionField(String str) {
530 selectionField.setText(str);
531 }
532
533 /**
534 * set the text in the filterField
535 */
536 void setFilterField(String str) {
537 filterField.setText(str);
538 }
539
540 /**
541 *
542 * @see java.awt.event.ItemEvent
543 * ItemEvent.ITEM_STATE_CHANGED
544 */
545 public void itemStateChanged(ItemEvent itemEvent){
546 if (itemEvent.getID() != ItemEvent.ITEM_STATE_CHANGED ||
547 itemEvent.getStateChange() == ItemEvent.DESELECTED) {
548 return;
549 }
550
551 Object source = itemEvent.getSource();
552
553 if (source == pathChoice) {
554 /*
555 * Update the selection ('folder name' text field) after
556 * the current item changing in the unfurled choice by the arrow keys.
557 * See 6259434, 6240074 for more information
558 */
559 String dir = pathChoice.getSelectedItem();
560 pathField.setText(dir);
561 } else if (directoryList == source) {
562 setFilterField(getFileName(filterField.getText()));
563 } else if (fileList == source) {
564 String file = fileList.getItem((Integer)itemEvent.getItem());
565 setSelectionField(file);
566 }
567 }
568
569 /*
570 * Updates the current directory only if directoryList-specific
571 * action occurred. Returns false if the forward directory is inaccessible
572 */
573 boolean updateDirectoryByUserAction(String str) {
574
575 String dir;
576 if (str.equals("..")) {
577 dir = getParentDirectory();
578 }
579 else {
580 dir = this.dir + str;
581 }
582
583 File fe = new File(dir);
584 if (fe.canRead()) {
585 this.dir = dir;
586 return true;
587 }else {
588 return false;
589 }
590 }
591
592 String getParentDirectory(){
593 String parent = this.dir;
594 if (!this.dir.equals("/")) // If the current directory is "/" leave it alone.
595 {
596 if (dir.endsWith("/"))
597 parent = parent.substring(0,parent.lastIndexOf("/"));
598
599 parent = parent.substring(0,parent.lastIndexOf("/")+1);
600 }
601 return parent;
602 }
603
604 public void actionPerformed( ActionEvent actionEvent ) {
605 String actionCommand = actionEvent.getActionCommand();
606 Object source = actionEvent.getSource();
607
608 if (actionCommand.equals(actionButtonText)) {
609 handleSelection( selectionField.getText() );
610 handleQuitButton();
611 } else if (actionCommand.equals(filterLabelText)) {
612 handleFilter( filterField.getText() );
613 } else if (actionCommand.equals(cancelButtonText)) {
614 handleCancel();
615 } else if ( source instanceof TextField ) {
616 if ( selectionField == ((TextField)source) ) {
617 // Fixed within 6259434: PIT: Choice in FileDialog is not responding to keyboard interactions, XToolkit
618 // We should handle the action based on the selection field
619 // Looks like mistake
620 handleSelection(selectionField.getText());
621 handleQuitButton();
622 } else if (filterField == ((TextField)source)) {
623 handleFilter(filterField.getText());
624 } else if (pathField == ((TextField)source)) {
625 target.setDirectory(pathField.getText());
626 }
627 } else if (source instanceof List) {
628 if (directoryList == ((List)source)) {
629 //handleFilter( actionCommand + getFileName( filterField.getText() ) );
630 if (updateDirectoryByUserAction(actionCommand)){
631 handleFilter( getFileName( filterField.getText() ) );
632 }
633 } else if (fileList == ((List)source)) {
634 handleSelection( actionCommand );
635 handleQuitButton();
636 }
637 }
638 }
639
640 public boolean dispatchKeyEvent(KeyEvent keyEvent) {
641 int id = keyEvent.getID();
642 int keyCode = keyEvent.getKeyCode();
643
644 if (id == KeyEvent.KEY_PRESSED && keyCode == KeyEvent.VK_ESCAPE) {
645 synchronized (target.getTreeLock()) {
646 Component comp = (Component) keyEvent.getSource();
647 while (comp != null) {
648 // Fix for 6240084 Disposing a file dialog when the drop-down is active does not dispose the dropdown menu, on Xtoolkit
649 // See also 6259493
650 if (comp == pathChoice) {
651 XChoicePeer choicePeer = (XChoicePeer)pathChoice.getPeer();
652 if (choicePeer.isUnfurled()){
653 return false;
654 }
655 }
656 if (comp.getPeer() == this) {
657 handleCancel();
658 return true;
659 }
660 comp = comp.getParent();
661 }
662 }
663 }
664
665 return false;
666 }
667
668
669 /**
670 * set the file
671 */
672 public void setFile(String file) {
673
674 if (file == null) {
675 this.file = null;
676 return;
677 }
678
679 if (this.dir == null) {
680 String d = "./";
681 File f = new File(d, file);
682
683 if (f.isFile()) {
684 this.file = file;
685 setDirectory(d);
686 }
687 } else {
688 File f = new File(this.dir, file);
689 if (f.isFile()) {
690 this.file = file;
691 }
692 }
693
694 setSelectionField(file);
695 }
696
697 /**
698 * set the directory
699 * FIXME: we should update 'savedDir' after programmatically 'setDirectory'
700 * Otherwise, SavedDir will be not null before second showing
701 * So the current directory of the file dialog will be incorrect after second showing
702 * since 'setDirectory' will be ignored
703 * We cann't update savedDir here now since it used very often
704 */
705 public void setDirectory(String dir) {
706
707 if (dir == null) {
708 this.dir = null;
709 return;
710 }
711
712 if (dir.equals(this.dir)) {
713 return;
714 }
715
716 int i;
717 if ((i=dir.indexOf("~")) != -1) {
718
719 dir = dir.substring(0,i) + System.getProperty("user.home") + dir.substring(i+1,dir.length());
720 }
721
722 File fe = new File(dir).getAbsoluteFile();
723 if (log.isLoggable(PlatformLogger.FINE)) {
724 log.fine("Current directory : " + fe);
725 }
726
727 if (!fe.isDirectory()) {
728 dir = "./";
729 fe = new File(dir).getAbsoluteFile();
730
731 if (!fe.isDirectory()) {
732 return;
733 }
734 }
735 try {
736 dir = this.dir = fe.getCanonicalPath();
737 } catch (java.io.IOException ie) {
738 dir = this.dir = fe.getAbsolutePath();
739 }
740 pathField.setText(this.dir);
741
742
743 if (dir.endsWith("/")) {
744 this.dir = dir;
745 handleFilter("");
746 } else {
747 this.dir = dir + "/";
748 handleFilter("");
749 }
750
751 // Some code was removed
752 // Now we do updating of the pathChoice at the time of the choice opening
753 // Fixed problem:
754 // The exception java.awt.IllegalComponentStateException will be thrown
755 // if the user invoke setDirectory after the closing of the file dialog
756 }
757
758 /**
759 * set filenameFilter
760 *
761 */
762 public void setFilenameFilter(FilenameFilter filter) {
763 this.filter = filter;
764 }
765
766
767 public void dispose() {
768 FileDialog fd = (FileDialog)fileDialog;
769 if (fd != null) {
770 fd.removeAll();
771 }
772 super.dispose();
773 }
774
775 // 03/02/2005 b5097243 Pressing 'ESC' on a file dlg does not dispose the dlg on Xtoolkit
776 public void setVisible(boolean b){
777 if (fileDialog == null) {
778 init((FileDialog)target);
779 }
780
781 if (savedDir != null || userDir != null) {
782 setDirectory(savedDir != null ? savedDir : userDir);
783 }
784
785 if (savedFile != null) {
786 // Actually in Motif implementation lost file value which was saved after prevously showing
787 // Seems we shouldn't restore Motif behaviour in this case
788 setFile(savedFile);
789 }
790
791 super.setVisible(b);
792 if (b == true){
793 // See 6240074 for more information
794 XChoicePeer choicePeer = (XChoicePeer)pathChoice.getPeer();
795 choicePeer.addXChoicePeerListener(this);
796 KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(this);
797 }else{
798 // See 6240074 for more information
799 XChoicePeer choicePeer = (XChoicePeer)pathChoice.getPeer();
800 choicePeer.removeXChoicePeerListener();
801 KeyboardFocusManager.getCurrentKeyboardFocusManager().removeKeyEventDispatcher(this);
802 }
803
804 selectionField.requestFocusInWindow();
805 }
806
807 /*
808 * Adding items to the path choice based on the text string
809 * See 6240074 for more information
810 */
811 public void addItemsToPathChoice(String text){
812 String dirList[] = getDirList(text);
813 for (int i = 0; i < dirList.length; i++) pathChoice.addItem(dirList[i]);
814 }
815
816 /*
817 * Refresh the unfurled choice at the time of the opening choice according to the text of the path field
818 * See 6240074 for more information
819 */
820 public void unfurledChoiceOpening(ListHelper choiceHelper){
821
822 // When the unfurled choice is opening the first time, we need only to add elements, otherwise we've got exception
823 if (choiceHelper.getItemCount() == 0){
824 addItemsToPathChoice(pathField.getText());
825 return;
826 }
827
828 // If the set of the directories the exactly same as the used to be then dummy
829 if (pathChoice.getItem(0).equals(pathField.getText()))
830 return;
831
832 pathChoice.removeAll();
833 addItemsToPathChoice(pathField.getText());
834 }
835
836 /*
837 * Refresh the file dialog at the time of the closing choice according to the selected item of the choice
838 * See 6240074 for more information
839 */
840 public void unfurledChoiceClosing(){
841 // This is the exactly same code as invoking later at the time of the itemStateChanged
842 // Here is we restore Windows behaviour: change current directory if user press 'ESC'
843 String dir = pathChoice.getSelectedItem();
844 target.setDirectory(dir);
845 }
846 }
847
848 class Separator extends Canvas {
849 public final static int HORIZONTAL = 0;
850 public final static int VERTICAL = 1;
851 int orientation;
852
853 public Separator(int length, int thickness, int orient) {
854 super();
855 orientation = orient;
856 if (orient == HORIZONTAL) {
857 resize(length, thickness);
858 } else {
859 // VERTICAL
860 resize(thickness, length);
861 }
862 }
863
864 public void paint(Graphics g) {
865 int x1, y1, x2, y2;
866 Rectangle bbox = bounds();
867 Color c = getBackground();
868 Color brighter = c.brighter();
869 Color darker = c.darker();
870
871 if (orientation == HORIZONTAL) {
872 x1 = 0;
873 x2 = bbox.width - 1;
874 y1 = y2 = bbox.height/2 - 1;
875
876 } else {
877 // VERTICAL
878 x1 = x2 = bbox.width/2 - 1;
879 y1 = 0;
880 y2 = bbox.height - 1;
881 }
882 g.setColor(darker);
883 g.drawLine(x1, y2, x2, y2);
884 g.setColor(brighter);
885 if (orientation == HORIZONTAL)
886 g.drawLine(x1, y2+1, x2, y2+1);
887 else
888 g.drawLine(x1+1, y2, x2+1, y2);
889 }
890 }
891
892 /*
893 * Motif file dialogs let the user specify a filter that controls the files that
894 * are displayed in the dialog. This filter is generally specified as a regular
895 * expression. The class is used to implement Motif-like filtering.
896 */
897 class FileDialogFilter implements FilenameFilter {
898
899 String filter;
900
901 public FileDialogFilter(String f) {
902 filter = f;
903 }
904
905 /*
906 * Tells whether or not the specified file should be included in a file list
907 */
908 public boolean accept(File dir, String fileName) {
909
910 File f = new File(dir, fileName);
911
912 if (f.isDirectory()) {
913 return true;
914 } else {
915 return matches(fileName, filter);
916 }
917 }
918
919 /*
920 * Tells whether or not the input string matches the given filter
921 */
922 private boolean matches(String input, String filter) {
923 String regex = convert(filter);
924 return input.matches(regex);
925 }
926
927 /*
928 * Converts the filter into the form which is acceptable by Java's regexps
929 */
930 private String convert(String filter) {
931 String regex = "^" + filter + "$";
932 regex = regex.replaceAll("\\.", "\\\\.");
933 regex = regex.replaceAll("\\?", ".");
934 regex = regex.replaceAll("\\*", ".*");
935 return regex;
936 }
937 }
--- EOF ---