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 com.sun.java.swing.plaf.windows; 27 28 import javax.swing.*; 29 import javax.swing.border.*; 30 import javax.swing.filechooser.*; 31 import javax.swing.event.*; 32 import javax.swing.plaf.*; 33 import javax.swing.plaf.basic.*; 34 import java.awt.*; 35 import java.awt.event.*; 36 import java.awt.image.BufferedImage; 37 import java.beans.*; 38 import java.io.File; 39 import java.io.FileNotFoundException; 40 import java.io.IOException; 41 import java.util.*; 42 import java.security.AccessController; 43 import java.security.PrivilegedAction; 44 45 import sun.awt.shell.ShellFolder; 46 import sun.swing.*; 47 48 import javax.accessibility.*; 49 50 /** 51 * Windows {@literal L&F} implementation of a FileChooser. 52 * 53 * @author Jeff Dinkins 54 */ 55 public class WindowsFileChooserUI extends BasicFileChooserUI { 56 57 // The following are private because the implementation of the 58 // Windows FileChooser L&F is not complete yet. 59 60 private JPanel centerPanel; 61 62 private JLabel lookInLabel; 63 private JComboBox<File> directoryComboBox; 64 private DirectoryComboBoxModel directoryComboBoxModel; 65 private ActionListener directoryComboBoxAction = new DirectoryComboBoxAction(); 66 67 private FilterComboBoxModel filterComboBoxModel; 68 69 private JTextField filenameTextField; 70 private FilePane filePane; 71 private WindowsPlacesBar placesBar; 72 73 private JButton approveButton; 74 private JButton cancelButton; 75 76 private JPanel buttonPanel; 77 private JPanel bottomPanel; 78 79 private JComboBox<FileFilter> filterComboBox; 80 81 private static final Dimension hstrut10 = new Dimension(10, 1); 82 83 private static final Dimension vstrut4 = new Dimension(1, 4); 84 private static final Dimension vstrut6 = new Dimension(1, 6); 85 private static final Dimension vstrut8 = new Dimension(1, 8); 86 87 private static final Insets shrinkwrap = new Insets(0,0,0,0); 88 89 // Preferred and Minimum sizes for the dialog box 90 private static int PREF_WIDTH = 425; 91 private static int PREF_HEIGHT = 245; 92 private static Dimension PREF_SIZE = new Dimension(PREF_WIDTH, PREF_HEIGHT); 93 94 private static int MIN_WIDTH = 425; 95 private static int MIN_HEIGHT = 245; 96 97 private static int LIST_PREF_WIDTH = 444; 98 private static int LIST_PREF_HEIGHT = 138; 99 private static Dimension LIST_PREF_SIZE = new Dimension(LIST_PREF_WIDTH, LIST_PREF_HEIGHT); 100 101 // Labels, mnemonics, and tooltips (oh my!) 102 private int lookInLabelMnemonic = 0; 103 private String lookInLabelText = null; 104 private String saveInLabelText = null; 105 106 private int fileNameLabelMnemonic = 0; 107 private String fileNameLabelText = null; 108 private int folderNameLabelMnemonic = 0; 109 private String folderNameLabelText = null; 110 111 private int filesOfTypeLabelMnemonic = 0; 112 private String filesOfTypeLabelText = null; 113 114 private String upFolderToolTipText = null; 115 private String upFolderAccessibleName = null; 116 117 private String newFolderToolTipText = null; 118 private String newFolderAccessibleName = null; 119 120 private String viewMenuButtonToolTipText = null; 121 private String viewMenuButtonAccessibleName = null; 122 123 private BasicFileView fileView = new WindowsFileView(); 124 125 private JLabel fileNameLabel; 126 127 private void populateFileNameLabel() { 128 if (getFileChooser().getFileSelectionMode() == JFileChooser.DIRECTORIES_ONLY) { 129 fileNameLabel.setText(folderNameLabelText); 130 fileNameLabel.setDisplayedMnemonic(folderNameLabelMnemonic); 131 } else { 132 fileNameLabel.setText(fileNameLabelText); 133 fileNameLabel.setDisplayedMnemonic(fileNameLabelMnemonic); 134 } 135 } 136 137 // 138 // ComponentUI Interface Implementation methods 139 // 140 public static ComponentUI createUI(JComponent c) { 141 return new WindowsFileChooserUI((JFileChooser) c); 142 } 143 144 public WindowsFileChooserUI(JFileChooser filechooser) { 145 super(filechooser); 146 } 147 148 public void installUI(JComponent c) { 149 super.installUI(c); 150 } 151 152 public void uninstallComponents(JFileChooser fc) { 153 fc.removeAll(); 154 } 155 156 private class WindowsFileChooserUIAccessor implements FilePane.FileChooserUIAccessor { 157 public JFileChooser getFileChooser() { 158 return WindowsFileChooserUI.this.getFileChooser(); 159 } 160 161 public BasicDirectoryModel getModel() { 162 return WindowsFileChooserUI.this.getModel(); 163 } 164 165 public JPanel createList() { 166 return WindowsFileChooserUI.this.createList(getFileChooser()); 167 } 168 169 public JPanel createDetailsView() { 170 return WindowsFileChooserUI.this.createDetailsView(getFileChooser()); 171 } 172 173 public boolean isDirectorySelected() { 174 return WindowsFileChooserUI.this.isDirectorySelected(); 175 } 176 177 public File getDirectory() { 178 return WindowsFileChooserUI.this.getDirectory(); 179 } 180 181 public Action getChangeToParentDirectoryAction() { 182 return WindowsFileChooserUI.this.getChangeToParentDirectoryAction(); 183 } 184 185 public Action getApproveSelectionAction() { 186 return WindowsFileChooserUI.this.getApproveSelectionAction(); 187 } 188 189 public Action getNewFolderAction() { 190 return WindowsFileChooserUI.this.getNewFolderAction(); 191 } 192 193 public MouseListener createDoubleClickListener(JList<?> list) { 194 return WindowsFileChooserUI.this.createDoubleClickListener(getFileChooser(), 195 list); 196 } 197 198 public ListSelectionListener createListSelectionListener() { 199 return WindowsFileChooserUI.this.createListSelectionListener(getFileChooser()); 200 } 201 } 202 203 public void installComponents(JFileChooser fc) { 204 filePane = new FilePane(new WindowsFileChooserUIAccessor()); 205 fc.addPropertyChangeListener(filePane); 206 207 FileSystemView fsv = fc.getFileSystemView(); 208 209 fc.setBorder(new EmptyBorder(4, 10, 10, 10)); 210 fc.setLayout(new BorderLayout(8, 8)); 211 212 updateUseShellFolder(); 213 214 // ********************************* // 215 // **** Construct the top panel **** // 216 // ********************************* // 217 218 // Directory manipulation buttons 219 JToolBar topPanel = new JToolBar(); 220 topPanel.setFloatable(false); 221 topPanel.putClientProperty("JToolBar.isRollover", Boolean.TRUE); 222 223 // Add the top panel to the fileChooser 224 fc.add(topPanel, BorderLayout.NORTH); 225 226 // ComboBox Label 227 @SuppressWarnings("serial") // anonymous class 228 JLabel tmp1 = new JLabel(lookInLabelText, JLabel.TRAILING) { 229 public Dimension getPreferredSize() { 230 return getMinimumSize(); 231 } 232 233 public Dimension getMinimumSize() { 234 Dimension d = super.getPreferredSize(); 235 if (placesBar != null) { 236 d.width = Math.max(d.width, placesBar.getWidth()); 237 } 238 return d; 239 } 240 }; 241 lookInLabel = tmp1; 242 lookInLabel.setDisplayedMnemonic(lookInLabelMnemonic); 243 lookInLabel.setAlignmentX(JComponent.LEFT_ALIGNMENT); 244 lookInLabel.setAlignmentY(JComponent.CENTER_ALIGNMENT); 245 topPanel.add(lookInLabel); 246 topPanel.add(Box.createRigidArea(new Dimension(8,0))); 247 248 // CurrentDir ComboBox 249 @SuppressWarnings("serial") // anonymous class 250 JComboBox<File> tmp2 = new JComboBox<File>() { 251 public Dimension getMinimumSize() { 252 Dimension d = super.getMinimumSize(); 253 d.width = 60; 254 return d; 255 } 256 257 public Dimension getPreferredSize() { 258 Dimension d = super.getPreferredSize(); 259 // Must be small enough to not affect total width. 260 d.width = 150; 261 return d; 262 } 263 }; 264 directoryComboBox = tmp2; 265 directoryComboBox.putClientProperty( "JComboBox.lightweightKeyboardNavigation", "Lightweight" ); 266 lookInLabel.setLabelFor(directoryComboBox); 267 directoryComboBoxModel = createDirectoryComboBoxModel(fc); 268 directoryComboBox.setModel(directoryComboBoxModel); 269 directoryComboBox.addActionListener(directoryComboBoxAction); 270 directoryComboBox.setRenderer(createDirectoryComboBoxRenderer(fc)); 271 directoryComboBox.setAlignmentX(JComponent.LEFT_ALIGNMENT); 272 directoryComboBox.setAlignmentY(JComponent.CENTER_ALIGNMENT); 273 directoryComboBox.setMaximumRowCount(8); 274 275 topPanel.add(directoryComboBox); 276 topPanel.add(Box.createRigidArea(hstrut10)); 277 278 // Up Button 279 JButton upFolderButton = createToolButton(getChangeToParentDirectoryAction(), upFolderIcon, 280 upFolderToolTipText, upFolderAccessibleName); 281 topPanel.add(upFolderButton); 282 283 // New Directory Button 284 if (!UIManager.getBoolean("FileChooser.readOnly")) { 285 JButton newFolderButton = createToolButton(filePane.getNewFolderAction(), newFolderIcon, 286 newFolderToolTipText, newFolderAccessibleName); 287 topPanel.add(newFolderButton); 288 } 289 290 // View button group 291 ButtonGroup viewButtonGroup = new ButtonGroup(); 292 293 // Popup Menu 294 final JPopupMenu viewTypePopupMenu = new JPopupMenu(); 295 296 final JRadioButtonMenuItem listViewMenuItem = new JRadioButtonMenuItem( 297 filePane.getViewTypeAction(FilePane.VIEWTYPE_LIST)); 298 listViewMenuItem.setSelected(filePane.getViewType() == FilePane.VIEWTYPE_LIST); 299 viewTypePopupMenu.add(listViewMenuItem); 300 viewButtonGroup.add(listViewMenuItem); 301 302 final JRadioButtonMenuItem detailsViewMenuItem = new JRadioButtonMenuItem( 303 filePane.getViewTypeAction(FilePane.VIEWTYPE_DETAILS)); 304 detailsViewMenuItem.setSelected(filePane.getViewType() == FilePane.VIEWTYPE_DETAILS); 305 viewTypePopupMenu.add(detailsViewMenuItem); 306 viewButtonGroup.add(detailsViewMenuItem); 307 308 // Create icon for viewMenuButton 309 BufferedImage image = new BufferedImage(viewMenuIcon.getIconWidth() + 7, viewMenuIcon.getIconHeight(), 310 BufferedImage.TYPE_INT_ARGB); 311 Graphics graphics = image.getGraphics(); 312 viewMenuIcon.paintIcon(filePane, graphics, 0, 0); 313 int x = image.getWidth() - 5; 314 int y = image.getHeight() / 2 - 1; 315 graphics.setColor(Color.BLACK); 316 graphics.fillPolygon(new int[]{x, x + 5, x + 2}, new int[]{y, y, y + 3}, 3); 317 318 // Details Button 319 final JButton viewMenuButton = createToolButton(null, new ImageIcon(image), viewMenuButtonToolTipText, 320 viewMenuButtonAccessibleName); 321 322 viewMenuButton.addMouseListener(new MouseAdapter() { 323 public void mousePressed(MouseEvent e) { 324 if (SwingUtilities.isLeftMouseButton(e) && !viewMenuButton.isSelected()) { 325 viewMenuButton.setSelected(true); 326 327 viewTypePopupMenu.show(viewMenuButton, 0, viewMenuButton.getHeight()); 328 } 329 } 330 }); 331 viewMenuButton.addKeyListener(new KeyAdapter() { 332 public void keyPressed(KeyEvent e) { 333 // Forbid keyboard actions if the button is not in rollover state 334 if (e.getKeyCode() == KeyEvent.VK_SPACE && viewMenuButton.getModel().isRollover()) { 335 viewMenuButton.setSelected(true); 336 337 viewTypePopupMenu.show(viewMenuButton, 0, viewMenuButton.getHeight()); 338 } 339 } 340 }); 341 viewTypePopupMenu.addPopupMenuListener(new PopupMenuListener() { 342 public void popupMenuWillBecomeVisible(PopupMenuEvent e) { 343 } 344 345 public void popupMenuWillBecomeInvisible(PopupMenuEvent e) { 346 SwingUtilities.invokeLater(new Runnable() { 347 public void run() { 348 viewMenuButton.setSelected(false); 349 } 350 }); 351 } 352 353 public void popupMenuCanceled(PopupMenuEvent e) { 354 } 355 }); 356 357 topPanel.add(viewMenuButton); 358 359 topPanel.add(Box.createRigidArea(new Dimension(80, 0))); 360 361 filePane.addPropertyChangeListener(new PropertyChangeListener() { 362 public void propertyChange(PropertyChangeEvent e) { 363 if ("viewType".equals(e.getPropertyName())) { 364 switch (filePane.getViewType()) { 365 case FilePane.VIEWTYPE_LIST: 366 listViewMenuItem.setSelected(true); 367 break; 368 369 case FilePane.VIEWTYPE_DETAILS: 370 detailsViewMenuItem.setSelected(true); 371 break; 372 } 373 } 374 } 375 }); 376 377 // ************************************** // 378 // ******* Add the directory pane ******* // 379 // ************************************** // 380 centerPanel = new JPanel(new BorderLayout()); 381 centerPanel.add(getAccessoryPanel(), BorderLayout.AFTER_LINE_ENDS); 382 JComponent accessory = fc.getAccessory(); 383 if(accessory != null) { 384 getAccessoryPanel().add(accessory); 385 } 386 filePane.setPreferredSize(LIST_PREF_SIZE); 387 centerPanel.add(filePane, BorderLayout.CENTER); 388 fc.add(centerPanel, BorderLayout.CENTER); 389 390 // ********************************** // 391 // **** Construct the bottom panel ** // 392 // ********************************** // 393 getBottomPanel().setLayout(new BoxLayout(getBottomPanel(), BoxLayout.LINE_AXIS)); 394 395 // Add the bottom panel to file chooser 396 centerPanel.add(getBottomPanel(), BorderLayout.SOUTH); 397 398 // labels 399 JPanel labelPanel = new JPanel(); 400 labelPanel.setLayout(new BoxLayout(labelPanel, BoxLayout.PAGE_AXIS)); 401 labelPanel.add(Box.createRigidArea(vstrut4)); 402 403 fileNameLabel = new JLabel(); 404 populateFileNameLabel(); 405 fileNameLabel.setAlignmentY(0); 406 labelPanel.add(fileNameLabel); 407 408 labelPanel.add(Box.createRigidArea(new Dimension(1,12))); 409 410 JLabel ftl = new JLabel(filesOfTypeLabelText); 411 ftl.setDisplayedMnemonic(filesOfTypeLabelMnemonic); 412 labelPanel.add(ftl); 413 414 getBottomPanel().add(labelPanel); 415 getBottomPanel().add(Box.createRigidArea(new Dimension(15, 0))); 416 417 // file entry and filters 418 JPanel fileAndFilterPanel = new JPanel(); 419 fileAndFilterPanel.add(Box.createRigidArea(vstrut8)); 420 fileAndFilterPanel.setLayout(new BoxLayout(fileAndFilterPanel, BoxLayout.Y_AXIS)); 421 422 @SuppressWarnings("serial") // anonymous class 423 JTextField tmp3 = new JTextField(35) { 424 public Dimension getMaximumSize() { 425 return new Dimension(Short.MAX_VALUE, super.getPreferredSize().height); 426 } 427 }; 428 filenameTextField = tmp3; 429 430 fileNameLabel.setLabelFor(filenameTextField); 431 filenameTextField.addFocusListener( 432 new FocusAdapter() { 433 public void focusGained(FocusEvent e) { 434 if (!getFileChooser().isMultiSelectionEnabled()) { 435 filePane.clearSelection(); 436 } 437 } 438 } 439 ); 440 441 if (fc.isMultiSelectionEnabled()) { 442 setFileName(fileNameString(fc.getSelectedFiles())); 443 } else { 444 setFileName(fileNameString(fc.getSelectedFile())); 445 } 446 447 fileAndFilterPanel.add(filenameTextField); 448 fileAndFilterPanel.add(Box.createRigidArea(vstrut8)); 449 450 filterComboBoxModel = createFilterComboBoxModel(); 451 fc.addPropertyChangeListener(filterComboBoxModel); 452 filterComboBox = new JComboBox<FileFilter>(filterComboBoxModel); 453 ftl.setLabelFor(filterComboBox); 454 filterComboBox.setRenderer(createFilterComboBoxRenderer()); 455 fileAndFilterPanel.add(filterComboBox); 456 457 getBottomPanel().add(fileAndFilterPanel); 458 getBottomPanel().add(Box.createRigidArea(new Dimension(30, 0))); 459 460 // buttons 461 getButtonPanel().setLayout(new BoxLayout(getButtonPanel(), BoxLayout.Y_AXIS)); 462 463 @SuppressWarnings("serial") // anonymous class 464 JButton tmp4 = new JButton(getApproveButtonText(fc)) { 465 public Dimension getMaximumSize() { 466 return approveButton.getPreferredSize().width > cancelButton.getPreferredSize().width ? 467 approveButton.getPreferredSize() : cancelButton.getPreferredSize(); 468 } 469 }; 470 approveButton = tmp4; 471 Insets buttonMargin = approveButton.getMargin(); 472 buttonMargin = new InsetsUIResource(buttonMargin.top, buttonMargin.left + 5, 473 buttonMargin.bottom, buttonMargin.right + 5); 474 approveButton.setMargin(buttonMargin); 475 approveButton.setMnemonic(getApproveButtonMnemonic(fc)); 476 approveButton.addActionListener(getApproveSelectionAction()); 477 approveButton.setToolTipText(getApproveButtonToolTipText(fc)); 478 getButtonPanel().add(Box.createRigidArea(vstrut6)); 479 getButtonPanel().add(approveButton); 480 getButtonPanel().add(Box.createRigidArea(vstrut4)); 481 482 @SuppressWarnings("serial") // anonymous class 483 JButton tmp5 = new JButton(cancelButtonText) { 484 public Dimension getMaximumSize() { 485 return approveButton.getPreferredSize().width > cancelButton.getPreferredSize().width ? 486 approveButton.getPreferredSize() : cancelButton.getPreferredSize(); 487 } 488 }; 489 cancelButton = tmp5; 490 cancelButton.setMargin(buttonMargin); 491 cancelButton.setToolTipText(cancelButtonToolTipText); 492 cancelButton.addActionListener(getCancelSelectionAction()); 493 getButtonPanel().add(cancelButton); 494 495 if(fc.getControlButtonsAreShown()) { 496 addControlButtons(); 497 } 498 } 499 500 private void updateUseShellFolder() { 501 // Decide whether to use the ShellFolder class to populate shortcut 502 // panel and combobox. 503 JFileChooser fc = getFileChooser(); 504 505 if (FilePane.usesShellFolder(fc)) { 506 if (placesBar == null && !UIManager.getBoolean("FileChooser.noPlacesBar")) { 507 placesBar = new WindowsPlacesBar(fc, XPStyle.getXP() != null); 508 fc.add(placesBar, BorderLayout.BEFORE_LINE_BEGINS); 509 fc.addPropertyChangeListener(placesBar); 510 } 511 } else { 512 if (placesBar != null) { 513 fc.remove(placesBar); 514 fc.removePropertyChangeListener(placesBar); 515 placesBar = null; 516 } 517 } 518 } 519 520 protected JPanel getButtonPanel() { 521 if(buttonPanel == null) { 522 buttonPanel = new JPanel(); 523 } 524 return buttonPanel; 525 } 526 527 protected JPanel getBottomPanel() { 528 if(bottomPanel == null) { 529 bottomPanel = new JPanel(); 530 } 531 return bottomPanel; 532 } 533 534 protected void installStrings(JFileChooser fc) { 535 super.installStrings(fc); 536 537 Locale l = fc.getLocale(); 538 539 lookInLabelMnemonic = getMnemonic("FileChooser.lookInLabelMnemonic", l); 540 lookInLabelText = UIManager.getString("FileChooser.lookInLabelText",l); 541 saveInLabelText = UIManager.getString("FileChooser.saveInLabelText",l); 542 543 fileNameLabelMnemonic = getMnemonic("FileChooser.fileNameLabelMnemonic", l); 544 fileNameLabelText = UIManager.getString("FileChooser.fileNameLabelText",l); 545 folderNameLabelMnemonic = getMnemonic("FileChooser.folderNameLabelMnemonic", l); 546 folderNameLabelText = UIManager.getString("FileChooser.folderNameLabelText",l); 547 548 filesOfTypeLabelMnemonic = getMnemonic("FileChooser.filesOfTypeLabelMnemonic", l); 549 filesOfTypeLabelText = UIManager.getString("FileChooser.filesOfTypeLabelText",l); 550 551 upFolderToolTipText = UIManager.getString("FileChooser.upFolderToolTipText",l); 552 upFolderAccessibleName = UIManager.getString("FileChooser.upFolderAccessibleName",l); 553 554 newFolderToolTipText = UIManager.getString("FileChooser.newFolderToolTipText",l); 555 newFolderAccessibleName = UIManager.getString("FileChooser.newFolderAccessibleName",l); 556 557 viewMenuButtonToolTipText = UIManager.getString("FileChooser.viewMenuButtonToolTipText",l); 558 viewMenuButtonAccessibleName = UIManager.getString("FileChooser.viewMenuButtonAccessibleName",l); 559 } 560 561 private Integer getMnemonic(String key, Locale l) { 562 return SwingUtilities2.getUIDefaultsInt(key, l); 563 } 564 565 protected void installListeners(JFileChooser fc) { 566 super.installListeners(fc); 567 ActionMap actionMap = getActionMap(); 568 SwingUtilities.replaceUIActionMap(fc, actionMap); 569 } 570 571 protected ActionMap getActionMap() { 572 return createActionMap(); 573 } 574 575 protected ActionMap createActionMap() { 576 ActionMap map = new ActionMapUIResource(); 577 FilePane.addActionsToMap(map, filePane.getActions()); 578 return map; 579 } 580 581 protected JPanel createList(JFileChooser fc) { 582 return filePane.createList(); 583 } 584 585 protected JPanel createDetailsView(JFileChooser fc) { 586 return filePane.createDetailsView(); 587 } 588 589 /** 590 * Creates a selection listener for the list of files and directories. 591 * 592 * @param fc a <code>JFileChooser</code> 593 * @return a <code>ListSelectionListener</code> 594 */ 595 public ListSelectionListener createListSelectionListener(JFileChooser fc) { 596 return super.createListSelectionListener(fc); 597 } 598 599 // Obsolete class, not used in this version. 600 @SuppressWarnings("serial") 601 protected class WindowsNewFolderAction extends NewFolderAction { 602 } 603 604 // Obsolete class, not used in this version. 605 protected class SingleClickListener extends MouseAdapter { 606 } 607 608 // Obsolete class, not used in this version. 609 @SuppressWarnings("serial") // Superclass is not serializable across versions 610 protected class FileRenderer extends DefaultListCellRenderer { 611 } 612 613 public void uninstallUI(JComponent c) { 614 // Remove listeners 615 c.removePropertyChangeListener(filterComboBoxModel); 616 c.removePropertyChangeListener(filePane); 617 if (placesBar != null) { 618 c.removePropertyChangeListener(placesBar); 619 } 620 cancelButton.removeActionListener(getCancelSelectionAction()); 621 approveButton.removeActionListener(getApproveSelectionAction()); 622 filenameTextField.removeActionListener(getApproveSelectionAction()); 623 624 if (filePane != null) { 625 filePane.uninstallUI(); 626 filePane = null; 627 } 628 629 super.uninstallUI(c); 630 } 631 632 /** 633 * Returns the preferred size of the specified 634 * <code>JFileChooser</code>. 635 * The preferred size is at least as large, 636 * in both height and width, 637 * as the preferred size recommended 638 * by the file chooser's layout manager. 639 * 640 * @param c a <code>JFileChooser</code> 641 * @return a <code>Dimension</code> specifying the preferred 642 * width and height of the file chooser 643 */ 644 @Override 645 public Dimension getPreferredSize(JComponent c) { 646 int prefWidth = PREF_SIZE.width; 647 Dimension d = c.getLayout().preferredLayoutSize(c); 648 if (d != null) { 649 return new Dimension(d.width < prefWidth ? prefWidth : d.width, 650 d.height < PREF_SIZE.height ? PREF_SIZE.height : d.height); 651 } else { 652 return new Dimension(prefWidth, PREF_SIZE.height); 653 } 654 } 655 656 /** 657 * Returns the minimum size of the <code>JFileChooser</code>. 658 * 659 * @param c a <code>JFileChooser</code> 660 * @return a <code>Dimension</code> specifying the minimum 661 * width and height of the file chooser 662 */ 663 @Override 664 public Dimension getMinimumSize(JComponent c) { 665 return new Dimension(MIN_WIDTH, MIN_HEIGHT); 666 } 667 668 /** 669 * Returns the maximum size of the <code>JFileChooser</code>. 670 * 671 * @param c a <code>JFileChooser</code> 672 * @return a <code>Dimension</code> specifying the maximum 673 * width and height of the file chooser 674 */ 675 @Override 676 public Dimension getMaximumSize(JComponent c) { 677 return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE); 678 } 679 680 private String fileNameString(File file) { 681 if (file == null) { 682 return null; 683 } else { 684 JFileChooser fc = getFileChooser(); 685 if ((fc.isDirectorySelectionEnabled() && !fc.isFileSelectionEnabled()) || 686 (fc.isDirectorySelectionEnabled() && fc.isFileSelectionEnabled() && fc.getFileSystemView().isFileSystemRoot(file))){ 687 return file.getPath(); 688 } else { 689 return file.getName(); 690 } 691 } 692 } 693 694 private String fileNameString(File[] files) { 695 StringBuilder buf = new StringBuilder(); 696 for (int i = 0; files != null && i < files.length; i++) { 697 if (i > 0) { 698 buf.append(" "); 699 } 700 if (files.length > 1) { 701 buf.append("\""); 702 } 703 buf.append(fileNameString(files[i])); 704 if (files.length > 1) { 705 buf.append("\""); 706 } 707 } 708 return buf.toString(); 709 } 710 711 /* The following methods are used by the PropertyChange Listener */ 712 713 private void doSelectedFileChanged(PropertyChangeEvent e) { 714 File f = (File) e.getNewValue(); 715 JFileChooser fc = getFileChooser(); 716 if (f != null 717 && ((fc.isFileSelectionEnabled() && !f.isDirectory()) 718 || (f.isDirectory() && fc.isDirectorySelectionEnabled()))) { 719 720 setFileName(fileNameString(f)); 721 } 722 } 723 724 private void doSelectedFilesChanged(PropertyChangeEvent e) { 725 File[] files = (File[]) e.getNewValue(); 726 JFileChooser fc = getFileChooser(); 727 if (files != null 728 && files.length > 0 729 && (files.length > 1 || fc.isDirectorySelectionEnabled() || !files[0].isDirectory())) { 730 setFileName(fileNameString(files)); 731 } 732 } 733 734 private void doDirectoryChanged(PropertyChangeEvent e) { 735 JFileChooser fc = getFileChooser(); 736 FileSystemView fsv = fc.getFileSystemView(); 737 738 clearIconCache(); 739 File currentDirectory = fc.getCurrentDirectory(); 740 if(currentDirectory != null) { 741 directoryComboBoxModel.addItem(currentDirectory); 742 743 if (fc.isDirectorySelectionEnabled() && !fc.isFileSelectionEnabled()) { 744 if (fsv.isFileSystem(currentDirectory)) { 745 setFileName(currentDirectory.getPath()); 746 } else { 747 setFileName(null); 748 } 749 } 750 } 751 } 752 753 private void doFilterChanged(PropertyChangeEvent e) { 754 clearIconCache(); 755 } 756 757 private void doFileSelectionModeChanged(PropertyChangeEvent e) { 758 if (fileNameLabel != null) { 759 populateFileNameLabel(); 760 } 761 clearIconCache(); 762 763 JFileChooser fc = getFileChooser(); 764 File currentDirectory = fc.getCurrentDirectory(); 765 if (currentDirectory != null 766 && fc.isDirectorySelectionEnabled() 767 && !fc.isFileSelectionEnabled() 768 && fc.getFileSystemView().isFileSystem(currentDirectory)) { 769 770 setFileName(currentDirectory.getPath()); 771 } else { 772 setFileName(null); 773 } 774 } 775 776 private void doAccessoryChanged(PropertyChangeEvent e) { 777 if(getAccessoryPanel() != null) { 778 if(e.getOldValue() != null) { 779 getAccessoryPanel().remove((JComponent) e.getOldValue()); 780 } 781 JComponent accessory = (JComponent) e.getNewValue(); 782 if(accessory != null) { 783 getAccessoryPanel().add(accessory, BorderLayout.CENTER); 784 } 785 } 786 } 787 788 private void doApproveButtonTextChanged(PropertyChangeEvent e) { 789 JFileChooser chooser = getFileChooser(); 790 approveButton.setText(getApproveButtonText(chooser)); 791 approveButton.setToolTipText(getApproveButtonToolTipText(chooser)); 792 approveButton.setMnemonic(getApproveButtonMnemonic(chooser)); 793 } 794 795 private void doDialogTypeChanged(PropertyChangeEvent e) { 796 JFileChooser chooser = getFileChooser(); 797 approveButton.setText(getApproveButtonText(chooser)); 798 approveButton.setToolTipText(getApproveButtonToolTipText(chooser)); 799 approveButton.setMnemonic(getApproveButtonMnemonic(chooser)); 800 if (chooser.getDialogType() == JFileChooser.SAVE_DIALOG) { 801 lookInLabel.setText(saveInLabelText); 802 } else { 803 lookInLabel.setText(lookInLabelText); 804 } 805 } 806 807 private void doApproveButtonMnemonicChanged(PropertyChangeEvent e) { 808 approveButton.setMnemonic(getApproveButtonMnemonic(getFileChooser())); 809 } 810 811 private void doControlButtonsChanged(PropertyChangeEvent e) { 812 if(getFileChooser().getControlButtonsAreShown()) { 813 addControlButtons(); 814 } else { 815 removeControlButtons(); 816 } 817 } 818 819 /* 820 * Listen for filechooser property changes, such as 821 * the selected file changing, or the type of the dialog changing. 822 */ 823 public PropertyChangeListener createPropertyChangeListener(JFileChooser fc) { 824 return new PropertyChangeListener() { 825 public void propertyChange(PropertyChangeEvent e) { 826 String s = e.getPropertyName(); 827 if(s.equals(JFileChooser.SELECTED_FILE_CHANGED_PROPERTY)) { 828 doSelectedFileChanged(e); 829 } else if (s.equals(JFileChooser.SELECTED_FILES_CHANGED_PROPERTY)) { 830 doSelectedFilesChanged(e); 831 } else if(s.equals(JFileChooser.DIRECTORY_CHANGED_PROPERTY)) { 832 doDirectoryChanged(e); 833 } else if(s.equals(JFileChooser.FILE_FILTER_CHANGED_PROPERTY)) { 834 doFilterChanged(e); 835 } else if(s.equals(JFileChooser.FILE_SELECTION_MODE_CHANGED_PROPERTY)) { 836 doFileSelectionModeChanged(e); 837 } else if(s.equals(JFileChooser.ACCESSORY_CHANGED_PROPERTY)) { 838 doAccessoryChanged(e); 839 } else if (s.equals(JFileChooser.APPROVE_BUTTON_TEXT_CHANGED_PROPERTY) || 840 s.equals(JFileChooser.APPROVE_BUTTON_TOOL_TIP_TEXT_CHANGED_PROPERTY)) { 841 doApproveButtonTextChanged(e); 842 } else if(s.equals(JFileChooser.DIALOG_TYPE_CHANGED_PROPERTY)) { 843 doDialogTypeChanged(e); 844 } else if(s.equals(JFileChooser.APPROVE_BUTTON_MNEMONIC_CHANGED_PROPERTY)) { 845 doApproveButtonMnemonicChanged(e); 846 } else if(s.equals(JFileChooser.CONTROL_BUTTONS_ARE_SHOWN_CHANGED_PROPERTY)) { 847 doControlButtonsChanged(e); 848 } else if (s == "FileChooser.useShellFolder") { 849 updateUseShellFolder(); 850 doDirectoryChanged(e); 851 } else if (s.equals("componentOrientation")) { 852 ComponentOrientation o = (ComponentOrientation)e.getNewValue(); 853 JFileChooser cc = (JFileChooser)e.getSource(); 854 if (o != e.getOldValue()) { 855 cc.applyComponentOrientation(o); 856 } 857 } else if (s.equals("ancestor")) { 858 if (e.getOldValue() == null && e.getNewValue() != null) { 859 // Ancestor was added, set initial focus 860 filenameTextField.selectAll(); 861 filenameTextField.requestFocus(); 862 } 863 } 864 } 865 }; 866 } 867 868 869 protected void removeControlButtons() { 870 getBottomPanel().remove(getButtonPanel()); 871 } 872 873 protected void addControlButtons() { 874 getBottomPanel().add(getButtonPanel()); 875 } 876 877 public void ensureFileIsVisible(JFileChooser fc, File f) { 878 filePane.ensureFileIsVisible(fc, f); 879 } 880 881 public void rescanCurrentDirectory(JFileChooser fc) { 882 filePane.rescanCurrentDirectory(); 883 } 884 885 public String getFileName() { 886 if(filenameTextField != null) { 887 return filenameTextField.getText(); 888 } else { 889 return null; 890 } 891 } 892 893 public void setFileName(String filename) { 894 if(filenameTextField != null) { 895 filenameTextField.setText(filename); 896 } 897 } 898 899 /** 900 * Property to remember whether a directory is currently selected in the UI. 901 * This is normally called by the UI on a selection event. 902 * 903 * @param directorySelected if a directory is currently selected. 904 * @since 1.4 905 */ 906 protected void setDirectorySelected(boolean directorySelected) { 907 super.setDirectorySelected(directorySelected); 908 JFileChooser chooser = getFileChooser(); 909 if(directorySelected) { 910 approveButton.setText(directoryOpenButtonText); 911 approveButton.setToolTipText(directoryOpenButtonToolTipText); 912 approveButton.setMnemonic(directoryOpenButtonMnemonic); 913 } else { 914 approveButton.setText(getApproveButtonText(chooser)); 915 approveButton.setToolTipText(getApproveButtonToolTipText(chooser)); 916 approveButton.setMnemonic(getApproveButtonMnemonic(chooser)); 917 } 918 } 919 920 public String getDirectoryName() { 921 // PENDING(jeff) - get the name from the directory combobox 922 return null; 923 } 924 925 public void setDirectoryName(String dirname) { 926 // PENDING(jeff) - set the name in the directory combobox 927 } 928 929 protected DirectoryComboBoxRenderer createDirectoryComboBoxRenderer(JFileChooser fc) { 930 return new DirectoryComboBoxRenderer(); 931 } 932 933 @SuppressWarnings("serial") // anonymous class 934 private static JButton createToolButton(Action a, Icon defaultIcon, String toolTipText, String accessibleName) { 935 final JButton result = new JButton(a); 936 937 result.setText(null); 938 result.setIcon(defaultIcon); 939 result.setToolTipText(toolTipText); 940 result.setRequestFocusEnabled(false); 941 result.putClientProperty(AccessibleContext.ACCESSIBLE_NAME_PROPERTY, accessibleName); 942 result.putClientProperty(WindowsLookAndFeel.HI_RES_DISABLED_ICON_CLIENT_KEY, Boolean.TRUE); 943 result.setAlignmentX(JComponent.LEFT_ALIGNMENT); 944 result.setAlignmentY(JComponent.CENTER_ALIGNMENT); 945 result.setMargin(shrinkwrap); 946 result.setFocusPainted(false); 947 948 result.setModel(new DefaultButtonModel() { 949 public void setPressed(boolean b) { 950 // Forbid keyboard actions if the button is not in rollover state 951 if (!b || isRollover()) { 952 super.setPressed(b); 953 } 954 } 955 956 public void setRollover(boolean b) { 957 if (b && !isRollover()) { 958 // Reset other buttons 959 for (Component component : result.getParent().getComponents()) { 960 if (component instanceof JButton && component != result) { 961 ((JButton) component).getModel().setRollover(false); 962 } 963 } 964 } 965 966 super.setRollover(b); 967 } 968 969 public void setSelected(boolean b) { 970 super.setSelected(b); 971 972 if (b) { 973 stateMask |= PRESSED | ARMED; 974 } else { 975 stateMask &= ~(PRESSED | ARMED); 976 } 977 } 978 }); 979 980 result.addFocusListener(new FocusAdapter() { 981 public void focusGained(FocusEvent e) { 982 result.getModel().setRollover(true); 983 } 984 985 public void focusLost(FocusEvent e) { 986 result.getModel().setRollover(false); 987 } 988 }); 989 990 return result; 991 } 992 993 // 994 // Renderer for DirectoryComboBox 995 // 996 @SuppressWarnings("serial") // Superclass is not serializable across versions 997 class DirectoryComboBoxRenderer extends DefaultListCellRenderer { 998 IndentIcon ii = new IndentIcon(); 999 public Component getListCellRendererComponent(JList<?> list, Object value, 1000 int index, boolean isSelected, 1001 boolean cellHasFocus) { 1002 1003 super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); 1004 1005 if (value == null) { 1006 setText(""); 1007 return this; 1008 } 1009 File directory = (File)value; 1010 setText(getFileChooser().getName(directory)); 1011 Icon icon = getFileChooser().getIcon(directory); 1012 ii.icon = icon; 1013 ii.depth = directoryComboBoxModel.getDepth(index); 1014 setIcon(ii); 1015 1016 return this; 1017 } 1018 } 1019 1020 static final int space = 10; 1021 class IndentIcon implements Icon { 1022 1023 Icon icon = null; 1024 int depth = 0; 1025 1026 public void paintIcon(Component c, Graphics g, int x, int y) { 1027 if (c.getComponentOrientation().isLeftToRight()) { 1028 icon.paintIcon(c, g, x+depth*space, y); 1029 } else { 1030 icon.paintIcon(c, g, x, y); 1031 } 1032 } 1033 1034 public int getIconWidth() { 1035 return icon.getIconWidth() + depth*space; 1036 } 1037 1038 public int getIconHeight() { 1039 return icon.getIconHeight(); 1040 } 1041 1042 } 1043 1044 // 1045 // DataModel for DirectoryComboxbox 1046 // 1047 protected DirectoryComboBoxModel createDirectoryComboBoxModel(JFileChooser fc) { 1048 return new DirectoryComboBoxModel(); 1049 } 1050 1051 /** 1052 * Data model for a type-face selection combo-box. 1053 */ 1054 @SuppressWarnings("serial") // Superclass is not serializable across versions 1055 protected class DirectoryComboBoxModel extends AbstractListModel<File> implements ComboBoxModel<File> { 1056 Vector<File> directories = new Vector<File>(); 1057 int[] depths = null; 1058 File selectedDirectory = null; 1059 JFileChooser chooser = getFileChooser(); 1060 FileSystemView fsv = chooser.getFileSystemView(); 1061 1062 public DirectoryComboBoxModel() { 1063 // Add the current directory to the model, and make it the 1064 // selectedDirectory 1065 File dir = getFileChooser().getCurrentDirectory(); 1066 if(dir != null) { 1067 addItem(dir); 1068 } 1069 } 1070 1071 /** 1072 * Adds the directory to the model and sets it to be selected, 1073 * additionally clears out the previous selected directory and 1074 * the paths leading up to it, if any. 1075 */ 1076 private void addItem(File directory) { 1077 1078 if(directory == null) { 1079 return; 1080 } 1081 1082 boolean useShellFolder = FilePane.usesShellFolder(chooser); 1083 1084 directories.clear(); 1085 1086 File[] baseFolders = (useShellFolder) 1087 ? (File[]) ShellFolder.get("fileChooserComboBoxFolders") 1088 : fsv.getRoots(); 1089 directories.addAll(Arrays.asList(baseFolders)); 1090 1091 // Get the canonical (full) path. This has the side 1092 // benefit of removing extraneous chars from the path, 1093 // for example /foo/bar/ becomes /foo/bar 1094 File canonical; 1095 try { 1096 canonical = directory.getCanonicalFile(); 1097 } catch (IOException e) { 1098 // Maybe drive is not ready. Can't abort here. 1099 canonical = directory; 1100 } 1101 1102 // create File instances of each directory leading up to the top 1103 try { 1104 File sf = useShellFolder ? ShellFolder.getShellFolder(canonical) 1105 : canonical; 1106 File f = sf; 1107 Vector<File> path = new Vector<File>(10); 1108 do { 1109 path.addElement(f); 1110 } while ((f = f.getParentFile()) != null); 1111 1112 int pathCount = path.size(); 1113 // Insert chain at appropriate place in vector 1114 for (int i = 0; i < pathCount; i++) { 1115 f = path.get(i); 1116 if (directories.contains(f)) { 1117 int topIndex = directories.indexOf(f); 1118 for (int j = i-1; j >= 0; j--) { 1119 directories.insertElementAt(path.get(j), topIndex+i-j); 1120 } 1121 break; 1122 } 1123 } 1124 calculateDepths(); 1125 setSelectedItem(sf); 1126 } catch (FileNotFoundException ex) { 1127 calculateDepths(); 1128 } 1129 } 1130 1131 private void calculateDepths() { 1132 depths = new int[directories.size()]; 1133 for (int i = 0; i < depths.length; i++) { 1134 File dir = directories.get(i); 1135 File parent = dir.getParentFile(); 1136 depths[i] = 0; 1137 if (parent != null) { 1138 for (int j = i-1; j >= 0; j--) { 1139 if (parent.equals(directories.get(j))) { 1140 depths[i] = depths[j] + 1; 1141 break; 1142 } 1143 } 1144 } 1145 } 1146 } 1147 1148 public int getDepth(int i) { 1149 return (depths != null && i >= 0 && i < depths.length) ? depths[i] : 0; 1150 } 1151 1152 public void setSelectedItem(Object selectedDirectory) { 1153 this.selectedDirectory = (File)selectedDirectory; 1154 fireContentsChanged(this, -1, -1); 1155 } 1156 1157 public Object getSelectedItem() { 1158 return selectedDirectory; 1159 } 1160 1161 public int getSize() { 1162 return directories.size(); 1163 } 1164 1165 public File getElementAt(int index) { 1166 return directories.elementAt(index); 1167 } 1168 } 1169 1170 // 1171 // Renderer for Types ComboBox 1172 // 1173 protected FilterComboBoxRenderer createFilterComboBoxRenderer() { 1174 return new FilterComboBoxRenderer(); 1175 } 1176 1177 /** 1178 * Render different type sizes and styles. 1179 */ 1180 @SuppressWarnings("serial") // Superclass is not serializable across versions 1181 public class FilterComboBoxRenderer extends DefaultListCellRenderer { 1182 public Component getListCellRendererComponent(JList<?> list, 1183 Object value, int index, boolean isSelected, 1184 boolean cellHasFocus) { 1185 1186 super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); 1187 1188 if (value != null && value instanceof FileFilter) { 1189 setText(((FileFilter)value).getDescription()); 1190 } 1191 1192 return this; 1193 } 1194 } 1195 1196 // 1197 // DataModel for Types Comboxbox 1198 // 1199 protected FilterComboBoxModel createFilterComboBoxModel() { 1200 return new FilterComboBoxModel(); 1262 if(index > getSize() - 1) { 1263 // This shouldn't happen. Try to recover gracefully. 1264 return getFileChooser().getFileFilter(); 1265 } 1266 if(filters != null) { 1267 return filters[index]; 1268 } else { 1269 return null; 1270 } 1271 } 1272 } 1273 1274 public void valueChanged(ListSelectionEvent e) { 1275 JFileChooser fc = getFileChooser(); 1276 File f = fc.getSelectedFile(); 1277 if (!e.getValueIsAdjusting() && f != null && !getFileChooser().isTraversable(f)) { 1278 setFileName(fileNameString(f)); 1279 } 1280 } 1281 1282 /** 1283 * Acts when DirectoryComboBox has changed the selected item. 1284 */ 1285 protected class DirectoryComboBoxAction implements ActionListener { 1286 1287 1288 1289 1290 public void actionPerformed(ActionEvent e) { 1291 File f = (File)directoryComboBox.getSelectedItem(); 1292 getFileChooser().setCurrentDirectory(f); 1293 } 1294 } 1295 1296 protected JButton getApproveButton(JFileChooser fc) { 1297 return approveButton; 1298 } 1299 1300 public FileView getFileView(JFileChooser fc) { 1301 return fileView; 1302 } 1303 1304 // *********************** 1305 // * FileView operations * 1306 // *********************** 1307 protected class WindowsFileView extends BasicFileView { 1308 /* FileView type descriptions */ 1309 1310 public Icon getIcon(File f) { 1311 Icon icon = getCachedIcon(f); 1312 if (icon != null) { 1313 return icon; 1314 } 1315 if (f != null) { 1316 icon = getFileChooser().getFileSystemView().getSystemIcon(f); 1317 } 1318 if (icon == null) { 1319 icon = super.getIcon(f); 1320 } 1321 cacheIcon(f, icon); 1322 return icon; 1323 } 1324 } 1325 } | 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 package com.sun.java.swing.plaf.windows; 26 27 import static com.sun.java.swing.plaf.windows.WindowsFileChooserUI.WindowsFileListUI.HOVER_CELL_PROPERTY; 28 import static com.sun.java.swing.plaf.windows.WindowsFileChooserUI.WindowsFileListUI.ITEM_SELECTED_BORDER_COLOR; 29 import javax.swing.*; 30 import javax.swing.border.*; 31 import javax.swing.filechooser.*; 32 import javax.swing.event.*; 33 import javax.swing.plaf.*; 34 import javax.swing.plaf.basic.*; 35 import java.awt.*; 36 import static java.awt.Color.WHITE; 37 import java.awt.event.*; 38 import java.awt.geom.Point2D; 39 import java.awt.image.BufferedImage; 40 import java.beans.*; 41 import java.io.File; 42 import static java.lang.Boolean.TRUE; 43 import java.util.*; 44 import sun.swing.*; 45 46 import javax.accessibility.*; 47 import static javax.swing.Action.NAME; 48 import static javax.swing.DefaultButtonModel.ARMED; 49 import static javax.swing.DefaultButtonModel.PRESSED; 50 import static javax.swing.SwingConstants.RIGHT; 51 import sun.awt.OSInfo; 52 import sun.awt.Win32GraphicsEnvironment; 53 import sun.swing.FilePane.ViewType; 54 55 /** 56 * Windows L&F implementation of a FileChooser. 57 * 58 * @author Jeff Dinkins 59 */ 60 public class WindowsFileChooserUI extends BasicFileChooserUI { 61 62 private WindowsAddressBar addressBar; 63 64 private FilterComboBoxModel filterComboBoxModel; 65 66 private JTextField filenameTextField; 67 private FilePane filePane; 68 private WindowsNavigationTree navTree; 69 70 private JButton approveButton; 71 private JButton cancelButton; 72 73 private JToolBar bottomToolbar; 74 private JPanel bottomPanel; 75 76 private final JPanel centerSplitPaneContainer = new JPanel(new BorderLayout()); 77 private final JSplitPane centerSplitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true) {{ 78 setUI(new BasicSplitPaneUI(){ 79 @Override 80 public BasicSplitPaneDivider createDefaultDivider() { 81 return new BasicSplitPaneDivider(this){ 82 83 @Override 84 public void paint(Graphics g) { 85 Color color = new Color(214, 229, 245); 86 if(OSInfo.getWindowsVersion().compareTo(OSInfo.WINDOWS_7)>0) 87 color = SystemColor.control; 88 89 g.setColor(WHITE); 90 g.fillRect(0, 0, getWidth(), getHeight()); 91 92 g.setColor(color); 93 int lineX = Math.max(getWidth() / 2, 0); 94 g.drawLine(lineX, 0, lineX, getHeight()); 95 } 96 }; 97 } 98 99 }); 100 }}; 101 102 private JComboBox<FileFilter> filterComboBox; 103 104 private static final Dimension hstrut10 = new Dimension(10, 1); 105 106 private static final Dimension vstrut4 = new Dimension(1, 4); 107 private static final Dimension vstrut6 = new Dimension(1, 6); 108 private static final Dimension vstrut8 = new Dimension(1, 8); 109 110 private static final Insets shrinkwrap = new Insets(0, 0, 0, 0); 111 112 // Preferred and Minimum sizes for the dialog box 113 private static int PREF_WIDTH = 425; 114 private static int PREF_HEIGHT = 245; 115 private static Dimension PREF_SIZE = new Dimension(PREF_WIDTH, PREF_HEIGHT); 116 117 private static int MIN_WIDTH = 425; 118 private static int MIN_HEIGHT = 245; 119 120 // Windows 10 values 121 private static int LIST_PREF_WIDTH = 638; 122 private static int LIST_PREF_HEIGHT = 590; 123 private static Dimension LIST_PREF_SIZE = new Dimension(LIST_PREF_WIDTH, LIST_PREF_HEIGHT); 124 125 private static final Insets UTILITY_TOOLBAR_BUTTON_MARGIN = new Insets(7, 11, 7, 11); 126 127 private int fileNameLabelMnemonic = 0; 128 private String fileNameLabelText = null; 129 private int folderNameLabelMnemonic = 0; 130 private String folderNameLabelText = null; 131 132 private int filesOfTypeLabelMnemonic = 0; 133 private String filesOfTypeLabelText = null; 134 135 private String upFolderToolTipText = null; 136 private String upFolderAccessibleName = null; 137 138 private String newFolderToolTipText = null; 139 private String newFolderAccessibleName = null; 140 141 private String viewMenuButtonToolTipText = null; 142 private String viewMenuButtonAccessibleName = null; 143 144 private BasicFileChooserUI.BasicFileView fileView = new WindowsFileView(); 145 146 private JLabel fileNameLabel; 147 148 private void populateFileNameLabel() { 149 if (getFileChooser().getFileSelectionMode() == JFileChooser.DIRECTORIES_ONLY) { 150 fileNameLabel.setText(folderNameLabelText); 151 fileNameLabel.setDisplayedMnemonic(folderNameLabelMnemonic); 152 } else { 153 fileNameLabel.setText(fileNameLabelText); 154 fileNameLabel.setDisplayedMnemonic(fileNameLabelMnemonic); 155 } 156 } 157 158 // 159 // ComponentUI Interface Implementation methods 160 // 161 public static ComponentUI createUI(JComponent c) { 162 return new WindowsFileChooserUI((JFileChooser) c); 163 } 164 165 public WindowsFileChooserUI(JFileChooser filechooser) { 166 super(filechooser); 167 } 168 169 public void installUI(JComponent c) { 170 super.installUI(c); 171 } 172 173 public void uninstallComponents(JFileChooser fc) { 174 fc.removeAll(); 175 } 176 private Deque<File> historyBack = new LinkedList<>(); 177 private Deque<File> historyForward = new LinkedList<>(); 178 private boolean isInBack; 179 private final Action backAction = new AbstractAction() { 180 { 181 putValue(NAME, "Back"); 182 setEnabled(false); 183 } 184 185 @Override 186 public void actionPerformed(ActionEvent e) { 187 File dir = historyBack.pop(); 188 historyForward.push(getFileChooser().getCurrentDirectory()); 189 190 isInBack = true; 191 getFileChooser().setCurrentDirectory(dir); 192 isInBack = false; 193 } 194 }; 195 private final Action forwardAction = new AbstractAction() { 196 197 { 198 putValue(NAME, "Forward"); 199 setEnabled(false); 200 } 201 202 @Override 203 public void actionPerformed(ActionEvent e) { 204 assert isEnabled(); 205 206 File dir = historyForward.peek(); 207 getFileChooser().setCurrentDirectory(dir); 208 } 209 }; 210 211 private Action getBackAction() { 212 return backAction; 213 } 214 215 private Action getForwardAction() { 216 return forwardAction; 217 } 218 219 private class WindowsFileChooserUIAccessor implements FilePane.FileChooserUIAccessor { 220 221 public JFileChooser getFileChooser() { 222 return WindowsFileChooserUI.this.getFileChooser(); 223 } 224 225 public BasicDirectoryModel getModel() { 226 return WindowsFileChooserUI.this.getModel(); 227 } 228 229 public JPanel createList() { 230 return WindowsFileChooserUI.this.createList(getFileChooser()); 231 } 232 233 public JPanel createDetailsView() { 234 return WindowsFileChooserUI.this.createDetailsView(getFileChooser()); 235 } 236 237 public boolean isDirectorySelected() { 238 return WindowsFileChooserUI.this.isDirectorySelected(); 239 } 240 241 public File getDirectory() { 242 return WindowsFileChooserUI.this.getDirectory(); 243 } 244 245 public Action getChangeToParentDirectoryAction() { 246 return WindowsFileChooserUI.this.getChangeToParentDirectoryAction(); 247 } 248 249 public Action getApproveSelectionAction() { 250 return WindowsFileChooserUI.this.getApproveSelectionAction(); 251 } 252 253 public Action getNewFolderAction() { 254 return WindowsFileChooserUI.this.getNewFolderAction(); 255 } 256 257 public MouseListener createDoubleClickListener(JList list) { 258 return WindowsFileChooserUI.this.createDoubleClickListener(getFileChooser(), 259 list); 260 } 261 262 public ListSelectionListener createListSelectionListener() { 263 return WindowsFileChooserUI.this.createListSelectionListener(getFileChooser()); 264 } 265 } 266 267 public void installComponents(JFileChooser fc) { 268 filePane = new FilePane(new WindowsFileChooserUIAccessor()); 269 fc.addPropertyChangeListener(filePane); 270 271 fc.setLayout(new BorderLayout()); 272 273 centerSplitPane.setBorder(null); 274 275 centerSplitPaneContainer.add(centerSplitPane, BorderLayout.CENTER); 276 fc.add(centerSplitPaneContainer, BorderLayout.CENTER); 277 278 if (!UIManager.getBoolean("FileChooser.noPlacesBar")) { 279 navTree = new WindowsNavigationTree(this); 280 navTreeScrollPane = new JScrollPane(navTree); 281 navTreeScrollPane.setBorder(null); 282 centerSplitPane.add(navTreeScrollPane, JSplitPane.LEFT); 283 fc.addPropertyChangeListener(navTree); 284 } 285 286 // ********************************* // 287 // **** Construct the top panel **** // 288 // ********************************* // 289 290 // Add the top panel to the fileChooser 291 fc.add(createTopContainer(fc), BorderLayout.NORTH); 292 293 // ************************************** // 294 // ******* Add the directory pane ******* // 295 // ************************************** // 296 JComponent accessory = fc.getAccessory(); 297 if (accessory != null) { 298 getAccessoryPanel().add(accessory); 299 } 300 filePane.setPreferredSize(LIST_PREF_SIZE); 301 centerSplitPane.add(filePane, JSplitPane.RIGHT); 302 // Add the bottom panel to file chooser 303 fc.add(getBottomPanel(), BorderLayout.SOUTH); 304 setupBottomPanel(fc); 305 } 306 307 private void setupBottomPanel(JFileChooser fc) { 308 getBottomPanel().setLayout(new BorderLayout()); 309 getBottomPanel().setBorder(new EmptyBorder(5, 5, 5, 5)); 310 getBottomPanel().setFont(Font.decode("Segoe UI-PLAIN-12.5")); 311 312 // labels 313 JPanel labelPanel = new JPanel(); 314 labelPanel.setOpaque(false); 315 labelPanel.setLayout(new GridBagLayout()); 316 317 GridBagConstraints cons = new GridBagConstraints(); 318 cons.insets = new Insets(0, 0, 0, 5); 319 cons.fill = GridBagConstraints.HORIZONTAL; 320 cons.weightx = 1; 321 cons.gridx = 0; 322 323 setupFileNameLabel(); 324 labelPanel.add(fileNameLabel, cons); 325 326 labelPanel.add(new JPanel(null), cons); 327 328 JLabel ftl = createFileTypeLabel(); 329 labelPanel.add(ftl, cons); 330 331 cons.gridx = 1; 332 cons.insets = new Insets(0, 0, 0, 2); 333 334 getBottomPanel().add(labelPanel); 335 336 setupFileNameTextField(); 337 338 if (fc.isMultiSelectionEnabled()) { 339 setFileName(fileNameString(fc.getSelectedFiles())); 340 } else { 341 setFileName(fileNameString(fc.getSelectedFile())); 342 } 343 344 labelPanel.add(filenameTextField, cons); 345 346 JPanel spacer = new JPanel(null); 347 spacer.setPreferredSize(new Dimension(0, 3)); 348 labelPanel.add(spacer, cons); 349 350 createFilterComboBox(fc, ftl); 351 labelPanel.add(filterComboBox, cons); 352 353 getBottomToolbar().setBorder(new EmptyBorder(20, 4, 4, 4)); 354 getBottomToolbar().setFloatable(false); 355 356 getBottomToolbar().add(Box.createHorizontalGlue()); 357 358 getBottomToolbar().add(new JPanel() { 359 360 { 361 GroupLayout buttonPanelLayout = new GroupLayout(this); 362 setLayout(buttonPanelLayout); 363 364 setupApproveButton(); 365 setupCancelButton(); 366 367 add(approveButton); 368 add(cancelButton); 369 370 buttonPanelLayout.setHorizontalGroup( 371 buttonPanelLayout.createSequentialGroup(). 372 addComponent(approveButton). 373 addPreferredGap(LayoutStyle.ComponentPlacement.RELATED). 374 addComponent(cancelButton) 375 ); 376 buttonPanelLayout.setVerticalGroup( 377 buttonPanelLayout.createParallelGroup(). 378 addComponent(approveButton). 379 addComponent(cancelButton) 380 ); 381 buttonPanelLayout.linkSize(approveButton, cancelButton); 382 } 383 384 private void setupApproveButton() { 385 approveButton = new JButton(getApproveButtonText(fc)); 386 approveButton.setMnemonic(getApproveButtonMnemonic(fc)); 387 approveButton.addActionListener(getApproveSelectionAction()); 388 approveButton.setToolTipText(getApproveButtonToolTipText(fc)); 389 approveButton.setMargin(new Insets(3, 15, 3, 15)); 390 approveButton.setFont(getFont()); 391 } 392 393 private Insets setupCancelButton() { 394 cancelButton = new JButton(cancelButtonText) { 395 public Dimension getMaximumSize() { 396 return approveButton.getPreferredSize().width > cancelButton.getPreferredSize().width 397 ? approveButton.getPreferredSize() : cancelButton.getPreferredSize(); 398 } 399 }; 400 401 Insets buttonMargin = approveButton.getMargin(); 402 cancelButton.setFont(getFont()); 403 cancelButton.setMargin(buttonMargin); 404 cancelButton.setToolTipText(cancelButtonToolTipText); 405 cancelButton.addActionListener(getCancelSelectionAction()); 406 return buttonMargin; 407 } 408 409 }); 410 411 if (fc.getControlButtonsAreShown()) { 412 addControlButtons(); 413 } 414 } 415 416 private void createFilterComboBox(JFileChooser fc, JLabel ftl) { 417 filterComboBoxModel = createFilterComboBoxModel(); 418 fc.addPropertyChangeListener(filterComboBoxModel); 419 filterComboBox = new JComboBox<FileFilter>(filterComboBoxModel); 420 ftl.setLabelFor(filterComboBox); 421 filterComboBox.setRenderer(createFilterComboBoxRenderer()); 422 423 filterComboBox.setFont(bottomPanel.getFont()); 424 } 425 426 private JLabel createFileTypeLabel() { 427 JLabel ftl = new JLabel(filesOfTypeLabelText); 428 ftl.setDisplayedMnemonic(filesOfTypeLabelMnemonic); 429 ftl.setHorizontalAlignment(RIGHT); 430 ftl.setFont(getBottomPanel().getFont()); 431 return ftl; 432 } 433 434 private void setupFileNameTextField() { 435 // file entry and filters 436 filenameTextField = new JTextField(35) { 437 public Dimension getMaximumSize() { 438 return new Dimension(Short.MAX_VALUE, super.getPreferredSize().height); 439 } 440 }; 441 442 fileNameLabel.setLabelFor(filenameTextField); 443 filenameTextField.addFocusListener( 444 new FocusAdapter() { 445 @Override 446 public void focusGained(FocusEvent e) { 447 if (!getFileChooser().isMultiSelectionEnabled()) { 448 filePane.clearSelection(); 449 } 450 } 451 }); 452 453 filenameTextField.setFont(bottomPanel.getFont()); 454 filenameTextField.setMargin(new Insets(2, 4, 2, 4)); 455 } 456 457 private void setupFileNameLabel() { 458 fileNameLabel = new JLabel(); 459 populateFileNameLabel(); 460 fileNameLabel.setHorizontalAlignment(RIGHT); 461 fileNameLabel.setAlignmentY(0); 462 fileNameLabel.setFont(getBottomPanel().getFont()); 463 } 464 465 private JPanel createTopContainer(JFileChooser fc) { 466 JPanel topContainer = new JPanel(new BorderLayout()); 467 468 JToolBar topPanel = new JToolBar() { 469 470 private boolean isWin7GradientBackground = false; 471 472 { 473 setOpaque(true); 474 475 /* switch (getType()) { 476 case WIN7: 477 isWin7GradientBackground 478 = Win32GraphicsEnvironment.isDWMCompositionEnabled(); 479 setBackground(new Color(185, 209, 234)); 480 // TODO: ablak unfókuszálásakor más szÃn kell 481 Win32GraphicsEnvironment.addDwmCompositionChangeListener(() -> { 482 isWin7GradientBackground 483 = Win32GraphicsEnvironment.isDWMCompositionEnabled(); 484 repaint(); 485 }); 486 487 //setBackground(new Color(230, 240, 250)); 488 break; 489 case WIN10:*/ 490 setBackground(WHITE);/* 491 break; 492 case CLASSIC: 493 setBackground(SystemColor.control); 494 break; 495 default: 496 throw new UnsupportedOperationException(); 497 }*/ 498 } 499 500 @Override 501 protected void paintComponent(Graphics g) { 502 if (!isWin7GradientBackground) { 503 super.paintComponent(g); 504 return; 505 } 506 507 Graphics2D g2d = (Graphics2D) g; 508 509 g2d.setPaint(new GradientPaint( 510 0, 0, 511 new Color(250, 252, 253), 512 0, getHeight() / 2, 513 new Color(230, 240, 250) 514 )); 515 g2d.fillRect(0, 0, getWidth(), getHeight()); 516 } 517 518 }; 519 topPanel.setBorder(new EmptyBorder(0, 4, 0, 0)); 520 topPanel.setFloatable(false); 521 topPanel.putClientProperty("JToolBar.isRollover", Boolean.TRUE); 522 topPanel.setMaximumSize(new Dimension(0, 12)); 523 topContainer.add(topPanel, BorderLayout.NORTH); 524 525 JToolBar utilityToolBar = new JToolBar() { 526 527 private boolean isWin7Background; 528 529 { 530 /* switch (getType()) { 531 case WIN7: 532 isWin7Background = true; 533 break; 534 case WIN10:*/ 535 setBackground(new Color(245, 246, 247));/* 536 break; 537 }*/ 538 } 539 540 @Override 541 protected void paintComponent(Graphics g) { 542 if (!isWin7Background) { 543 super.paintComponent(g); 544 return; 545 } 546 547 Graphics2D g2d = (Graphics2D) g; 548 549 g2d.setPaint(new LinearGradientPaint( 550 new Point2D.Double(0, 0), 551 new Point2D.Double(0, getHeight() / 2), 552 new float[]{0, 1}, 553 new Color[]{new Color(250, 252, 253), new Color(230, 240, 250)} 554 )); 555 g2d.fillRect(0, 0, getWidth(), getHeight() / 2); 556 557 g2d.setPaint(new LinearGradientPaint( 558 new Point2D.Double(0, 0), 559 new Point2D.Double(0, getHeight() / 2), 560 new float[]{0, 1}, 561 new Color[]{new Color(220, 230, 244), new Color(221, 233, 247)} 562 )); 563 g2d.fillRect(0, getHeight() / 2, getWidth(), getHeight() / 2); 564 } 565 566 @Override 567 protected void addImpl(Component comp, Object constraints, int index) { 568 super.addImpl(comp, constraints, index); 569 if(comp instanceof JButton) { 570 JButton btn = (JButton) comp; 571 btn.setBorder(new EmptyBorder(btn.getInsets())); 572 } 573 } 574 575 }; 576 utilityToolBar.setForeground(new Color(30, 57, 91)); 577 utilityToolBar.setFloatable(false); 578 utilityToolBar.setOpaque(true); 579 utilityToolBar.setBorder(new MatteBorder(0, 0, 1, 0, new Color(232, 233, 234))); 580 topContainer.add(utilityToolBar, BorderLayout.CENTER); 581 582 // Back Button 583 JButton backFolderButton = createToolButton(getBackAction(), 584 new ImageIcon(initBackArrowImage()), 585 "BACKBUTTON TOOLTIP", "BACKBUTTON ACCESSIBLENAME"); 586 topPanel.add(backFolderButton); 587 588 // Forward Button 589 JButton forwardFolderButton = createToolButton(getForwardAction(), 590 new ImageIcon(initForwardArrowImage()), 591 "FWBUTTON TOOLTIP", "FWBUTTON ACCESSIBLENAME"); 592 topPanel.add(forwardFolderButton); 593 594 // Up Button 595 JButton upFolderButton = createToolButton(getChangeToParentDirectoryAction(), 596 new ImageIcon(initUpArrowImage()), 597 upFolderToolTipText, upFolderAccessibleName); 598 topPanel.add(upFolderButton); 599 600 // Refresh Button 601 JButton refreshButton = new JButton(getUpdateAction()); 602 refreshButton.putClientProperty("WindowsButtonUI.displayAsInToolbar", TRUE); 603 refreshButton.putClientProperty("WindowsButtonUI.animateStateChange", TRUE); 604 refreshButton.setBackground(WHITE); 605 refreshButton.setPreferredSize(new Dimension(20, 22)); 606 refreshButton.setBorder(new MatteBorder(1, 0, 1, 1, 607 new Color(217, 217, 217))); 608 609 // AddressBar 610 addressBar = new WindowsAddressBar(fc); 611 612 JPanel addressBarContainer = new JPanel(new BorderLayout()); 613 addressBarContainer.setBorder(new EmptyBorder(5, 3, 7, 4)); 614 addressBarContainer.setOpaque(false); 615 addressBarContainer.add(newSpaceFiller(), BorderLayout.NORTH); 616 addressBarContainer.add(addressBar, BorderLayout.CENTER); 617 addressBarContainer.add(newSpaceFiller(), BorderLayout.SOUTH); 618 addressBarContainer.add(refreshButton, BorderLayout.EAST); 619 topPanel.add(addressBarContainer); 620 topPanel.add(Box.createRigidArea(hstrut10)); 621 622 // New Directory Button 623 if (!UIManager.getBoolean("FileChooser.readOnly")) { 624 JButton newFolderButton = new JButton(filePane.getNewFolderAction()); 625 newFolderButton.setForeground(utilityToolBar.getForeground()); 626 newFolderButton.setOpaque(false); 627 newFolderButton.setMargin(UTILITY_TOOLBAR_BUTTON_MARGIN); 628 newFolderButton.setToolTipText(newFolderToolTipText); 629 newFolderButton.getAccessibleContext().setAccessibleName(newFolderAccessibleName); 630 utilityToolBar.add(newFolderButton); 631 } 632 633 JPanel filler = new JPanel(); 634 filler.setOpaque(false); 635 utilityToolBar.add(filler); 636 637 JButton viewMenuButton = createDetailsButton(createViewTypePopupMenu()); 638 viewMenuButton.setForeground(utilityToolBar.getForeground()); 639 viewMenuButton.setMargin(UTILITY_TOOLBAR_BUTTON_MARGIN); 640 utilityToolBar.add(viewMenuButton); 641 642 initViewTypeMenuIcon(); 643 644 return topContainer; 645 } 646 647 private static JPanel newSpaceFiller() { 648 JPanel panel = new JPanel(new FlowLayout(FlowLayout.CENTER, 0, 0)); 649 panel.setOpaque(false); 650 return panel; 651 } 652 653 private void initViewTypeMenuIcon() { 654 // Create icon for viewMenuButton 655 BufferedImage image = new BufferedImage(viewMenuIcon.getIconWidth() + 7, viewMenuIcon.getIconHeight(), 656 BufferedImage.TYPE_INT_ARGB); 657 Graphics graphics = image.getGraphics(); 658 viewMenuIcon.paintIcon(filePane, graphics, 0, 0); 659 int x = image.getWidth() - 5; 660 int y = image.getHeight() / 2 - 1; 661 graphics.setColor(Color.BLACK); 662 graphics.fillPolygon(new int[]{x, x + 5, x + 2}, new int[]{y, y, y + 3}, 3); 663 } 664 665 private JPopupMenu createViewTypePopupMenu() { 666 // View button group 667 ButtonGroup viewButtonGroup = new ButtonGroup(); 668 669 // Popup Menu 670 final JPopupMenu viewTypePopupMenu = new JPopupMenu(); 671 672 Map<ViewType, JRadioButtonMenuItem> viewTypeMenuItems 673 = new EnumMap<>(ViewType.class); 674 675 for (ViewType viewType : ViewType.values()) { 676 final JRadioButtonMenuItem menuItem = new JRadioButtonMenuItem( 677 filePane.getViewTypeAction(viewType)); 678 menuItem.setSelected(filePane.getViewType() == viewType); 679 viewTypePopupMenu.add(menuItem); 680 viewButtonGroup.add(menuItem); 681 682 viewTypeMenuItems.put(viewType, menuItem); 683 } 684 685 filePane.addPropertyChangeListener(evt -> { 686 if ("viewType".equals(evt.getPropertyName())) { 687 viewTypeMenuItems.get(filePane.getViewType()).setSelected(true); 688 } 689 }); 690 691 return viewTypePopupMenu; 692 } 693 694 private JButton createDetailsButton(final JPopupMenu viewTypePopupMenu) { 695 // Details Button 696 final JButton viewMenuButton = createToolButton(new AbstractAction("Rendezés"){ 697 @Override 698 public void actionPerformed(ActionEvent e) { 699 } 700 }, null, viewMenuButtonToolTipText, 701 viewMenuButtonAccessibleName); 702 viewMenuButton.addActionListener(evt->{ 703 viewTypePopupMenu.show(viewMenuButton, 0, viewMenuButton.getHeight()); 704 }); 705 viewMenuButton.setOpaque(false); 706 viewMenuButton.setMargin(UTILITY_TOOLBAR_BUTTON_MARGIN); 707 viewTypePopupMenu.addPopupMenuListener(new PopupMenuListener() { 708 public void popupMenuWillBecomeVisible(PopupMenuEvent e) { 709 viewMenuButton.setSelected(true); 710 } 711 712 public void popupMenuWillBecomeInvisible(PopupMenuEvent e) { 713 SwingUtilities.invokeLater(new Runnable() { 714 public void run() { 715 viewMenuButton.setSelected(false); 716 } 717 }); 718 } 719 720 public void popupMenuCanceled(PopupMenuEvent e) { 721 } 722 }); 723 return viewMenuButton; 724 } 725 726 private JScrollPane navTreeScrollPane; 727 728 protected JToolBar getBottomToolbar() { 729 if (bottomToolbar == null) { 730 bottomToolbar = new JToolBar(); 731 } 732 return bottomToolbar; 733 } 734 735 protected JPanel getBottomPanel() { 736 if (bottomPanel == null) { 737 bottomPanel = new JPanel(); 738 } 739 return bottomPanel; 740 } 741 742 protected void installStrings(JFileChooser fc) { 743 super.installStrings(fc); 744 745 Locale l = fc.getLocale(); 746 747 fileNameLabelMnemonic = getMnemonic("FileChooser.fileNameLabelMnemonic", l); 748 fileNameLabelText = UIManager.getString("FileChooser.fileNameLabelText", l); 749 750 filesOfTypeLabelMnemonic = getMnemonic("FileChooser.filesOfTypeLabelMnemonic", l); 751 filesOfTypeLabelText = UIManager.getString("FileChooser.filesOfTypeLabelText", l); 752 753 upFolderToolTipText = UIManager.getString("FileChooser.upFolderToolTipText", l); 754 upFolderAccessibleName = UIManager.getString("FileChooser.upFolderAccessibleName", l); 755 756 newFolderToolTipText = UIManager.getString("FileChooser.newFolderToolTipText", l); 757 newFolderAccessibleName = UIManager.getString("FileChooser.newFolderAccessibleName", l); 758 759 viewMenuButtonToolTipText = UIManager.getString("FileChooser.viewMenuButtonToolTipText", l); 760 viewMenuButtonAccessibleName = UIManager.getString("FileChooser.viewMenuButtonAccessibleName", l); 761 } 762 763 private Integer getMnemonic(String key, Locale l) { 764 return SwingUtilities2.getUIDefaultsInt(key, l); 765 } 766 767 protected void installListeners(JFileChooser fc) { 768 super.installListeners(fc); 769 ActionMap actionMap = getActionMap(); 770 SwingUtilities.replaceUIActionMap(fc, actionMap); 771 772 fc.addPropertyChangeListener(JFileChooser.DIRECTORY_CHANGED_PROPERTY, evt -> { 773 if (!isInBack) { 774 if (!historyForward.isEmpty()) { 775 if (historyForward.peek().equals(evt.getNewValue())) { 776 historyForward.pop(); 777 } else { 778 historyForward.clear(); 779 } 780 } 781 782 if (evt.getOldValue() != null) { 783 historyBack.push((File) evt.getOldValue()); 784 } 785 } 786 787 getBackAction().setEnabled(!historyBack.isEmpty()); 788 getForwardAction().setEnabled(!historyForward.isEmpty()); 789 }); 790 } 791 792 protected ActionMap getActionMap() { 793 return createActionMap(); 794 } 795 796 protected ActionMap createActionMap() { 797 ActionMap map = new ActionMapUIResource(); 798 FilePane.addActionsToMap(map, filePane.getActions()); 799 FilePane.addActionsToMap(map, new Action[]{getChangeToParentDirectoryAction()}); 800 return map; 801 } 802 803 protected JPanel createList(JFileChooser fc) { 804 return filePane.createList(); 805 } 806 807 protected JPanel createDetailsView(JFileChooser fc) { 808 return filePane.createDetailsView(); 809 } 810 811 /** 812 * Creates a selection listener for the list of files and directories. 813 * 814 * @param fc a <code>JFileChooser</code> 815 * @return a <code>ListSelectionListener</code> 816 */ 817 public ListSelectionListener createListSelectionListener(JFileChooser fc) { 818 return super.createListSelectionListener(fc); 819 } 820 821 public void uninstallUI(JComponent c) { 822 // Remove listeners 823 c.removePropertyChangeListener(filterComboBoxModel); 824 c.removePropertyChangeListener(filePane); 825 if (navTree != null) { 826 c.removePropertyChangeListener(navTree); 827 } 828 cancelButton.removeActionListener(getCancelSelectionAction()); 829 approveButton.removeActionListener(getApproveSelectionAction()); 830 filenameTextField.removeActionListener(getApproveSelectionAction()); 831 832 if (filePane != null) { 833 filePane.uninstallUI(); 834 filePane = null; 835 } 836 837 super.uninstallUI(c); 838 } 839 840 /** 841 * Returns the preferred size of the specified <code>JFileChooser</code>. 842 * The preferred size is at least as large, in both height and width, as the 843 * preferred size recommended by the file chooser's layout manager. 844 * 845 * @param c a <code>JFileChooser</code> 846 * @return a <code>Dimension</code> specifying the preferred width and 847 * height of the file chooser 848 */ 849 @Override 850 public Dimension getPreferredSize(JComponent c) { 851 int prefWidth = PREF_SIZE.width; 852 Dimension d = c.getLayout().preferredLayoutSize(c); 853 if (d != null) { 854 return new Dimension(d.width < prefWidth ? prefWidth : d.width, 855 d.height < PREF_SIZE.height ? PREF_SIZE.height : d.height); 856 } else { 857 return new Dimension(prefWidth, PREF_SIZE.height); 858 } 859 } 860 861 /** 862 * Returns the minimum size of the <code>JFileChooser</code>. 863 * 864 * @param c a <code>JFileChooser</code> 865 * @return a <code>Dimension</code> specifying the minimum width and height 866 * of the file chooser 867 */ 868 @Override 869 public Dimension getMinimumSize(JComponent c) { 870 return new Dimension(MIN_WIDTH, MIN_HEIGHT); 871 } 872 873 /** 874 * Returns the maximum size of the <code>JFileChooser</code>. 875 * 876 * @param c a <code>JFileChooser</code> 877 * @return a <code>Dimension</code> specifying the maximum width and height 878 * of the file chooser 879 */ 880 @Override 881 public Dimension getMaximumSize(JComponent c) { 882 return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE); 883 } 884 885 private String fileNameString(File file) { 886 if (file == null) { 887 return null; 888 } else { 889 JFileChooser fc = getFileChooser(); 890 if ((fc.isDirectorySelectionEnabled() && !fc.isFileSelectionEnabled()) 891 || (fc.isDirectorySelectionEnabled() && fc.isFileSelectionEnabled() && fc.getFileSystemView().isFileSystemRoot(file))) { 892 return file.getPath(); 893 } else { 894 return file.getName(); 895 } 896 } 897 } 898 899 private String fileNameString(File[] files) { 900 StringBuffer buf = new StringBuffer(); 901 for (int i = 0; files != null && i < files.length; i++) { 902 if (i > 0) { 903 buf.append(" "); 904 } 905 if (files.length > 1) { 906 buf.append("\""); 907 } 908 buf.append(fileNameString(files[i])); 909 if (files.length > 1) { 910 buf.append("\""); 911 } 912 } 913 return buf.toString(); 914 } 915 916 /* The following methods are used by the PropertyChange Listener */ 917 private void doSelectedFileChanged(PropertyChangeEvent e) { 918 File f = (File) e.getNewValue(); 919 JFileChooser fc = getFileChooser(); 920 if (f != null 921 && ((fc.isFileSelectionEnabled() && !f.isDirectory()) 922 || (f.isDirectory() && fc.isDirectorySelectionEnabled()))) { 923 924 setFileName(fileNameString(f)); 925 } 926 } 927 928 private void doSelectedFilesChanged(PropertyChangeEvent e) { 929 File[] files = (File[]) e.getNewValue(); 930 JFileChooser fc = getFileChooser(); 931 if (files != null 932 && files.length > 0 933 && (files.length > 1 || fc.isDirectorySelectionEnabled() || !files[0].isDirectory())) { 934 setFileName(fileNameString(files)); 935 } 936 } 937 938 private void doDirectoryChanged(PropertyChangeEvent e) { 939 JFileChooser fc = getFileChooser(); 940 FileSystemView fsv = fc.getFileSystemView(); 941 942 clearIconCache(); 943 File currentDirectory = fc.getCurrentDirectory(); 944 if (currentDirectory != null) { 945 if (fc.isDirectorySelectionEnabled() && !fc.isFileSelectionEnabled()) { 946 if (fsv.isFileSystem(currentDirectory)) { 947 setFileName(currentDirectory.getPath()); 948 } else { 949 setFileName(null); 950 } 951 } 952 } 953 } 954 955 private void doFilterChanged(PropertyChangeEvent e) { 956 clearIconCache(); 957 } 958 959 private void doFileSelectionModeChanged(PropertyChangeEvent e) { 960 if (fileNameLabel != null) { 961 populateFileNameLabel(); 962 } 963 clearIconCache(); 964 965 JFileChooser fc = getFileChooser(); 966 File currentDirectory = fc.getCurrentDirectory(); 967 if (currentDirectory != null 968 && fc.isDirectorySelectionEnabled() 969 && !fc.isFileSelectionEnabled() 970 && fc.getFileSystemView().isFileSystem(currentDirectory)) { 971 972 setFileName(currentDirectory.getPath()); 973 } else { 974 setFileName(null); 975 } 976 } 977 978 private void doAccessoryChanged(PropertyChangeEvent e) { 979 if (getAccessoryPanel() != null) { 980 if (e.getOldValue() != null) { 981 getAccessoryPanel().remove((JComponent) e.getOldValue()); 982 } 983 JComponent accessory = (JComponent) e.getNewValue(); 984 if (accessory != null) { 985 getAccessoryPanel().add(accessory, BorderLayout.CENTER); 986 } 987 } 988 } 989 990 private void doApproveButtonTextChanged(PropertyChangeEvent e) { 991 JFileChooser chooser = getFileChooser(); 992 approveButton.setText(getApproveButtonText(chooser)); 993 approveButton.setToolTipText(getApproveButtonToolTipText(chooser)); 994 approveButton.setMnemonic(getApproveButtonMnemonic(chooser)); 995 } 996 997 private void doDialogTypeChanged(PropertyChangeEvent e) { 998 JFileChooser chooser = getFileChooser(); 999 approveButton.setText(getApproveButtonText(chooser)); 1000 approveButton.setToolTipText(getApproveButtonToolTipText(chooser)); 1001 approveButton.setMnemonic(getApproveButtonMnemonic(chooser)); 1002 } 1003 1004 private void doApproveButtonMnemonicChanged(PropertyChangeEvent e) { 1005 approveButton.setMnemonic(getApproveButtonMnemonic(getFileChooser())); 1006 } 1007 1008 private void doControlButtonsChanged(PropertyChangeEvent e) { 1009 if (getFileChooser().getControlButtonsAreShown()) { 1010 addControlButtons(); 1011 } else { 1012 removeControlButtons(); 1013 } 1014 } 1015 1016 /* 1017 * Listen for filechooser property changes, such as 1018 * the selected file changing, or the type of the dialog changing. 1019 */ 1020 public PropertyChangeListener createPropertyChangeListener(JFileChooser fc) { 1021 return (PropertyChangeEvent e) -> { 1022 String s = e.getPropertyName(); 1023 switch (s) { 1024 case JFileChooser.SELECTED_FILE_CHANGED_PROPERTY: 1025 doSelectedFileChanged(e); 1026 break; 1027 case JFileChooser.SELECTED_FILES_CHANGED_PROPERTY: 1028 doSelectedFilesChanged(e); 1029 break; 1030 case JFileChooser.DIRECTORY_CHANGED_PROPERTY: 1031 doDirectoryChanged(e); 1032 break; 1033 case JFileChooser.FILE_FILTER_CHANGED_PROPERTY: 1034 doFilterChanged(e); 1035 break; 1036 case JFileChooser.FILE_SELECTION_MODE_CHANGED_PROPERTY: 1037 doFileSelectionModeChanged(e); 1038 break; 1039 case JFileChooser.ACCESSORY_CHANGED_PROPERTY: 1040 doAccessoryChanged(e); 1041 break; 1042 case JFileChooser.APPROVE_BUTTON_TEXT_CHANGED_PROPERTY: 1043 case JFileChooser.APPROVE_BUTTON_TOOL_TIP_TEXT_CHANGED_PROPERTY: 1044 doApproveButtonTextChanged(e); 1045 break; 1046 case JFileChooser.DIALOG_TYPE_CHANGED_PROPERTY: 1047 doDialogTypeChanged(e); 1048 break; 1049 case JFileChooser.APPROVE_BUTTON_MNEMONIC_CHANGED_PROPERTY: 1050 doApproveButtonMnemonicChanged(e); 1051 break; 1052 case JFileChooser.CONTROL_BUTTONS_ARE_SHOWN_CHANGED_PROPERTY: 1053 doControlButtonsChanged(e); 1054 break; 1055 case "FileChooser.useShellFolder": 1056 doDirectoryChanged(e); 1057 break; 1058 case "componentOrientation": 1059 ComponentOrientation o = (ComponentOrientation) e.getNewValue(); 1060 JFileChooser cc = (JFileChooser) e.getSource(); 1061 if (o != e.getOldValue()) { 1062 cc.applyComponentOrientation(o); 1063 } 1064 break; 1065 case "ancestor": 1066 if (e.getOldValue() == null && e.getNewValue() != null) { 1067 // Ancestor was added, set initial focus 1068 filenameTextField.selectAll(); 1069 filenameTextField.requestFocus(); 1070 } 1071 break; 1072 } 1073 }; 1074 } 1075 1076 protected void removeControlButtons() { 1077 getBottomPanel().remove(getBottomToolbar()); 1078 } 1079 1080 protected void addControlButtons() { 1081 getBottomPanel().add(getBottomToolbar(), BorderLayout.SOUTH); 1082 } 1083 1084 public void ensureFileIsVisible(JFileChooser fc, File f) { 1085 filePane.ensureFileIsVisible(fc, f); 1086 } 1087 1088 public void rescanCurrentDirectory(JFileChooser fc) { 1089 filePane.rescanCurrentDirectory(); 1090 } 1091 1092 public String getFileName() { 1093 if (filenameTextField != null) { 1094 return filenameTextField.getText(); 1095 } else { 1096 return null; 1097 } 1098 } 1099 1100 @Override 1101 public void setFileName(String filename) { 1102 if (filenameTextField != null) { 1103 filenameTextField.setText(filename); 1104 } 1105 } 1106 1107 /** 1108 * Property to remember whether a directory is currently selected in the UI. 1109 * This is normally called by the UI on a selection event. 1110 * 1111 * @param directorySelected if a directory is currently selected. 1112 * @since 1.4 1113 */ 1114 @Override 1115 protected void setDirectorySelected(boolean directorySelected) { 1116 super.setDirectorySelected(directorySelected); 1117 JFileChooser chooser = getFileChooser(); 1118 if (directorySelected) { 1119 approveButton.setText(directoryOpenButtonText); 1120 approveButton.setToolTipText(directoryOpenButtonToolTipText); 1121 approveButton.setMnemonic(directoryOpenButtonMnemonic); 1122 } else { 1123 approveButton.setText(getApproveButtonText(chooser)); 1124 approveButton.setToolTipText(getApproveButtonToolTipText(chooser)); 1125 approveButton.setMnemonic(getApproveButtonMnemonic(chooser)); 1126 } 1127 } 1128 1129 @Override 1130 public Action getUpdateAction() { 1131 return new UpdateAction() { 1132 1133 { 1134 putValue(Action.SMALL_ICON, new ImageIcon(initRefreshImage())); 1135 } 1136 1137 @Override 1138 public void actionPerformed(ActionEvent e) { 1139 rescanCurrentDirectory(getFileChooser()); 1140 } 1141 1142 }; 1143 } 1144 1145 1146 public String getDirectoryName() { 1147 System.out.println(getFileChooser().getCurrentDirectory().getPath()); 1148 return getFileChooser().getCurrentDirectory().getPath(); 1149 } 1150 1151 public void setDirectoryName(String dirname) { 1152 // PENDING(jeff) - set the name in the directory combobox 1153 } 1154 1155 private static JButton createToolButton(Action a, Icon defaultIcon, String toolTipText, String accessibleName) { 1156 final JButton result = new JButton(a); 1157 1158 if (defaultIcon != null) { 1159 result.setText(null); 1160 result.setIcon(defaultIcon); 1161 } 1162 result.setToolTipText(toolTipText); 1163 result.setRequestFocusEnabled(false); 1164 result.putClientProperty(AccessibleContext.ACCESSIBLE_NAME_PROPERTY, accessibleName); 1165 result.putClientProperty(WindowsLookAndFeel.HI_RES_DISABLED_ICON_CLIENT_KEY, Boolean.TRUE); 1166 result.setAlignmentX(JComponent.LEFT_ALIGNMENT); 1167 result.setAlignmentY(JComponent.CENTER_ALIGNMENT); 1168 result.setMargin(new Insets(5, 5, 5, 5)); 1169 result.setOpaque(false); 1170 result.setFocusPainted(false); 1171 1172 result.setModel(new DefaultButtonModel() { 1173 @Override 1174 public void setPressed(boolean b) { 1175 // Forbid keyboard actions if the button is not in rollover state 1176 if (!b || isRollover()) { 1177 super.setPressed(b); 1178 } 1179 } 1180 1181 @Override 1182 public void setRollover(boolean b) { 1183 if (b && !isRollover()) { 1184 // Reset other buttons 1185 for (Component component : result.getParent().getComponents()) { 1186 if (component instanceof JButton && component != result) { 1187 ((JButton) component).getModel().setRollover(false); 1188 } 1189 } 1190 } 1191 1192 super.setRollover(b); 1193 } 1194 1195 public void setSelected(boolean b) { 1196 super.setSelected(b); 1197 1198 if (b) { 1199 stateMask |= PRESSED | ARMED; 1200 } else { 1201 stateMask &= ~(PRESSED | ARMED); 1202 } 1203 } 1204 }); 1205 result.getModel().setEnabled(a.isEnabled()); 1206 1207 result.addFocusListener(new FocusAdapter() { 1208 public void focusGained(FocusEvent e) { 1209 result.getModel().setRollover(true); 1210 } 1211 1212 public void focusLost(FocusEvent e) { 1213 result.getModel().setRollover(false); 1214 } 1215 }); 1216 1217 return result; 1218 } 1219 1220 // 1221 // Renderer for Types ComboBox 1222 // 1223 protected FilterComboBoxRenderer createFilterComboBoxRenderer() { 1224 return new FilterComboBoxRenderer(); 1225 } 1226 1227 /** 1228 * Render different type sizes and styles. 1229 */ 1230 public class FilterComboBoxRenderer extends DefaultListCellRenderer { 1231 public Component getListCellRendererComponent(JList<?> list, 1232 Object value, int index, boolean isSelected, 1233 boolean cellHasFocus) { 1234 1235 super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); 1236 1237 if (value != null && value instanceof FileFilter) { 1238 setText(((FileFilter)value).getDescription()); 1239 } 1240 1241 return this; 1242 } 1243 } 1244 1245 // 1246 // DataModel for Types Comboxbox 1247 // 1248 protected FilterComboBoxModel createFilterComboBoxModel() { 1249 return new FilterComboBoxModel(); 1311 if(index > getSize() - 1) { 1312 // This shouldn't happen. Try to recover gracefully. 1313 return getFileChooser().getFileFilter(); 1314 } 1315 if(filters != null) { 1316 return filters[index]; 1317 } else { 1318 return null; 1319 } 1320 } 1321 } 1322 1323 public void valueChanged(ListSelectionEvent e) { 1324 JFileChooser fc = getFileChooser(); 1325 File f = fc.getSelectedFile(); 1326 if (!e.getValueIsAdjusting() && f != null && !getFileChooser().isTraversable(f)) { 1327 setFileName(fileNameString(f)); 1328 } 1329 } 1330 1331 protected JButton getApproveButton(JFileChooser fc) { 1332 return approveButton; 1333 } 1334 1335 public FileView getFileView(JFileChooser fc) { 1336 return fileView; 1337 } 1338 1339 // *********************** 1340 // * FileView operations * 1341 // *********************** 1342 protected class WindowsFileView extends BasicFileView { 1343 /* FileView type descriptions */ 1344 1345 public Icon getIcon(File f) { 1346 Icon icon = getCachedIcon(f); 1347 if (icon != null) { 1348 return icon; 1349 } 1350 if (f != null) { 1351 icon = getFileChooser().getFileSystemView().getSystemIcon(f); 1352 } 1353 if (icon == null) { 1354 icon = super.getIcon(f); 1355 } 1356 cacheIcon(f, icon); 1357 return icon; 1358 } 1359 } 1360 1361 public static class WindowsFileListUI extends BasicListUI { 1362 1363 public static final Color ITEM_SELECTED_COLOR = new Color(204, 232, 255); 1364 public static final Color ITEM_HOVERED_COLOR = new Color(229, 243, 255); 1365 public static final Color ITEM_SELECTED_UNFOCUSED_COLOR = new Color(217, 217, 217); 1366 public static final Color ITEM_SELECTED_BORDER_COLOR = new Color(153, 209, 255); 1367 public static final Border ITEM_SELECTED_BORDER 1368 = new LineBorder(ITEM_SELECTED_BORDER_COLOR); 1369 1370 public static final String HOVER_CELL_PROPERTY = "WindowsFileListUI.hoverCell"; 1371 public static final String CELL_WIDTH_PROPERTY = "WindowsFileListUI.cellWidth"; 1372 1373 private Rectangle selectionRectangle; 1374 private final JFileChooser fileChooser; 1375 1376 public WindowsFileListUI(JFileChooser fileChooser) { 1377 this.fileChooser = fileChooser; 1378 } 1379 1380 @Override 1381 protected void installListeners() { 1382 super.installListeners(); 1383 1384 MouseAdapter mouseListener = new MouseAdapter() { 1385 @Override 1386 public void mouseExited(MouseEvent e) { 1387 setHoverCell(-1); 1388 } 1389 1390 @Override 1391 public void mouseMoved(MouseEvent e) { 1392 int hoverCell = list.locationToIndex(e.getPoint()); 1393 if (hoverCell != -1 && !list.getCellBounds( 1394 hoverCell, hoverCell).contains(e.getPoint())) { 1395 hoverCell = -1; 1396 } 1397 setHoverCell(hoverCell); 1398 } 1399 1400 private void setHoverCell(int hoverCell) { 1401 list.putClientProperty(HOVER_CELL_PROPERTY, hoverCell); 1402 list.repaint(); 1403 } 1404 private Point press; 1405 1406 @Override 1407 public void mousePressed(MouseEvent e) { 1408 press = e.getPoint(); 1409 } 1410 1411 @Override 1412 public void mouseDragged(MouseEvent e) { 1413 if (!fileChooser.isMultiSelectionEnabled()) { 1414 return; 1415 } 1416 1417 int x = press.x, y = press.y, w, h; 1418 1419 if (e.getX() < x) { 1420 w = x - e.getX(); 1421 x -= w; 1422 } else { 1423 w = e.getX() - x; 1424 } 1425 1426 if (e.getY() < y) { 1427 h = y - e.getY(); 1428 y -= h; 1429 } else { 1430 h = e.getY() - y; 1431 } 1432 1433 selectionRectangle = new Rectangle(x, y, w, h); 1434 1435 Set<Integer> toBeSelected = new HashSet<>(); 1436 for (int i = 0; i < list.getModel().getSize(); i++) { 1437 if (list.getCellBounds(i, i).intersects(selectionRectangle)) { 1438 toBeSelected.add(i); 1439 } 1440 } 1441 list.getSelectionModel().clearSelection(); 1442 for (Integer cell : toBeSelected) { 1443 list.getSelectionModel().addSelectionInterval(cell, cell); 1444 } 1445 list.repaint(); 1446 } 1447 1448 @Override 1449 public void mouseReleased(MouseEvent e) { 1450 selectionRectangle = null; 1451 list.repaint(); 1452 } 1453 1454 }; 1455 1456 list.addMouseListener(mouseListener); 1457 list.addMouseMotionListener(mouseListener); 1458 1459 list.addFocusListener(new FocusListener() { 1460 @Override 1461 public void focusGained(FocusEvent e) { 1462 list.repaint(); 1463 } 1464 1465 @Override 1466 public void focusLost(FocusEvent e) { 1467 list.repaint(); 1468 } 1469 1470 }); 1471 } 1472 1473 @Override 1474 protected void updateLayoutState() { 1475 super.updateLayoutState(); 1476 list.putClientProperty(CELL_WIDTH_PROPERTY, cellWidth); 1477 } 1478 1479 @Override 1480 public void paint(Graphics g, JComponent c) { 1481 super.paint(g, c); 1482 1483 if (selectionRectangle != null) { 1484 g.setColor(new Color(0, 102, 204, 85)); 1485 g.fillRect(selectionRectangle.x, selectionRectangle.y, 1486 selectionRectangle.width, selectionRectangle.height); 1487 1488 g.setColor(new Color(0, 128, 255, 204)); 1489 g.drawRect(selectionRectangle.x, selectionRectangle.y, 1490 selectionRectangle.width, selectionRectangle.height); 1491 } 1492 } 1493 1494 } 1495 1496 public static class WindowsFileTableUI extends BasicTableUI { 1497 1498 public static final Border ITEM_SELECTED_BORDER_LEFT_CELL 1499 = new CompoundBorder( 1500 new MatteBorder(1, 1, 1, 0, ITEM_SELECTED_BORDER_COLOR), 1501 new EmptyBorder(0, 0, 0, 1) 1502 ); 1503 1504 public static final Border ITEM_SELECTED_BORDER_MID_CELL 1505 = new CompoundBorder( 1506 new MatteBorder(1, 0, 1, 0, ITEM_SELECTED_BORDER_COLOR), 1507 new EmptyBorder(0, 1, 0, 1) 1508 ); 1509 1510 1511 public static final Border ITEM_SELECTED_BORDER_RIGHT_CELL 1512 = new CompoundBorder( 1513 new MatteBorder(1, 0, 1, 1, ITEM_SELECTED_BORDER_COLOR), 1514 new EmptyBorder(0, 1, 0, 0) 1515 ); 1516 1517 private Rectangle selectionRectangle; 1518 private final JFileChooser fileChooser; 1519 1520 public WindowsFileTableUI(JFileChooser fileChooser) { 1521 this.fileChooser = fileChooser; 1522 } 1523 1524 @Override 1525 protected void installListeners() { 1526 super.installListeners(); 1527 1528 MouseAdapter mouseListener = new MouseAdapter() { 1529 @Override 1530 public void mouseExited(MouseEvent e) { 1531 setHoverCell(-1); 1532 } 1533 1534 @Override 1535 public void mouseMoved(MouseEvent e) { 1536 int hoverRow = table.rowAtPoint(e.getPoint()); 1537 if (hoverRow != -1 && !containsIgnoreX( 1538 table.getCellRect(hoverRow, 0, true), 1539 e.getPoint())) { 1540 hoverRow = -1; // outside any row 1541 } 1542 setHoverCell(hoverRow); 1543 } 1544 1545 private boolean containsIgnoreX(Rectangle rect, Point p) { 1546 return p.y >= rect.y && p.y < rect.y + rect.height; 1547 } 1548 1549 private void setHoverCell(int hoverCell) { 1550 table.putClientProperty(HOVER_CELL_PROPERTY, hoverCell); 1551 table.repaint(); 1552 } 1553 1554 private Point press; 1555 1556 @Override 1557 public void mousePressed(MouseEvent e) { 1558 press = e.getPoint(); 1559 } 1560 1561 @Override 1562 public void mouseDragged(MouseEvent e) { 1563 if (!fileChooser.isMultiSelectionEnabled()) { 1564 return; 1565 } 1566 1567 int x = press.x, y = press.y, w, h; 1568 1569 if (e.getX() < x) { 1570 w = x - e.getX(); 1571 x -= w; 1572 } else { 1573 w = e.getX() - x; 1574 } 1575 1576 if (e.getY() < y) { 1577 h = y - e.getY(); 1578 y -= h; 1579 } else { 1580 h = e.getY() - y; 1581 } 1582 1583 Rectangle rect = selectionRectangle == null ? new Rectangle() 1584 : new Rectangle(selectionRectangle); 1585 selectionRectangle = new Rectangle(x, y, w, h); 1586 1587 Rectangle union = selectionRectangle.union(rect); 1588 union.x--; 1589 union.y--; 1590 union.width += 2; 1591 union.height += 2; 1592 table.paintImmediately(union); 1593 } 1594 1595 @Override 1596 public void mouseReleased(MouseEvent e) { 1597 selectionRectangle = null; 1598 table.repaint(); 1599 } 1600 1601 }; 1602 table.addMouseListener(mouseListener); 1603 table.addMouseMotionListener(mouseListener); 1604 1605 table.putClientProperty("FileChooser.supportsFileDrop", TRUE); 1606 table.putClientProperty("FileChooser.instance", fileChooser); 1607 table.putClientProperty("Table.noOutsideChecking", TRUE); 1608 table.putClientProperty("Table.showWholeRowAsDropTarget", TRUE); 1609 table.putClientProperty("BasicTableUI.cellWidthHack", Boolean.TRUE); 1610 1611 table.setDropMode(DropMode.ON); 1612 } 1613 1614 @Override 1615 public void paint(Graphics g, JComponent c) { 1616 super.paint(g, c); 1617 1618 if (selectionRectangle != null) { 1619 g.setColor(new Color(0, 102, 204, 85)); 1620 g.fillRect(selectionRectangle.x, selectionRectangle.y, 1621 selectionRectangle.width, selectionRectangle.height); 1622 1623 g.setColor(new Color(0, 128, 255, 204)); 1624 g.drawRect(selectionRectangle.x, selectionRectangle.y, 1625 selectionRectangle.width, selectionRectangle.height); 1626 } 1627 } 1628 } 1629 1630 private static Image initBackArrowImage() { 1631 BufferedImage img = new BufferedImage(12, 12, 6); 1632 img.setRGB(0, 4, 16777216); 1633 img.setRGB(0, 5, 1476395008); 1634 img.setRGB(0, 6, 1409286144); 1635 img.setRGB(0, 7, 16777216); 1636 img.setRGB(1, 3, 16777216); 1637 img.setRGB(1, 4, 1476395008); 1638 img.setRGB(1, 5, 2130706432); 1639 img.setRGB(1, 6, 2130706432); 1640 img.setRGB(1, 7, 1409286144); 1641 img.setRGB(1, 8, 16777216); 1642 img.setRGB(2, 2, 16777216); 1643 img.setRGB(2, 3, 1476395008); 1644 img.setRGB(2, 4, 2130706432); 1645 img.setRGB(2, 5, 2130706432); 1646 img.setRGB(2, 6, 2130706432); 1647 img.setRGB(2, 7, 2130706432); 1648 img.setRGB(2, 8, 1409286144); 1649 img.setRGB(2, 9, 16777216); 1650 img.setRGB(3, 1, 16777216); 1651 img.setRGB(3, 2, 1476395008); 1652 img.setRGB(3, 3, 2130706432); 1653 img.setRGB(3, 4, 1459617792); 1654 img.setRGB(3, 5, 2130706432); 1655 img.setRGB(3, 6, 2130706432); 1656 img.setRGB(3, 7, 1509949440); 1657 img.setRGB(3, 8, 2130706432); 1658 img.setRGB(3, 9, 1409286144); 1659 img.setRGB(3, 10, 16777216); 1660 img.setRGB(4, 0, 16777216); 1661 img.setRGB(4, 1, 1476395008); 1662 img.setRGB(4, 2, 2130706432); 1663 img.setRGB(4, 3, 1459617792); 1664 img.setRGB(4, 4, 16777216); 1665 img.setRGB(4, 5, 2130706432); 1666 img.setRGB(4, 6, 2130706432); 1667 img.setRGB(4, 7, 16777216); 1668 img.setRGB(4, 8, 1509949440); 1669 img.setRGB(4, 9, 2130706432); 1670 img.setRGB(4, 10, 1409286144); 1671 img.setRGB(4, 11, 16777216); 1672 img.setRGB(5, 0, 452984832); 1673 img.setRGB(5, 1, 2130706432); 1674 img.setRGB(5, 2, 1459617792); 1675 img.setRGB(5, 3, 16777216); 1676 img.setRGB(5, 5, 2130706432); 1677 img.setRGB(5, 6, 2130706432); 1678 img.setRGB(5, 8, 16777216); 1679 img.setRGB(5, 9, 1509949440); 1680 img.setRGB(5, 10, 2130706432); 1681 img.setRGB(5, 11, 402653184); 1682 img.setRGB(6, 1, 469762048); 1683 img.setRGB(6, 2, 16777216); 1684 img.setRGB(6, 5, 2130706432); 1685 img.setRGB(6, 6, 2130706432); 1686 img.setRGB(6, 9, 16777216); 1687 img.setRGB(6, 10, 419430400); 1688 img.setRGB(7, 5, 2130706432); 1689 img.setRGB(7, 6, 2130706432); 1690 img.setRGB(8, 5, 2130706432); 1691 img.setRGB(8, 6, 2130706432); 1692 img.setRGB(9, 5, 2130706432); 1693 img.setRGB(9, 6, 2130706432); 1694 img.setRGB(10, 5, 2130706432); 1695 img.setRGB(10, 6, 2130706432); 1696 img.setRGB(11, 5, 2130706432); 1697 img.setRGB(11, 6, 2130706432); 1698 return img; 1699 } 1700 1701 private static Image initForwardArrowImage() { 1702 BufferedImage img = new BufferedImage(12, 12, 6); 1703 img.setRGB(0, 5, 2130706432); 1704 img.setRGB(0, 6, 2130706432); 1705 img.setRGB(1, 5, 2130706432); 1706 img.setRGB(1, 6, 2130706432); 1707 img.setRGB(2, 5, 2130706432); 1708 img.setRGB(2, 6, 2130706432); 1709 img.setRGB(3, 5, 2130706432); 1710 img.setRGB(3, 6, 2130706432); 1711 img.setRGB(4, 5, 2130706432); 1712 img.setRGB(4, 6, 2130706432); 1713 img.setRGB(5, 1, 452984832); 1714 img.setRGB(5, 2, 16777216); 1715 img.setRGB(5, 5, 2130706432); 1716 img.setRGB(5, 6, 2130706432); 1717 img.setRGB(5, 9, 16777216); 1718 img.setRGB(5, 10, 419430400); 1719 img.setRGB(6, 0, 452984832); 1720 img.setRGB(6, 1, 2130706432); 1721 img.setRGB(6, 2, 1442840576); 1722 img.setRGB(6, 3, 16777216); 1723 img.setRGB(6, 5, 2130706432); 1724 img.setRGB(6, 6, 2130706432); 1725 img.setRGB(6, 8, 16777216); 1726 img.setRGB(6, 9, 1509949440); 1727 img.setRGB(6, 10, 2130706432); 1728 img.setRGB(6, 11, 402653184); 1729 img.setRGB(7, 0, 16777216); 1730 img.setRGB(7, 1, 1476395008); 1731 img.setRGB(7, 2, 2130706432); 1732 img.setRGB(7, 3, 1442840576); 1733 img.setRGB(7, 4, 16777216); 1734 img.setRGB(7, 5, 2130706432); 1735 img.setRGB(7, 6, 2130706432); 1736 img.setRGB(7, 7, 16777216); 1737 img.setRGB(7, 8, 1509949440); 1738 img.setRGB(7, 9, 2130706432); 1739 img.setRGB(7, 10, 1392508928); 1740 img.setRGB(7, 11, 16777216); 1741 img.setRGB(8, 1, 16777216); 1742 img.setRGB(8, 2, 1476395008); 1743 img.setRGB(8, 3, 2130706432); 1744 img.setRGB(8, 4, 1442840576); 1745 img.setRGB(8, 5, 2130706432); 1746 img.setRGB(8, 6, 2130706432); 1747 img.setRGB(8, 7, 1509949440); 1748 img.setRGB(8, 8, 2130706432); 1749 img.setRGB(8, 9, 1409286144); 1750 img.setRGB(8, 10, 16777216); 1751 img.setRGB(9, 2, 16777216); 1752 img.setRGB(9, 3, 1476395008); 1753 img.setRGB(9, 4, 2130706432); 1754 img.setRGB(9, 5, 2130706432); 1755 img.setRGB(9, 6, 2130706432); 1756 img.setRGB(9, 7, 2130706432); 1757 img.setRGB(9, 8, 1409286144); 1758 img.setRGB(9, 9, 16777216); 1759 img.setRGB(10, 3, 16777216); 1760 img.setRGB(10, 4, 1476395008); 1761 img.setRGB(10, 5, 2130706432); 1762 img.setRGB(10, 6, 2130706432); 1763 img.setRGB(10, 7, 1409286144); 1764 img.setRGB(10, 8, 16777216); 1765 img.setRGB(11, 4, 16777216); 1766 img.setRGB(11, 5, 1476395008); 1767 img.setRGB(11, 6, 1409286144); 1768 img.setRGB(11, 7, 16777216); 1769 return img; 1770 } 1771 1772 private static Image initUpArrowImage() { 1773 BufferedImage img = new BufferedImage(12, 13, 6); 1774 img.setRGB(0, 5, 167772160); 1775 img.setRGB(0, 6, 1325400064); 1776 img.setRGB(0, 7, 117440512); 1777 img.setRGB(1, 4, 167772160); 1778 img.setRGB(1, 5, 1778384896); 1779 img.setRGB(1, 6, 2130706432); 1780 img.setRGB(1, 7, 1308622848); 1781 img.setRGB(2, 3, 167772160); 1782 img.setRGB(2, 4, 1778384896); 1783 img.setRGB(2, 5, 2130706432); 1784 img.setRGB(2, 6, 1778384896); 1785 img.setRGB(2, 7, 167772160); 1786 img.setRGB(3, 2, 167772160); 1787 img.setRGB(3, 3, 1778384896); 1788 img.setRGB(3, 4, 2130706432); 1789 img.setRGB(3, 5, 1778384896); 1790 img.setRGB(3, 6, 167772160); 1791 img.setRGB(4, 1, 167772160); 1792 img.setRGB(4, 2, 1778384896); 1793 img.setRGB(4, 3, 2130706432); 1794 img.setRGB(4, 4, 1778384896); 1795 img.setRGB(4, 5, 167772160); 1796 img.setRGB(5, 0, 167772160); 1797 img.setRGB(5, 1, 1778384896); 1798 img.setRGB(5, 2, 2130706432); 1799 img.setRGB(5, 3, 2130706432); 1800 img.setRGB(5, 4, 2130706432); 1801 img.setRGB(5, 5, 2130706432); 1802 img.setRGB(5, 6, 2130706432); 1803 img.setRGB(5, 7, 2130706432); 1804 img.setRGB(5, 8, 2130706432); 1805 img.setRGB(5, 9, 2130706432); 1806 img.setRGB(5, 10, 2130706432); 1807 img.setRGB(5, 11, 2130706432); 1808 img.setRGB(5, 12, 2130706432); 1809 img.setRGB(6, 0, 167772160); 1810 img.setRGB(6, 1, 1778384896); 1811 img.setRGB(6, 2, 2130706432); 1812 img.setRGB(6, 3, 2130706432); 1813 img.setRGB(6, 4, 2130706432); 1814 img.setRGB(6, 5, 2130706432); 1815 img.setRGB(6, 6, 2130706432); 1816 img.setRGB(6, 7, 2130706432); 1817 img.setRGB(6, 8, 2130706432); 1818 img.setRGB(6, 9, 2130706432); 1819 img.setRGB(6, 10, 2130706432); 1820 img.setRGB(6, 11, 2130706432); 1821 img.setRGB(6, 12, 2130706432); 1822 img.setRGB(7, 1, 184549376); 1823 img.setRGB(7, 2, 1778384896); 1824 img.setRGB(7, 3, 2130706432); 1825 img.setRGB(7, 4, 1761607680); 1826 img.setRGB(7, 5, 167772160); 1827 img.setRGB(8, 2, 184549376); 1828 img.setRGB(8, 3, 1778384896); 1829 img.setRGB(8, 4, 2130706432); 1830 img.setRGB(8, 5, 1744830464); 1831 img.setRGB(8, 6, 167772160); 1832 img.setRGB(9, 3, 184549376); 1833 img.setRGB(9, 4, 1795162112); 1834 img.setRGB(9, 5, 2130706432); 1835 img.setRGB(9, 6, 1728053248); 1836 img.setRGB(9, 7, 150994944); 1837 img.setRGB(10, 4, 201326592); 1838 img.setRGB(10, 5, 1795162112); 1839 img.setRGB(10, 6, 2130706432); 1840 img.setRGB(10, 7, 1258291200); 1841 img.setRGB(11, 5, 201326592); 1842 img.setRGB(11, 6, 1308622848); 1843 img.setRGB(11, 7, 83886080); 1844 return img; 1845 } 1846 1847 private static Image initRefreshImage() { 1848 BufferedImage img = new BufferedImage(10, 11, 6); 1849 img.setRGB(0, 3, 385875968); 1850 img.setRGB(0, 4, 1325400064); 1851 img.setRGB(0, 5, 1778384896); 1852 img.setRGB(0, 6, 1761607680); 1853 img.setRGB(0, 7, 1308622848); 1854 img.setRGB(0, 8, 369098752); 1855 img.setRGB(1, 0, 2130706432); 1856 img.setRGB(1, 1, 989855744); 1857 img.setRGB(1, 2, 805306368); 1858 img.setRGB(1, 3, 2097152000); 1859 img.setRGB(1, 4, 2130706432); 1860 img.setRGB(1, 5, 2013265920); 1861 img.setRGB(1, 6, 1996488704); 1862 img.setRGB(1, 7, 2130706432); 1863 img.setRGB(1, 8, 2080374784); 1864 img.setRGB(1, 9, 788529152); 1865 img.setRGB(2, 0, 2130706432); 1866 img.setRGB(2, 1, 1191182336); 1867 img.setRGB(2, 2, 2097152000); 1868 img.setRGB(2, 3, 1962934272); 1869 img.setRGB(2, 4, 620756992); 1870 img.setRGB(2, 7, 603979776); 1871 img.setRGB(2, 8, 1979711488); 1872 img.setRGB(2, 9, 2097152000); 1873 img.setRGB(2, 10, 352321536); 1874 img.setRGB(3, 0, 2130706432); 1875 img.setRGB(3, 1, 1660944384); 1876 img.setRGB(3, 2, 2130706432); 1877 img.setRGB(3, 3, 637534208); 1878 img.setRGB(3, 8, 687865856); 1879 img.setRGB(3, 9, 2130706432); 1880 img.setRGB(3, 10, 1308622848); 1881 img.setRGB(4, 0, 2130706432); 1882 img.setRGB(4, 1, 2097152000); 1883 img.setRGB(4, 2, 1996488704); 1884 img.setRGB(4, 3, 1006632960); 1885 img.setRGB(4, 4, 1006632960); 1886 img.setRGB(4, 9, 1996488704); 1887 img.setRGB(4, 10, 1761607680); 1888 img.setRGB(5, 0, 2130706432); 1889 img.setRGB(5, 1, 2130706432); 1890 img.setRGB(5, 2, 2130706432); 1891 img.setRGB(5, 3, 2130706432); 1892 img.setRGB(5, 4, 2130706432); 1893 img.setRGB(5, 9, 1996488704); 1894 img.setRGB(5, 10, 1761607680); 1895 img.setRGB(6, 8, 687865856); 1896 img.setRGB(6, 9, 2130706432); 1897 img.setRGB(6, 10, 1308622848); 1898 img.setRGB(7, 3, 587202560); 1899 img.setRGB(7, 4, 603979776); 1900 img.setRGB(7, 7, 603979776); 1901 img.setRGB(7, 8, 1979711488); 1902 img.setRGB(7, 9, 2097152000); 1903 img.setRGB(7, 10, 369098752); 1904 img.setRGB(8, 2, 150994944); 1905 img.setRGB(8, 3, 1996488704); 1906 img.setRGB(8, 4, 2130706432); 1907 img.setRGB(8, 5, 1996488704); 1908 img.setRGB(8, 6, 1996488704); 1909 img.setRGB(8, 7, 2130706432); 1910 img.setRGB(8, 8, 2080374784); 1911 img.setRGB(8, 9, 788529152); 1912 img.setRGB(9, 3, 369098752); 1913 img.setRGB(9, 4, 1325400064); 1914 img.setRGB(9, 5, 1778384896); 1915 img.setRGB(9, 6, 1761607680); 1916 img.setRGB(9, 7, 1308622848); 1917 img.setRGB(9, 8, 369098752); 1918 return img; 1919 } 1920 } |