1 /* 2 * Copyright 2003-2008 Sun Microsystems, Inc. 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. Sun designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, 22 * CA 95054 USA or visit www.sun.com if you need additional information or 23 * have any 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 AWTAccessor.FileDialogAccessor fileDialogAccessor = AWTAccessor.getFileDialogAccessor(); 400 401 fileDialogAccessor.setDirectory(target, savedDir); 402 fileDialogAccessor.setFile(target, savedFile); 403 fileDialogAccessor.setFiles(target, savedDir, fileList.getSelectedItems()); 404 } 405 406 /** 407 * handle the cancel event 408 */ 409 void handleCancel() { 410 KeyboardFocusManager.getCurrentKeyboardFocusManager() 411 .removeKeyEventDispatcher(this); 412 413 setSelectionField(null); 414 setFilterField(null); 415 directoryList.clear(); 416 fileList.clear(); 417 418 AWTAccessor.FileDialogAccessor fileDialogAccessor = AWTAccessor.getFileDialogAccessor(); 419 420 fileDialogAccessor.setDirectory(target, null); 421 fileDialogAccessor.setFile(target, null); 422 fileDialogAccessor.setFiles(target, null, null); 423 424 handleQuitButton(); 425 } 426 427 /** 428 * handle the quit event 429 */ 430 void handleQuitButton() { 431 dir = null; 432 file = null; 433 target.hide(); 434 } 435 436 /** 437 * set the entry of the new dir with f 438 */ 439 void setFilterEntry(String d, String f) { 440 File fe = new File(d); 441 442 if (fe.isDirectory() && fe.canRead()) { 443 // Fixed 6260659: File Name set programmatically in FileDialog is overridden during navigation, XToolkit 444 // Here we restoring Motif behaviour 445 setSelectionField(target.getFile()); 446 447 if (f.equals("")) { 448 f = "*"; 449 setFilterField(f); 450 } else { 451 setFilterField(f); 452 } 453 String l[]; 454 455 if (f.equals("*")) { 456 l = fe.list(); 457 } else { 458 // REMIND: fileDialogFilter is not implemented yet 459 FileDialogFilter ff = new FileDialogFilter(f); 460 l = fe.list(ff); 461 } 462 // Fixed 6358953: handling was added in case of I/O error happens 463 if (l == null) { 464 this.dir = getParentDirectory(); 465 return; 466 } 467 directoryList.clear(); 468 fileList.clear(); 469 directoryList.setVisible(false); 470 fileList.setVisible(false); 471 472 directoryList.addItem(".."); 473 Arrays.sort(l); 474 for (int i = 0 ; i < l.length ; i++) { 475 File file = new File(d + l[i]); 476 if (file.isDirectory()) { 477 directoryList.addItem(l[i] + "/"); 478 } else { 479 if (filter != null) { 480 if (filter.accept(new File(l[i]),l[i])) fileList.addItem(l[i]); 481 } 482 else fileList.addItem(l[i]); 483 } 484 } 485 this.dir = d; 486 487 pathField.setText(dir); 488 489 // Some code was removed 490 // Now we do updating of the pathChoice at the time of the choice opening 491 492 target.setDirectory(this.dir); 493 directoryList.setVisible(true); 494 fileList.setVisible(true); 495 } 496 } 497 498 499 String[] getDirList(String dir) { 500 if (!dir.endsWith("/")) 501 dir = dir + "/"; 502 char[] charr = dir.toCharArray(); 503 int numSlashes = 0; 504 for (int i=0;i<charr.length;i++) { 505 if (charr[i] == '/') 506 numSlashes++; 507 } 508 String[] starr = new String[numSlashes]; 509 int j=0; 510 for (int i=charr.length-1;i>=0;i--) { 511 if (charr[i] == '/') 512 { 513 starr[j++] = new String(charr,0,i+1); 514 } 515 } 516 return starr; 517 } 518 519 /** 520 * set the text in the selectionField 521 */ 522 void setSelectionField(String str) { 523 selectionField.setText(str); 524 } 525 526 /** 527 * set the text in the filterField 528 */ 529 void setFilterField(String str) { 530 filterField.setText(str); 531 } 532 533 /** 534 * 535 * @see java.awt.event.ItemEvent 536 * ItemEvent.ITEM_STATE_CHANGED 537 */ 538 public void itemStateChanged(ItemEvent itemEvent){ 539 if (itemEvent.getID() != ItemEvent.ITEM_STATE_CHANGED || 540 itemEvent.getStateChange() == ItemEvent.DESELECTED) { 541 return; 542 } 543 544 Object source = itemEvent.getSource(); 545 546 if (source == pathChoice) { 547 /* 548 * Update the selection ('folder name' text field) after 549 * the current item changing in the unfurled choice by the arrow keys. 550 * See 6259434, 6240074 for more information 551 */ 552 String dir = pathChoice.getSelectedItem(); 553 pathField.setText(dir); 554 } else if (directoryList == source) { 555 setFilterField(getFileName(filterField.getText())); 556 } else if (fileList == source) { 557 String file = fileList.getItem((Integer)itemEvent.getItem()); 558 setSelectionField(file); 559 } 560 } 561 562 /* 563 * Updates the current directory only if directoryList-specific 564 * action occurred. Returns false if the forward directory is inaccessible 565 */ 566 boolean updateDirectoryByUserAction(String str) { 567 568 String dir; 569 if (str.equals("..")) { 570 dir = getParentDirectory(); 571 } 572 else { 573 dir = this.dir + str; 574 } 575 576 File fe = new File(dir); 577 if (fe.canRead()) { 578 this.dir = dir; 579 return true; 580 }else { 581 return false; 582 } 583 } 584 585 String getParentDirectory(){ 586 String parent = this.dir; 587 if (!this.dir.equals("/")) // If the current directory is "/" leave it alone. 588 { 589 if (dir.endsWith("/")) 590 parent = parent.substring(0,parent.lastIndexOf("/")); 591 592 parent = parent.substring(0,parent.lastIndexOf("/")+1); 593 } 594 return parent; 595 } 596 597 public void actionPerformed( ActionEvent actionEvent ) { 598 String actionCommand = actionEvent.getActionCommand(); 599 Object source = actionEvent.getSource(); 600 601 if (actionCommand.equals(actionButtonText)) { 602 handleSelection( selectionField.getText() ); 603 handleQuitButton(); 604 } else if (actionCommand.equals(filterLabelText)) { 605 handleFilter( filterField.getText() ); 606 } else if (actionCommand.equals(cancelButtonText)) { 607 handleCancel(); 608 } else if ( source instanceof TextField ) { 609 if ( selectionField == ((TextField)source) ) { 610 // Fixed within 6259434: PIT: Choice in FileDialog is not responding to keyboard interactions, XToolkit 611 // We should handle the action based on the selection field 612 // Looks like mistake 613 handleSelection(selectionField.getText()); 614 handleQuitButton(); 615 } else if (filterField == ((TextField)source)) { 616 handleFilter(filterField.getText()); 617 } else if (pathField == ((TextField)source)) { 618 target.setDirectory(pathField.getText()); 619 } 620 } else if (source instanceof List) { 621 if (directoryList == ((List)source)) { 622 //handleFilter( actionCommand + getFileName( filterField.getText() ) ); 623 if (updateDirectoryByUserAction(actionCommand)){ 624 handleFilter( getFileName( filterField.getText() ) ); 625 } 626 } else if (fileList == ((List)source)) { 627 handleSelection( actionCommand ); 628 handleQuitButton(); 629 } 630 } 631 } 632 633 public boolean dispatchKeyEvent(KeyEvent keyEvent) { 634 int id = keyEvent.getID(); 635 int keyCode = keyEvent.getKeyCode(); 636 637 if (id == KeyEvent.KEY_PRESSED && keyCode == KeyEvent.VK_ESCAPE) { 638 synchronized (target.getTreeLock()) { 639 Component comp = (Component) keyEvent.getSource(); 640 while (comp != null) { 641 // Fix for 6240084 Disposing a file dialog when the drop-down is active does not dispose the dropdown menu, on Xtoolkit 642 // See also 6259493 643 if (comp == pathChoice) { 644 XChoicePeer choicePeer = (XChoicePeer)pathChoice.getPeer(); 645 if (choicePeer.isUnfurled()){ 646 return false; 647 } 648 } 649 if (comp.getPeer() == this) { 650 handleCancel(); 651 return true; 652 } 653 comp = comp.getParent(); 654 } 655 } 656 } 657 658 return false; 659 } 660 661 662 /** 663 * set the file 664 */ 665 public void setFile(String file) { 666 667 if (file == null) { 668 this.file = null; 669 return; 670 } 671 672 if (this.dir == null) { 673 String d = "./"; 674 File f = new File(d, file); 675 676 if (f.isFile()) { 677 this.file = file; 678 setDirectory(d); 679 } 680 } else { 681 File f = new File(this.dir, file); 682 if (f.isFile()) { 683 this.file = file; 684 } 685 } 686 687 setSelectionField(file); 688 } 689 690 /** 691 * set the directory 692 * FIXME: we should update 'savedDir' after programmatically 'setDirectory' 693 * Otherwise, SavedDir will be not null before second showing 694 * So the current directory of the file dialog will be incorrect after second showing 695 * since 'setDirectory' will be ignored 696 * We cann't update savedDir here now since it used very often 697 */ 698 public void setDirectory(String dir) { 699 700 if (dir == null) { 701 this.dir = null; 702 return; 703 } 704 705 if (dir.equals(this.dir)) { 706 return; 707 } 708 709 int i; 710 if ((i=dir.indexOf("~")) != -1) { 711 712 dir = dir.substring(0,i) + System.getProperty("user.home") + dir.substring(i+1,dir.length()); 713 } 714 715 File fe = new File(dir).getAbsoluteFile(); 716 log.fine("Current directory : " + fe); 717 718 if (!fe.isDirectory()) { 719 dir = "./"; 720 fe = new File(dir).getAbsoluteFile(); 721 722 if (!fe.isDirectory()) { 723 return; 724 } 725 } 726 try { 727 dir = this.dir = fe.getCanonicalPath(); 728 } catch (java.io.IOException ie) { 729 dir = this.dir = fe.getAbsolutePath(); 730 } 731 pathField.setText(this.dir); 732 733 734 if (dir.endsWith("/")) { 735 this.dir = dir; 736 handleFilter(""); 737 } else { 738 this.dir = dir + "/"; 739 handleFilter(""); 740 } 741 742 // Some code was removed 743 // Now we do updating of the pathChoice at the time of the choice opening 744 // Fixed problem: 745 // The exception java.awt.IllegalComponentStateException will be thrown 746 // if the user invoke setDirectory after the closing of the file dialog 747 } 748 749 /** 750 * set filenameFilter 751 * 752 */ 753 public void setFilenameFilter(FilenameFilter filter) { 754 this.filter = filter; 755 } 756 757 758 public void dispose() { 759 FileDialog fd = (FileDialog)fileDialog; 760 if (fd != null) { 761 fd.removeAll(); 762 } 763 super.dispose(); 764 } 765 766 // 03/02/2005 b5097243 Pressing 'ESC' on a file dlg does not dispose the dlg on Xtoolkit 767 public void setVisible(boolean b){ 768 if (fileDialog == null) { 769 init((FileDialog)target); 770 } 771 772 if (savedDir != null || userDir != null) { 773 setDirectory(savedDir != null ? savedDir : userDir); 774 } 775 776 if (savedFile != null) { 777 // Actually in Motif implementation lost file value which was saved after prevously showing 778 // Seems we shouldn't restore Motif behaviour in this case 779 setFile(savedFile); 780 } 781 782 super.setVisible(b); 783 if (b == true){ 784 // See 6240074 for more information 785 XChoicePeer choicePeer = (XChoicePeer)pathChoice.getPeer(); 786 choicePeer.addXChoicePeerListener(this); 787 KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(this); 788 }else{ 789 // See 6240074 for more information 790 XChoicePeer choicePeer = (XChoicePeer)pathChoice.getPeer(); 791 choicePeer.removeXChoicePeerListener(); 792 KeyboardFocusManager.getCurrentKeyboardFocusManager().removeKeyEventDispatcher(this); 793 } 794 795 selectionField.requestFocusInWindow(); 796 } 797 798 /* 799 * Adding items to the path choice based on the text string 800 * See 6240074 for more information 801 */ 802 public void addItemsToPathChoice(String text){ 803 String dirList[] = getDirList(text); 804 for (int i = 0; i < dirList.length; i++) pathChoice.addItem(dirList[i]); 805 } 806 807 /* 808 * Refresh the unfurled choice at the time of the opening choice according to the text of the path field 809 * See 6240074 for more information 810 */ 811 public void unfurledChoiceOpening(ListHelper choiceHelper){ 812 813 // When the unfurled choice is opening the first time, we need only to add elements, otherwise we've got exception 814 if (choiceHelper.getItemCount() == 0){ 815 addItemsToPathChoice(pathField.getText()); 816 return; 817 } 818 819 // If the set of the directories the exactly same as the used to be then dummy 820 if (pathChoice.getItem(0).equals(pathField.getText())) 821 return; 822 823 pathChoice.removeAll(); 824 addItemsToPathChoice(pathField.getText()); 825 } 826 827 /* 828 * Refresh the file dialog at the time of the closing choice according to the selected item of the choice 829 * See 6240074 for more information 830 */ 831 public void unfurledChoiceClosing(){ 832 // This is the exactly same code as invoking later at the time of the itemStateChanged 833 // Here is we restore Windows behaviour: change current directory if user press 'ESC' 834 String dir = pathChoice.getSelectedItem(); 835 target.setDirectory(dir); 836 } 837 } 838 839 /* 840 * Motif file dialogs let the user specify a filter that controls the files that 841 * are displayed in the dialog. This filter is generally specified as a regular 842 * expression. The class is used to implement Motif-like filtering. 843 */ 844 class FileDialogFilter implements FilenameFilter { 845 846 String filter; 847 848 public FileDialogFilter(String f) { 849 filter = f; 850 } 851 852 /* 853 * Tells whether or not the specified file should be included in a file list 854 */ 855 public boolean accept(File dir, String fileName) { 856 857 File f = new File(dir, fileName); 858 859 if (f.isDirectory()) { 860 return true; 861 } else { 862 return matches(fileName, filter); 863 } 864 } 865 866 /* 867 * Tells whether or not the input string matches the given filter 868 */ 869 private boolean matches(String input, String filter) { 870 String regex = convert(filter); 871 return input.matches(regex); 872 } 873 874 /* 875 * Converts the filter into the form which is acceptable by Java's regexps 876 */ 877 private String convert(String filter) { 878 String regex = "^" + filter + "$"; 879 regex = regex.replaceAll("\\.", "\\\\."); 880 regex = regex.replaceAll("\\?", "."); 881 regex = regex.replaceAll("\\*", ".*"); 882 return regex; 883 } 884 }