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