1 /* 2 * Copyright (c) 2003, 2013, 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 installStrings()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 XFileDialogPeer(FileDialog target)133 XFileDialogPeer(FileDialog target) { 134 super((Dialog)target); 135 this.target = target; 136 } 137 init(FileDialog target)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 updateMinimumSize()317 public void updateMinimumSize() { 318 } 319 updateIconImages()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 */ 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)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 */ getFileName(String str)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 */ handleFilter(String f)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 */ handleSelection(String file)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 */ handleCancel()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 */ handleQuitButton()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 */ setFilterEntry(String d, String f)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 getDirList(String dir)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 */ setSelectionField(String str)529 void setSelectionField(String str) { 530 selectionField.setText(str); 531 } 532 533 /** 534 * set the text in the filterField 535 */ setFilterField(String str)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 */ itemStateChanged(ItemEvent itemEvent)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 */ updateDirectoryByUserAction(String str)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 getParentDirectory()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 actionPerformed( ActionEvent actionEvent )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 dispatchKeyEvent(KeyEvent keyEvent)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 */ setFile(String file)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 */ setDirectory(String dir)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.Level.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 */ setFilenameFilter(FilenameFilter filter)762 public void setFilenameFilter(FilenameFilter filter) { 763 this.filter = filter; 764 } 765 766 dispose()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 setVisible(boolean b)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 */ addItemsToPathChoice(String text)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 */ unfurledChoiceOpening(ListHelper choiceHelper)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 */ unfurledChoiceClosing()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 Separator(int length, int thickness, int orient)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 paint(Graphics g)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 FileDialogFilter(String f)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 */ accept(File dir, String fileName)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 */ matches(String input, String filter)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 */ convert(String filter)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 } 938