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