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 }