1 /* 2 * Copyright (c) 2003, 2014, 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 = AccessController.doPrivileged( 150 new PrivilegedAction<String>() { 151 public String 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 @SuppressWarnings("serial") // Anonymous class 203 Choice tmp = new Choice() { 204 public Dimension getPreferredSize() { 205 return new Dimension(PATH_CHOICE_WIDTH, pathField.getPreferredSize().height); 206 } 207 }; 208 pathChoice = tmp; 209 pathPanel = new Panel(); 210 pathPanel.setLayout(new BorderLayout()); 211 212 pathPanel.add(pathField,BorderLayout.CENTER); 213 pathPanel.add(pathChoice,BorderLayout.EAST); 214 //addComponent(pathField, gbl, gbc, 0, 1, 2, 215 // GridBagConstraints.WEST, (Container)fileDialog, 216 // 1, 0, GridBagConstraints.HORIZONTAL, textFieldInset); 217 //addComponent(pathChoice, gbl, gbc, 1, 1, GridBagConstraints.RELATIVE, 218 // GridBagConstraints.WEST, (Container)fileDialog, 219 // 1, 0, GridBagConstraints.HORIZONTAL, textFieldInset); 220 addComponent(pathPanel, gbl, gbc, 0, 1, 2, 221 GridBagConstraints.WEST, (Container)fileDialog, 222 1, 0, GridBagConstraints.HORIZONTAL, textFieldInset); 223 224 225 226 label = new Label(filterLabelText); 227 228 label.setFont(f); 229 addComponent(label, gbl, gbc, 0, 2, 1, 230 GridBagConstraints.WEST, (Container)fileDialog, 231 1, 0, GridBagConstraints.NONE, labelInset); 232 addComponent(filterField, gbl, gbc, 0, 3, 2, 233 GridBagConstraints.WEST, (Container)fileDialog, 234 1, 0, GridBagConstraints.HORIZONTAL, textFieldInset); 235 236 label = new Label(foldersLabelText); 237 238 label.setFont(f); 239 addComponent(label, gbl, gbc, 0, 4, 1, 240 GridBagConstraints.WEST, (Container)fileDialog, 241 1, 0, GridBagConstraints.NONE, labelInset); 242 243 label = new Label(filesLabelText); 244 245 label.setFont(f); 246 addComponent(label, gbl, gbc, 1, 4, 1, 247 GridBagConstraints.WEST, (Container)fileDialog, 248 1, 0, GridBagConstraints.NONE, labelInset); 249 addComponent(directoryList, gbl, gbc, 0, 5, 1, 250 GridBagConstraints.WEST, (Container)fileDialog, 251 1, 1, GridBagConstraints.BOTH, leftListInset); 252 addComponent(fileList, gbl, gbc, 1, 5, 1, 253 GridBagConstraints.WEST, (Container)fileDialog, 254 1, 1, GridBagConstraints.BOTH, rightListInset); 255 256 label = new Label(enterFileNameLabelText); 257 258 label.setFont(f); 259 addComponent(label, gbl, gbc, 0, 6, 1, 260 GridBagConstraints.WEST, (Container)fileDialog, 261 1, 0, GridBagConstraints.NONE, labelInset); 262 addComponent(selectionField, gbl, gbc, 0, 7, 2, 263 GridBagConstraints.WEST, (Container)fileDialog, 264 1, 0, GridBagConstraints.HORIZONTAL, textFieldInset); 265 addComponent(new Separator(fileDialog.size().width, 2, Separator.HORIZONTAL), gbl, gbc, 0, 8, 15, 266 GridBagConstraints.WEST, (Container)fileDialog, 267 1, 0, GridBagConstraints.HORIZONTAL, separatorInset); 268 269 // add buttons to GridBagLayout Buttons 270 addComponent(openButton, gblButtons, gbc, 0, 0, 1, 271 GridBagConstraints.WEST, (Container)buttons, 272 1, 0, GridBagConstraints.NONE, noInset); 273 addComponent(filterButton, gblButtons, gbc, 1, 0, 1, 274 GridBagConstraints.CENTER, (Container)buttons, 275 1, 0, GridBagConstraints.NONE, noInset); 276 addComponent(cancelButton, gblButtons, gbc, 2, 0, 1, 277 GridBagConstraints.EAST, (Container)buttons, 278 1, 0, GridBagConstraints.NONE, noInset); 279 280 // add ButtonPanel to the GridBagLayout of this class 281 addComponent(buttons, gbl, gbc, 0, 9, 2, 282 GridBagConstraints.WEST, (Container)fileDialog, 283 1, 0, GridBagConstraints.HORIZONTAL, buttonsInset); 284 285 fileDialog.setSize(400, 400); 286 287 // Update choice's popup width 288 XChoicePeer choicePeer = (XChoicePeer)pathChoice.getPeer(); 289 choicePeer.setDrawSelectedItem(false); 290 choicePeer.setAlignUnder(pathField); 291 292 filterField.addActionListener(this); 293 selectionField.addActionListener(this); 294 directoryList.addActionListener(this); 295 directoryList.addItemListener(this); 296 fileList.addItemListener(this); 297 fileList.addActionListener(this); 298 openButton.addActionListener(this); 299 filterButton.addActionListener(this); 300 cancelButton.addActionListener(this); 301 pathChoice.addItemListener(this); 302 pathField.addActionListener(this); 303 304 // b6227750 FileDialog is not disposed when clicking the 'close' (X) button on the top right corner, XToolkit 305 target.addWindowListener( 306 new WindowAdapter(){ 307 public void windowClosing(WindowEvent e){ 308 handleCancel(); 309 } 310 } 311 ); 312 313 // 6259434 PIT: Choice in FileDialog is not responding to keyboard interactions, XToolkit 314 pathChoice.addItemListener(this); 315 316 } 317 318 public void updateMinimumSize() { 319 } 320 321 public void updateIconImages() { 322 if (winAttr.icons == null){ 323 winAttr.iconsInherited = false; 324 winAttr.icons = getDefaultIconInfo(); 325 setIconHints(winAttr.icons); 326 } 327 } 328 329 /** 330 * add Component comp to the container cont. 331 * add the component to the correct GridBagLayout 332 */ 333 void addComponent(Component comp, GridBagLayout gb, GridBagConstraints c, int gridx, 334 int gridy, int gridwidth, int anchor, Container cont, int weightx, int weighty, 335 int fill, Insets in) { 336 c.gridx = gridx; 337 c.gridy = gridy; 338 c.gridwidth = gridwidth; 339 c.anchor = anchor; 340 c.weightx = weightx; 341 c.weighty = weighty; 342 c.fill = fill; 343 c.insets = in; 344 gb.setConstraints(comp, c); 345 cont.add(comp); 346 } 347 348 /** 349 * get fileName 350 */ 351 String getFileName(String str) { 352 if (str == null) { 353 return ""; 354 } 355 356 int index = str.lastIndexOf('/'); 357 358 if (index == -1) { 359 return str; 360 } else { 361 return str.substring(index + 1); 362 } 363 } 364 365 /** handleFilter 366 * 367 */ 368 void handleFilter(String f) { 369 370 if (f == null) { 371 return; 372 } 373 setFilterEntry(dir,f); 374 375 // Fixed within 6259434: PIT: Choice in FileDialog is not responding to keyboard interactions, XToolkit 376 // Here we restoring Motif behaviour 377 directoryList.select(0); 378 if (fileList.getItemCount() != 0) { 379 fileList.requestFocus(); 380 } else { 381 directoryList.requestFocus(); 382 } 383 } 384 385 /** 386 * handle the selection event 387 */ 388 void handleSelection(String file) { 389 390 int index = file.lastIndexOf(java.io.File.separatorChar); 391 392 if (index == -1) { 393 savedDir = this.dir; 394 savedFile = file; 395 } else { 396 savedDir = file.substring(0, index+1); 397 savedFile = file.substring(index+1); 398 } 399 400 String[] fileNames = fileList.getSelectedItems(); 401 int filesNumber = (fileNames != null) ? fileNames.length : 0; 402 File[] files = new File[filesNumber]; 403 for (int i = 0; i < filesNumber; i++) { 404 files[i] = new File(savedDir, fileNames[i]); 405 } 406 407 AWTAccessor.FileDialogAccessor fileDialogAccessor = AWTAccessor.getFileDialogAccessor(); 408 409 fileDialogAccessor.setDirectory(target, savedDir); 410 fileDialogAccessor.setFile(target, savedFile); 411 fileDialogAccessor.setFiles(target, files); 412 } 413 414 /** 415 * handle the cancel event 416 */ 417 void handleCancel() { 418 KeyboardFocusManager.getCurrentKeyboardFocusManager() 419 .removeKeyEventDispatcher(this); 420 421 setSelectionField(null); 422 setFilterField(null); 423 directoryList.clear(); 424 fileList.clear(); 425 426 AWTAccessor.FileDialogAccessor fileDialogAccessor = AWTAccessor.getFileDialogAccessor(); 427 428 fileDialogAccessor.setDirectory(target, null); 429 fileDialogAccessor.setFile(target, null); 430 fileDialogAccessor.setFiles(target, null); 431 432 handleQuitButton(); 433 } 434 435 /** 436 * handle the quit event 437 */ 438 void handleQuitButton() { 439 dir = null; 440 file = null; 441 target.hide(); 442 } 443 444 /** 445 * set the entry of the new dir with f 446 */ 447 void setFilterEntry(String d, String f) { 448 File fe = new File(d); 449 450 if (fe.isDirectory() && fe.canRead()) { 451 // Fixed 6260659: File Name set programmatically in FileDialog is overridden during navigation, XToolkit 452 // Here we restoring Motif behaviour 453 setSelectionField(target.getFile()); 454 455 if (f.equals("")) { 456 f = "*"; 457 setFilterField(f); 458 } else { 459 setFilterField(f); 460 } 461 String l[]; 462 463 if (f.equals("*")) { 464 l = fe.list(); 465 } else { 466 // REMIND: fileDialogFilter is not implemented yet 467 FileDialogFilter ff = new FileDialogFilter(f); 468 l = fe.list(ff); 469 } 470 // Fixed 6358953: handling was added in case of I/O error happens 471 if (l == null) { 472 this.dir = getParentDirectory(); 473 return; 474 } 475 directoryList.clear(); 476 fileList.clear(); 477 directoryList.setVisible(false); 478 fileList.setVisible(false); 479 480 directoryList.addItem(".."); 481 Arrays.sort(l); 482 for (int i = 0 ; i < l.length ; i++) { 483 File file = new File(d + l[i]); 484 if (file.isDirectory()) { 485 directoryList.addItem(l[i] + "/"); 486 } else { 487 if (filter != null) { 488 if (filter.accept(new File(l[i]),l[i])) fileList.addItem(l[i]); 489 } 490 else fileList.addItem(l[i]); 491 } 492 } 493 this.dir = d; 494 495 pathField.setText(dir); 496 497 // Some code was removed 498 // Now we do updating of the pathChoice at the time of the choice opening 499 500 target.setDirectory(this.dir); 501 directoryList.setVisible(true); 502 fileList.setVisible(true); 503 } 504 } 505 506 507 String[] getDirList(String dir) { 508 if (!dir.endsWith("/")) 509 dir = dir + "/"; 510 char[] charr = dir.toCharArray(); 511 int numSlashes = 0; 512 for (int i=0;i<charr.length;i++) { 513 if (charr[i] == '/') 514 numSlashes++; 515 } 516 String[] starr = new String[numSlashes]; 517 int j=0; 518 for (int i=charr.length-1;i>=0;i--) { 519 if (charr[i] == '/') 520 { 521 starr[j++] = new String(charr,0,i+1); 522 } 523 } 524 return starr; 525 } 526 527 /** 528 * set the text in the selectionField 529 */ 530 void setSelectionField(String str) { 531 selectionField.setText(str); 532 } 533 534 /** 535 * set the text in the filterField 536 */ 537 void setFilterField(String str) { 538 filterField.setText(str); 539 } 540 541 /** 542 * 543 * @see java.awt.event.ItemEvent 544 * ItemEvent.ITEM_STATE_CHANGED 545 */ 546 public void itemStateChanged(ItemEvent itemEvent){ 547 if (itemEvent.getID() != ItemEvent.ITEM_STATE_CHANGED || 548 itemEvent.getStateChange() == ItemEvent.DESELECTED) { 549 return; 550 } 551 552 Object source = itemEvent.getSource(); 553 554 if (source == pathChoice) { 555 /* 556 * Update the selection ('folder name' text field) after 557 * the current item changing in the unfurled choice by the arrow keys. 558 * See 6259434, 6240074 for more information 559 */ 560 String dir = pathChoice.getSelectedItem(); 561 pathField.setText(dir); 562 } else if (directoryList == source) { 563 setFilterField(getFileName(filterField.getText())); 564 } else if (fileList == source) { 565 String file = fileList.getItem((Integer)itemEvent.getItem()); 566 setSelectionField(file); 567 } 568 } 569 570 /* 571 * Updates the current directory only if directoryList-specific 572 * action occurred. Returns false if the forward directory is inaccessible 573 */ 574 boolean updateDirectoryByUserAction(String str) { 575 576 String dir; 577 if (str.equals("..")) { 578 dir = getParentDirectory(); 579 } 580 else { 581 dir = this.dir + str; 582 } 583 584 File fe = new File(dir); 585 if (fe.canRead()) { 586 this.dir = dir; 587 return true; 588 }else { 589 return false; 590 } 591 } 592 593 String getParentDirectory(){ 594 String parent = this.dir; 595 if (!this.dir.equals("/")) // If the current directory is "/" leave it alone. 596 { 597 if (dir.endsWith("/")) 598 parent = parent.substring(0,parent.lastIndexOf("/")); 599 600 parent = parent.substring(0,parent.lastIndexOf("/")+1); 601 } 602 return parent; 603 } 604 605 public void actionPerformed( ActionEvent actionEvent ) { 606 String actionCommand = actionEvent.getActionCommand(); 607 Object source = actionEvent.getSource(); 608 609 if (actionCommand.equals(actionButtonText)) { 610 handleSelection( selectionField.getText() ); 611 handleQuitButton(); 612 } else if (actionCommand.equals(filterLabelText)) { 613 handleFilter( filterField.getText() ); 614 } else if (actionCommand.equals(cancelButtonText)) { 615 handleCancel(); 616 } else if ( source instanceof TextField ) { 617 if ( selectionField == ((TextField)source) ) { 618 // Fixed within 6259434: PIT: Choice in FileDialog is not responding to keyboard interactions, XToolkit 619 // We should handle the action based on the selection field 620 // Looks like mistake 621 handleSelection(selectionField.getText()); 622 handleQuitButton(); 623 } else if (filterField == ((TextField)source)) { 624 handleFilter(filterField.getText()); 625 } else if (pathField == ((TextField)source)) { 626 target.setDirectory(pathField.getText()); 627 } 628 } else if (source instanceof List) { 629 if (directoryList == ((List)source)) { 630 //handleFilter( actionCommand + getFileName( filterField.getText() ) ); 631 if (updateDirectoryByUserAction(actionCommand)){ 632 handleFilter( getFileName( filterField.getText() ) ); 633 } 634 } else if (fileList == ((List)source)) { 635 handleSelection( actionCommand ); 636 handleQuitButton(); 637 } 638 } 639 } 640 641 public boolean dispatchKeyEvent(KeyEvent keyEvent) { 642 int id = keyEvent.getID(); 643 int keyCode = keyEvent.getKeyCode(); 644 645 if (id == KeyEvent.KEY_PRESSED && keyCode == KeyEvent.VK_ESCAPE) { 646 synchronized (target.getTreeLock()) { 647 Component comp = (Component) keyEvent.getSource(); 648 while (comp != null) { 649 // Fix for 6240084 Disposing a file dialog when the drop-down is active does not dispose the dropdown menu, on Xtoolkit 650 // See also 6259493 651 if (comp == pathChoice) { 652 XChoicePeer choicePeer = (XChoicePeer)pathChoice.getPeer(); 653 if (choicePeer.isUnfurled()){ 654 return false; 655 } 656 } 657 if (comp.getPeer() == this) { 658 handleCancel(); 659 return true; 660 } 661 comp = comp.getParent(); 662 } 663 } 664 } 665 666 return false; 667 } 668 669 670 /** 671 * set the file 672 */ 673 public void setFile(String file) { 674 675 if (file == null) { 676 this.file = null; 677 return; 678 } 679 680 if (this.dir == null) { 681 String d = "./"; 682 File f = new File(d, file); 683 684 if (f.isFile()) { 685 this.file = file; 686 setDirectory(d); 687 } 688 } else { 689 File f = new File(this.dir, file); 690 if (f.isFile()) { 691 this.file = file; 692 } 693 } 694 695 setSelectionField(file); 696 } 697 698 /** 699 * set the directory 700 * FIXME: we should update 'savedDir' after programmatically 'setDirectory' 701 * Otherwise, SavedDir will be not null before second showing 702 * So the current directory of the file dialog will be incorrect after second showing 703 * since 'setDirectory' will be ignored 704 * We cann't update savedDir here now since it used very often 705 */ 706 public void setDirectory(String dir) { 707 708 if (dir == null) { 709 this.dir = null; 710 return; 711 } 712 713 if (dir.equals(this.dir)) { 714 return; 715 } 716 717 int i; 718 if ((i=dir.indexOf("~")) != -1) { 719 720 dir = dir.substring(0,i) + System.getProperty("user.home") + dir.substring(i+1,dir.length()); 721 } 722 723 File fe = new File(dir).getAbsoluteFile(); 724 if (log.isLoggable(PlatformLogger.Level.FINE)) { 725 log.fine("Current directory : " + fe); 726 } 727 728 if (!fe.isDirectory()) { 729 dir = "./"; 730 fe = new File(dir).getAbsoluteFile(); 731 732 if (!fe.isDirectory()) { 733 return; 734 } 735 } 736 try { 737 dir = this.dir = fe.getCanonicalPath(); 738 } catch (java.io.IOException ie) { 739 dir = this.dir = fe.getAbsolutePath(); 740 } 741 pathField.setText(this.dir); 742 743 744 if (dir.endsWith("/")) { 745 this.dir = dir; 746 handleFilter(""); 747 } else { 748 this.dir = dir + "/"; 749 handleFilter(""); 750 } 751 752 // Some code was removed 753 // Now we do updating of the pathChoice at the time of the choice opening 754 // Fixed problem: 755 // The exception java.awt.IllegalComponentStateException will be thrown 756 // if the user invoke setDirectory after the closing of the file dialog 757 } 758 759 /** 760 * set filenameFilter 761 * 762 */ 763 public void setFilenameFilter(FilenameFilter filter) { 764 this.filter = filter; 765 } 766 767 768 public void dispose() { 769 FileDialog fd = (FileDialog)fileDialog; 770 if (fd != null) { 771 fd.removeAll(); 772 } 773 super.dispose(); 774 } 775 776 // 03/02/2005 b5097243 Pressing 'ESC' on a file dlg does not dispose the dlg on Xtoolkit 777 public void setVisible(boolean b){ 778 if (fileDialog == null) { 779 init(target); 780 } 781 782 if (savedDir != null || userDir != null) { 783 setDirectory(savedDir != null ? savedDir : userDir); 784 } 785 786 if (savedFile != null) { 787 // Actually in Motif implementation lost file value which was saved after prevously showing 788 // Seems we shouldn't restore Motif behaviour in this case 789 setFile(savedFile); 790 } 791 792 super.setVisible(b); 793 if (b == true){ 794 // See 6240074 for more information 795 XChoicePeer choicePeer = (XChoicePeer)pathChoice.getPeer(); 796 choicePeer.addXChoicePeerListener(this); 797 KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(this); 798 }else{ 799 // See 6240074 for more information 800 XChoicePeer choicePeer = (XChoicePeer)pathChoice.getPeer(); 801 choicePeer.removeXChoicePeerListener(); 802 KeyboardFocusManager.getCurrentKeyboardFocusManager().removeKeyEventDispatcher(this); 803 } 804 805 selectionField.requestFocusInWindow(); 806 } 807 808 /* 809 * Adding items to the path choice based on the text string 810 * See 6240074 for more information 811 */ 812 public void addItemsToPathChoice(String text){ 813 String dirList[] = getDirList(text); 814 for (int i = 0; i < dirList.length; i++) pathChoice.addItem(dirList[i]); 815 } 816 817 /* 818 * Refresh the unfurled choice at the time of the opening choice according to the text of the path field 819 * See 6240074 for more information 820 */ 821 public void unfurledChoiceOpening(ListHelper choiceHelper){ 822 823 // When the unfurled choice is opening the first time, we need only to add elements, otherwise we've got exception 824 if (choiceHelper.getItemCount() == 0){ 825 addItemsToPathChoice(pathField.getText()); 826 return; 827 } 828 829 // If the set of the directories the exactly same as the used to be then dummy 830 if (pathChoice.getItem(0).equals(pathField.getText())) 831 return; 832 833 pathChoice.removeAll(); 834 addItemsToPathChoice(pathField.getText()); 835 } 836 837 /* 838 * Refresh the file dialog at the time of the closing choice according to the selected item of the choice 839 * See 6240074 for more information 840 */ 841 public void unfurledChoiceClosing(){ 842 // This is the exactly same code as invoking later at the time of the itemStateChanged 843 // Here is we restore Windows behaviour: change current directory if user press 'ESC' 844 String dir = pathChoice.getSelectedItem(); 845 target.setDirectory(dir); 846 } 847 } 848 849 @SuppressWarnings("serial") // JDK-implementation class 850 class Separator extends Canvas { 851 public final static int HORIZONTAL = 0; 852 public final static int VERTICAL = 1; 853 int orientation; 854 855 public Separator(int length, int thickness, int orient) { 856 super(); 857 orientation = orient; 858 if (orient == HORIZONTAL) { 859 resize(length, thickness); 860 } else { 861 // VERTICAL 862 resize(thickness, length); 863 } 864 } 865 866 public void paint(Graphics g) { 867 int x1, y1, x2, y2; 868 Rectangle bbox = bounds(); 869 Color c = getBackground(); 870 Color brighter = c.brighter(); 871 Color darker = c.darker(); 872 873 if (orientation == HORIZONTAL) { 874 x1 = 0; 875 x2 = bbox.width - 1; 876 y1 = y2 = bbox.height/2 - 1; 877 878 } else { 879 // VERTICAL 880 x1 = x2 = bbox.width/2 - 1; 881 y1 = 0; 882 y2 = bbox.height - 1; 883 } 884 g.setColor(darker); 885 g.drawLine(x1, y2, x2, y2); 886 g.setColor(brighter); 887 if (orientation == HORIZONTAL) 888 g.drawLine(x1, y2+1, x2, y2+1); 889 else 890 g.drawLine(x1+1, y2, x2+1, y2); 891 } 892 } 893 894 /* 895 * Motif file dialogs let the user specify a filter that controls the files that 896 * are displayed in the dialog. This filter is generally specified as a regular 897 * expression. The class is used to implement Motif-like filtering. 898 */ 899 class FileDialogFilter implements FilenameFilter { 900 901 String filter; 902 903 public FileDialogFilter(String f) { 904 filter = f; 905 } 906 907 /* 908 * Tells whether or not the specified file should be included in a file list 909 */ 910 public boolean accept(File dir, String fileName) { 911 912 File f = new File(dir, fileName); 913 914 if (f.isDirectory()) { 915 return true; 916 } else { 917 return matches(fileName, filter); 918 } 919 } 920 921 /* 922 * Tells whether or not the input string matches the given filter 923 */ 924 private boolean matches(String input, String filter) { 925 String regex = convert(filter); 926 return input.matches(regex); 927 } 928 929 /* 930 * Converts the filter into the form which is acceptable by Java's regexps 931 */ 932 private String convert(String filter) { 933 String regex = "^" + filter + "$"; 934 regex = regex.replaceAll("\\.", "\\\\."); 935 regex = regex.replaceAll("\\?", "."); 936 regex = regex.replaceAll("\\*", ".*"); 937 return regex; 938 } 939 }