1 /*
2 * Copyright (c) 2003, 2009, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
41 import javax.swing.event.*;
42 import javax.swing.filechooser.*;
43 import javax.swing.plaf.basic.*;
44 import javax.swing.table.*;
45 import javax.swing.text.*;
46
47 import sun.awt.shell.*;
48
49 /**
50 * <b>WARNING:</b> This class is an implementation detail and is only
51 * public so that it can be used by two packages. You should NOT consider
52 * this public API.
53 * <p>
54 * This component is intended to be used in a subclass of
55 * javax.swing.plaf.basic.BasicFileChooserUI. It realies heavily on the
56 * implementation of BasicFileChooserUI, and is intended to be API compatible
57 * with earlier implementations of MetalFileChooserUI and WindowsFileChooserUI.
58 *
59 * @author Leif Samuelsson
60 */
61 public class FilePane extends JPanel implements PropertyChangeListener {
62 // Constants for actions. These are used for the actions' ACTION_COMMAND_KEY
63 // and as keys in the action maps for FilePane and the corresponding UI classes
64
65 public final static String ACTION_APPROVE_SELECTION = "approveSelection";
66 public final static String ACTION_CANCEL = "cancelSelection";
67 public final static String ACTION_EDIT_FILE_NAME = "editFileName";
68 public final static String ACTION_REFRESH = "refresh";
69 public final static String ACTION_CHANGE_TO_PARENT_DIRECTORY = "Go Up";
70 public final static String ACTION_NEW_FOLDER = "New Folder";
71 public final static String ACTION_VIEW_LIST = "viewTypeList";
72 public final static String ACTION_VIEW_DETAILS = "viewTypeDetails";
73
74 private Action[] actions;
75
76 // "enums" for setViewType()
77 public static final int VIEWTYPE_LIST = 0;
78 public static final int VIEWTYPE_DETAILS = 1;
79 private static final int VIEWTYPE_COUNT = 2;
80
374 getCurrentKeyboardFocusManager().getPermanentFocusOwner();
375
376 isFocusOwner = owner == detailsTable || owner == list;
377
378 remove(currentViewPanel);
379 }
380
381 currentViewPanel = viewPanels[viewType];
382 add(currentViewPanel, BorderLayout.CENTER);
383
384 if (isFocusOwner && newFocusOwner != null) {
385 newFocusOwner.requestFocusInWindow();
386 }
387
388 revalidate();
389 repaint();
390 updateViewMenu();
391 firePropertyChange("viewType", oldValue, viewType);
392 }
393
394 class ViewTypeAction extends AbstractAction {
395 private int viewType;
396
397 ViewTypeAction(int viewType) {
398 super(viewTypeActionNames[viewType]);
399 this.viewType = viewType;
400
401 String cmd;
402 switch (viewType) {
403 case VIEWTYPE_LIST: cmd = ACTION_VIEW_LIST; break;
404 case VIEWTYPE_DETAILS: cmd = ACTION_VIEW_DETAILS; break;
405 default: cmd = (String)getValue(Action.NAME);
406 }
407 putValue(Action.ACTION_COMMAND_KEY, cmd);
408 }
409
410 public void actionPerformed(ActionEvent e) {
411 setViewType(viewType);
412 }
413 }
453 megaByteString = UIManager.getString("FileChooser.fileSizeMegaBytes", l);
454 gigaByteString = UIManager.getString("FileChooser.fileSizeGigaBytes", l);
455 fullRowSelection = UIManager.getBoolean("FileView.fullRowSelection");
456
457 filesListAccessibleName = UIManager.getString("FileChooser.filesListAccessibleName", l);
458 filesDetailsAccessibleName = UIManager.getString("FileChooser.filesDetailsAccessibleName", l);
459
460 renameErrorTitleText = UIManager.getString("FileChooser.renameErrorTitleText", l);
461 renameErrorText = UIManager.getString("FileChooser.renameErrorText", l);
462 renameErrorFileExistsText = UIManager.getString("FileChooser.renameErrorFileExistsText", l);
463 }
464
465 /**
466 * Fetches the command list for the FilePane. These commands
467 * are useful for binding to events, such as in a keymap.
468 *
469 * @return the command list
470 */
471 public Action[] getActions() {
472 if (actions == null) {
473 class FilePaneAction extends AbstractAction {
474 FilePaneAction(String name) {
475 this(name, name);
476 }
477
478 FilePaneAction(String name, String cmd) {
479 super(name);
480 putValue(Action.ACTION_COMMAND_KEY, cmd);
481 }
482
483 public void actionPerformed(ActionEvent e) {
484 String cmd = (String)getValue(Action.ACTION_COMMAND_KEY);
485
486 if (cmd == ACTION_CANCEL) {
487 if (editFile != null) {
488 cancelEdit();
489 } else {
490 getFileChooser().cancelSelection();
491 }
492 } else if (cmd == ACTION_EDIT_FILE_NAME) {
560 if (cmd == null) {
561 cmd = (String)a.getValue(Action.NAME);
562 }
563 map.put(cmd, a);
564 }
565 }
566 }
567
568
569 private void updateListRowCount(JList list) {
570 if (smallIconsView) {
571 list.setVisibleRowCount(getModel().getSize() / 3);
572 } else {
573 list.setVisibleRowCount(-1);
574 }
575 }
576
577 public JPanel createList() {
578 JPanel p = new JPanel(new BorderLayout());
579 final JFileChooser fileChooser = getFileChooser();
580 final JList<Object> list = new JList<Object>() {
581 public int getNextMatch(String prefix, int startIndex, Position.Bias bias) {
582 ListModel model = getModel();
583 int max = model.getSize();
584 if (prefix == null || startIndex < 0 || startIndex >= max) {
585 throw new IllegalArgumentException();
586 }
587 // start search from the next element before/after the selected element
588 boolean backwards = (bias == Position.Bias.Backward);
589 for (int i = startIndex; backwards ? i >= 0 : i < max; i += (backwards ? -1 : 1)) {
590 String filename = fileChooser.getName((File)model.getElementAt(i));
591 if (filename.regionMatches(true, 0, prefix, 0, prefix.length())) {
592 return i;
593 }
594 }
595 return -1;
596 }
597 };
598 list.setCellRenderer(new FileRenderer());
599 list.setLayoutOrientation(JList.VERTICAL_WRAP);
634 list.addListSelectionListener(createListSelectionListener());
635 list.addMouseListener(getMouseHandler());
636
637 JScrollPane scrollpane = new JScrollPane(list);
638 if (listViewBackground != null) {
639 list.setBackground(listViewBackground);
640 }
641 if (listViewBorder != null) {
642 scrollpane.setBorder(listViewBorder);
643 }
644
645 list.putClientProperty(AccessibleContext.ACCESSIBLE_NAME_PROPERTY, filesListAccessibleName);
646
647 p.add(scrollpane, BorderLayout.CENTER);
648 return p;
649 }
650
651 /**
652 * This model allows for sorting JList
653 */
654 private class SortableListModel extends AbstractListModel<Object>
655 implements TableModelListener, RowSorterListener {
656
657 public SortableListModel() {
658 getDetailsTableModel().addTableModelListener(this);
659 getRowSorter().addRowSorterListener(this);
660 }
661
662 public int getSize() {
663 return getModel().getSize();
664 }
665
666 public Object getElementAt(int index) {
667 // JList doesn't support RowSorter so far, so we put it into the list model
668 return getModel().getElementAt(getRowSorter().convertRowIndexToModel(index));
669 }
670
671 public void tableChanged(TableModelEvent e) {
672 fireContentsChanged(this, 0, getSize());
673 }
674
675 public void sorterChanged(RowSorterEvent e) {
676 fireContentsChanged(this, 0, getSize());
677 }
678 }
679
680 private DetailsTableModel getDetailsTableModel() {
681 if(detailsTableModel == null) {
682 detailsTableModel = new DetailsTableModel(getFileChooser());
683 }
684 return detailsTableModel;
685 }
686
687 class DetailsTableModel extends AbstractTableModel implements ListDataListener {
688 JFileChooser chooser;
689 BasicDirectoryModel directoryModel;
690
691 ShellFolderColumnInfo[] columns;
692 int[] columnMap;
693
694 DetailsTableModel(JFileChooser fc) {
695 this.chooser = fc;
696 directoryModel = getModel();
697 directoryModel.addListDataListener(this);
698
699 updateColumnInfo();
700 }
701
702 void updateColumnInfo() {
703 File dir = chooser.getCurrentDirectory();
704 if (dir != null && usesShellFolder(chooser)) {
705 try {
706 dir = ShellFolder.getShellFolder(dir);
986 return comparator.compare(
987 getDetailsTableModel().getFileColumnValue(f1, column),
988 getDetailsTableModel().getFileColumnValue(f2, column)
989 );
990 }
991 // For this column we need to pass the file itself (not a
992 // column value) to the comparator
993 return comparator.compare(f1, f2);
994 }
995 }
996
997 private DetailsTableCellEditor tableCellEditor;
998
999 private DetailsTableCellEditor getDetailsTableCellEditor() {
1000 if (tableCellEditor == null) {
1001 tableCellEditor = new DetailsTableCellEditor(new JTextField());
1002 }
1003 return tableCellEditor;
1004 }
1005
1006 private class DetailsTableCellEditor extends DefaultCellEditor {
1007 private final JTextField tf;
1008
1009 public DetailsTableCellEditor(JTextField tf) {
1010 super(tf);
1011 this.tf = tf;
1012 tf.setName("Table.editor");
1013 tf.addFocusListener(editorFocusListener);
1014 }
1015
1016 public Component getTableCellEditorComponent(JTable table, Object value,
1017 boolean isSelected, int row, int column) {
1018 Component comp = super.getTableCellEditorComponent(table, value,
1019 isSelected, row, column);
1020 if (value instanceof File) {
1021 tf.setText(getFileChooser().getName((File) value));
1022 tf.selectAll();
1023 }
1024 return comp;
1025 }
1026 }
1027
1028
1029 class DetailsTableCellRenderer extends DefaultTableCellRenderer {
1030 JFileChooser chooser;
1031 DateFormat df;
1032
1033 DetailsTableCellRenderer(JFileChooser chooser) {
1034 this.chooser = chooser;
1035 df = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT,
1036 chooser.getLocale());
1037 }
1038
1039 public void setBounds(int x, int y, int width, int height) {
1040 if (getHorizontalAlignment() == SwingConstants.LEADING &&
1041 !fullRowSelection) {
1042 // Restrict width to actual text
1043 width = Math.min(width, this.getPreferredSize().width+4);
1044 } else {
1045 x -= 4;
1046 }
1047 super.setBounds(x, y, width, height);
1048 }
1112 }
1113
1114 } else if (value instanceof Date) {
1115 text = df.format((Date)value);
1116
1117 } else {
1118 text = value.toString();
1119 }
1120
1121 setText(text);
1122
1123 return this;
1124 }
1125 }
1126
1127 public JPanel createDetailsView() {
1128 final JFileChooser chooser = getFileChooser();
1129
1130 JPanel p = new JPanel(new BorderLayout());
1131
1132 final JTable detailsTable = new JTable(getDetailsTableModel()) {
1133 // Handle Escape key events here
1134 protected boolean processKeyBinding(KeyStroke ks, KeyEvent e, int condition, boolean pressed) {
1135 if (e.getKeyCode() == KeyEvent.VK_ESCAPE && getCellEditor() == null) {
1136 // We are not editing, forward to filechooser.
1137 chooser.dispatchEvent(e);
1138 return true;
1139 }
1140 return super.processKeyBinding(ks, e, condition, pressed);
1141 }
1142
1143 public void tableChanged(TableModelEvent e) {
1144 super.tableChanged(e);
1145
1146 if (e.getFirstRow() == TableModelEvent.HEADER_ROW) {
1147 // update header with possibly changed column set
1148 updateDetailsColumnModel(this);
1149 }
1150 }
1151 };
1430 }
1431 } else {
1432 //Could be because of delay in updating Desktop folder
1433 //chooser.setSelectedFile(null);
1434 }
1435 } else {
1436 JOptionPane.showMessageDialog(chooser, MessageFormat.format(renameErrorText, oldFileName),
1437 renameErrorTitleText, JOptionPane.ERROR_MESSAGE);
1438 }
1439 }
1440 }
1441 }
1442 if (detailsTable != null && detailsTable.isEditing()) {
1443 detailsTable.getCellEditor().stopCellEditing();
1444 }
1445 cancelEdit();
1446 }
1447
1448 protected Action newFolderAction;
1449
1450 public Action getNewFolderAction() {
1451 if (!readOnly && newFolderAction == null) {
1452 newFolderAction = new AbstractAction(newFolderActionLabelText) {
1453 private Action basicNewFolderAction;
1454
1455 // Initializer
1456 {
1457 putValue(Action.ACTION_COMMAND_KEY, FilePane.ACTION_NEW_FOLDER);
1458
1459 File currentDirectory = getFileChooser().getCurrentDirectory();
1460 if (currentDirectory != null) {
1461 setEnabled(canWrite(currentDirectory));
1462 }
1463 }
1464
1465 public void actionPerformed(ActionEvent ev) {
1466 if (basicNewFolderAction == null) {
1467 basicNewFolderAction = fileChooserUIAccessor.getNewFolderAction();
1468 }
1469 JFileChooser fc = getFileChooser();
1470 File oldFile = fc.getSelectedFile();
1471 basicNewFolderAction.actionPerformed(ev);
1472 File newFile = fc.getSelectedFile();
1473 if (newFile != null && !newFile.equals(oldFile) && newFile.isDirectory()) {
1474 newFolderFile = newFile;
1475 }
1476 }
1477 };
1478 }
1479 return newFolderAction;
1480 }
1481
1482 protected class FileRenderer extends DefaultListCellRenderer {
1483
1484 public Component getListCellRendererComponent(JList list, Object value,
1485 int index, boolean isSelected,
1486 boolean cellHasFocus) {
1487
1488 if (listViewWindowsStyle && !list.isFocusOwner()) {
1489 isSelected = false;
1490 }
1491
1492 super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
1493 File file = (File) value;
1494 String fileName = getFileChooser().getName(file);
1495 setText(fileName);
1496 setFont(list.getFont());
1497
1498 Icon icon = getFileChooser().getIcon(file);
1499 if (icon != null) {
1500 setIcon(icon);
1501 } else {
|
1 /*
2 * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
41 import javax.swing.event.*;
42 import javax.swing.filechooser.*;
43 import javax.swing.plaf.basic.*;
44 import javax.swing.table.*;
45 import javax.swing.text.*;
46
47 import sun.awt.shell.*;
48
49 /**
50 * <b>WARNING:</b> This class is an implementation detail and is only
51 * public so that it can be used by two packages. You should NOT consider
52 * this public API.
53 * <p>
54 * This component is intended to be used in a subclass of
55 * javax.swing.plaf.basic.BasicFileChooserUI. It realies heavily on the
56 * implementation of BasicFileChooserUI, and is intended to be API compatible
57 * with earlier implementations of MetalFileChooserUI and WindowsFileChooserUI.
58 *
59 * @author Leif Samuelsson
60 */
61 @SuppressWarnings("serial") // JDK-implementation class
62 public class FilePane extends JPanel implements PropertyChangeListener {
63 // Constants for actions. These are used for the actions' ACTION_COMMAND_KEY
64 // and as keys in the action maps for FilePane and the corresponding UI classes
65
66 public final static String ACTION_APPROVE_SELECTION = "approveSelection";
67 public final static String ACTION_CANCEL = "cancelSelection";
68 public final static String ACTION_EDIT_FILE_NAME = "editFileName";
69 public final static String ACTION_REFRESH = "refresh";
70 public final static String ACTION_CHANGE_TO_PARENT_DIRECTORY = "Go Up";
71 public final static String ACTION_NEW_FOLDER = "New Folder";
72 public final static String ACTION_VIEW_LIST = "viewTypeList";
73 public final static String ACTION_VIEW_DETAILS = "viewTypeDetails";
74
75 private Action[] actions;
76
77 // "enums" for setViewType()
78 public static final int VIEWTYPE_LIST = 0;
79 public static final int VIEWTYPE_DETAILS = 1;
80 private static final int VIEWTYPE_COUNT = 2;
81
375 getCurrentKeyboardFocusManager().getPermanentFocusOwner();
376
377 isFocusOwner = owner == detailsTable || owner == list;
378
379 remove(currentViewPanel);
380 }
381
382 currentViewPanel = viewPanels[viewType];
383 add(currentViewPanel, BorderLayout.CENTER);
384
385 if (isFocusOwner && newFocusOwner != null) {
386 newFocusOwner.requestFocusInWindow();
387 }
388
389 revalidate();
390 repaint();
391 updateViewMenu();
392 firePropertyChange("viewType", oldValue, viewType);
393 }
394
395 @SuppressWarnings("serial") // JDK-implementation class
396 class ViewTypeAction extends AbstractAction {
397 private int viewType;
398
399 ViewTypeAction(int viewType) {
400 super(viewTypeActionNames[viewType]);
401 this.viewType = viewType;
402
403 String cmd;
404 switch (viewType) {
405 case VIEWTYPE_LIST: cmd = ACTION_VIEW_LIST; break;
406 case VIEWTYPE_DETAILS: cmd = ACTION_VIEW_DETAILS; break;
407 default: cmd = (String)getValue(Action.NAME);
408 }
409 putValue(Action.ACTION_COMMAND_KEY, cmd);
410 }
411
412 public void actionPerformed(ActionEvent e) {
413 setViewType(viewType);
414 }
415 }
455 megaByteString = UIManager.getString("FileChooser.fileSizeMegaBytes", l);
456 gigaByteString = UIManager.getString("FileChooser.fileSizeGigaBytes", l);
457 fullRowSelection = UIManager.getBoolean("FileView.fullRowSelection");
458
459 filesListAccessibleName = UIManager.getString("FileChooser.filesListAccessibleName", l);
460 filesDetailsAccessibleName = UIManager.getString("FileChooser.filesDetailsAccessibleName", l);
461
462 renameErrorTitleText = UIManager.getString("FileChooser.renameErrorTitleText", l);
463 renameErrorText = UIManager.getString("FileChooser.renameErrorText", l);
464 renameErrorFileExistsText = UIManager.getString("FileChooser.renameErrorFileExistsText", l);
465 }
466
467 /**
468 * Fetches the command list for the FilePane. These commands
469 * are useful for binding to events, such as in a keymap.
470 *
471 * @return the command list
472 */
473 public Action[] getActions() {
474 if (actions == null) {
475 @SuppressWarnings("serial") // JDK-implementation class
476 class FilePaneAction extends AbstractAction {
477 FilePaneAction(String name) {
478 this(name, name);
479 }
480
481 FilePaneAction(String name, String cmd) {
482 super(name);
483 putValue(Action.ACTION_COMMAND_KEY, cmd);
484 }
485
486 public void actionPerformed(ActionEvent e) {
487 String cmd = (String)getValue(Action.ACTION_COMMAND_KEY);
488
489 if (cmd == ACTION_CANCEL) {
490 if (editFile != null) {
491 cancelEdit();
492 } else {
493 getFileChooser().cancelSelection();
494 }
495 } else if (cmd == ACTION_EDIT_FILE_NAME) {
563 if (cmd == null) {
564 cmd = (String)a.getValue(Action.NAME);
565 }
566 map.put(cmd, a);
567 }
568 }
569 }
570
571
572 private void updateListRowCount(JList list) {
573 if (smallIconsView) {
574 list.setVisibleRowCount(getModel().getSize() / 3);
575 } else {
576 list.setVisibleRowCount(-1);
577 }
578 }
579
580 public JPanel createList() {
581 JPanel p = new JPanel(new BorderLayout());
582 final JFileChooser fileChooser = getFileChooser();
583
584 @SuppressWarnings("serial") // anonymous class
585 final JList<Object> list = new JList<Object>() {
586 public int getNextMatch(String prefix, int startIndex, Position.Bias bias) {
587 ListModel model = getModel();
588 int max = model.getSize();
589 if (prefix == null || startIndex < 0 || startIndex >= max) {
590 throw new IllegalArgumentException();
591 }
592 // start search from the next element before/after the selected element
593 boolean backwards = (bias == Position.Bias.Backward);
594 for (int i = startIndex; backwards ? i >= 0 : i < max; i += (backwards ? -1 : 1)) {
595 String filename = fileChooser.getName((File)model.getElementAt(i));
596 if (filename.regionMatches(true, 0, prefix, 0, prefix.length())) {
597 return i;
598 }
599 }
600 return -1;
601 }
602 };
603 list.setCellRenderer(new FileRenderer());
604 list.setLayoutOrientation(JList.VERTICAL_WRAP);
639 list.addListSelectionListener(createListSelectionListener());
640 list.addMouseListener(getMouseHandler());
641
642 JScrollPane scrollpane = new JScrollPane(list);
643 if (listViewBackground != null) {
644 list.setBackground(listViewBackground);
645 }
646 if (listViewBorder != null) {
647 scrollpane.setBorder(listViewBorder);
648 }
649
650 list.putClientProperty(AccessibleContext.ACCESSIBLE_NAME_PROPERTY, filesListAccessibleName);
651
652 p.add(scrollpane, BorderLayout.CENTER);
653 return p;
654 }
655
656 /**
657 * This model allows for sorting JList
658 */
659 @SuppressWarnings("serial") // JDK-implementation class
660 private class SortableListModel extends AbstractListModel<Object>
661 implements TableModelListener, RowSorterListener {
662
663 public SortableListModel() {
664 getDetailsTableModel().addTableModelListener(this);
665 getRowSorter().addRowSorterListener(this);
666 }
667
668 public int getSize() {
669 return getModel().getSize();
670 }
671
672 public Object getElementAt(int index) {
673 // JList doesn't support RowSorter so far, so we put it into the list model
674 return getModel().getElementAt(getRowSorter().convertRowIndexToModel(index));
675 }
676
677 public void tableChanged(TableModelEvent e) {
678 fireContentsChanged(this, 0, getSize());
679 }
680
681 public void sorterChanged(RowSorterEvent e) {
682 fireContentsChanged(this, 0, getSize());
683 }
684 }
685
686 private DetailsTableModel getDetailsTableModel() {
687 if(detailsTableModel == null) {
688 detailsTableModel = new DetailsTableModel(getFileChooser());
689 }
690 return detailsTableModel;
691 }
692
693 @SuppressWarnings("serial") // JDK-implementation class
694 class DetailsTableModel extends AbstractTableModel implements ListDataListener {
695 JFileChooser chooser;
696 BasicDirectoryModel directoryModel;
697
698 ShellFolderColumnInfo[] columns;
699 int[] columnMap;
700
701 DetailsTableModel(JFileChooser fc) {
702 this.chooser = fc;
703 directoryModel = getModel();
704 directoryModel.addListDataListener(this);
705
706 updateColumnInfo();
707 }
708
709 void updateColumnInfo() {
710 File dir = chooser.getCurrentDirectory();
711 if (dir != null && usesShellFolder(chooser)) {
712 try {
713 dir = ShellFolder.getShellFolder(dir);
993 return comparator.compare(
994 getDetailsTableModel().getFileColumnValue(f1, column),
995 getDetailsTableModel().getFileColumnValue(f2, column)
996 );
997 }
998 // For this column we need to pass the file itself (not a
999 // column value) to the comparator
1000 return comparator.compare(f1, f2);
1001 }
1002 }
1003
1004 private DetailsTableCellEditor tableCellEditor;
1005
1006 private DetailsTableCellEditor getDetailsTableCellEditor() {
1007 if (tableCellEditor == null) {
1008 tableCellEditor = new DetailsTableCellEditor(new JTextField());
1009 }
1010 return tableCellEditor;
1011 }
1012
1013 @SuppressWarnings("serial") // JDK-implementation class
1014 private class DetailsTableCellEditor extends DefaultCellEditor {
1015 private final JTextField tf;
1016
1017 public DetailsTableCellEditor(JTextField tf) {
1018 super(tf);
1019 this.tf = tf;
1020 tf.setName("Table.editor");
1021 tf.addFocusListener(editorFocusListener);
1022 }
1023
1024 public Component getTableCellEditorComponent(JTable table, Object value,
1025 boolean isSelected, int row, int column) {
1026 Component comp = super.getTableCellEditorComponent(table, value,
1027 isSelected, row, column);
1028 if (value instanceof File) {
1029 tf.setText(getFileChooser().getName((File) value));
1030 tf.selectAll();
1031 }
1032 return comp;
1033 }
1034 }
1035
1036 @SuppressWarnings("serial") // JDK-implementation class
1037 class DetailsTableCellRenderer extends DefaultTableCellRenderer {
1038 JFileChooser chooser;
1039 DateFormat df;
1040
1041 DetailsTableCellRenderer(JFileChooser chooser) {
1042 this.chooser = chooser;
1043 df = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT,
1044 chooser.getLocale());
1045 }
1046
1047 public void setBounds(int x, int y, int width, int height) {
1048 if (getHorizontalAlignment() == SwingConstants.LEADING &&
1049 !fullRowSelection) {
1050 // Restrict width to actual text
1051 width = Math.min(width, this.getPreferredSize().width+4);
1052 } else {
1053 x -= 4;
1054 }
1055 super.setBounds(x, y, width, height);
1056 }
1120 }
1121
1122 } else if (value instanceof Date) {
1123 text = df.format((Date)value);
1124
1125 } else {
1126 text = value.toString();
1127 }
1128
1129 setText(text);
1130
1131 return this;
1132 }
1133 }
1134
1135 public JPanel createDetailsView() {
1136 final JFileChooser chooser = getFileChooser();
1137
1138 JPanel p = new JPanel(new BorderLayout());
1139
1140 @SuppressWarnings("serial") // anonymous class
1141 final JTable detailsTable = new JTable(getDetailsTableModel()) {
1142 // Handle Escape key events here
1143 protected boolean processKeyBinding(KeyStroke ks, KeyEvent e, int condition, boolean pressed) {
1144 if (e.getKeyCode() == KeyEvent.VK_ESCAPE && getCellEditor() == null) {
1145 // We are not editing, forward to filechooser.
1146 chooser.dispatchEvent(e);
1147 return true;
1148 }
1149 return super.processKeyBinding(ks, e, condition, pressed);
1150 }
1151
1152 public void tableChanged(TableModelEvent e) {
1153 super.tableChanged(e);
1154
1155 if (e.getFirstRow() == TableModelEvent.HEADER_ROW) {
1156 // update header with possibly changed column set
1157 updateDetailsColumnModel(this);
1158 }
1159 }
1160 };
1439 }
1440 } else {
1441 //Could be because of delay in updating Desktop folder
1442 //chooser.setSelectedFile(null);
1443 }
1444 } else {
1445 JOptionPane.showMessageDialog(chooser, MessageFormat.format(renameErrorText, oldFileName),
1446 renameErrorTitleText, JOptionPane.ERROR_MESSAGE);
1447 }
1448 }
1449 }
1450 }
1451 if (detailsTable != null && detailsTable.isEditing()) {
1452 detailsTable.getCellEditor().stopCellEditing();
1453 }
1454 cancelEdit();
1455 }
1456
1457 protected Action newFolderAction;
1458
1459 @SuppressWarnings("serial") // anonymous class inside
1460 public Action getNewFolderAction() {
1461 if (!readOnly && newFolderAction == null) {
1462 newFolderAction = new AbstractAction(newFolderActionLabelText) {
1463 private Action basicNewFolderAction;
1464
1465 // Initializer
1466 {
1467 putValue(Action.ACTION_COMMAND_KEY, FilePane.ACTION_NEW_FOLDER);
1468
1469 File currentDirectory = getFileChooser().getCurrentDirectory();
1470 if (currentDirectory != null) {
1471 setEnabled(canWrite(currentDirectory));
1472 }
1473 }
1474
1475 public void actionPerformed(ActionEvent ev) {
1476 if (basicNewFolderAction == null) {
1477 basicNewFolderAction = fileChooserUIAccessor.getNewFolderAction();
1478 }
1479 JFileChooser fc = getFileChooser();
1480 File oldFile = fc.getSelectedFile();
1481 basicNewFolderAction.actionPerformed(ev);
1482 File newFile = fc.getSelectedFile();
1483 if (newFile != null && !newFile.equals(oldFile) && newFile.isDirectory()) {
1484 newFolderFile = newFile;
1485 }
1486 }
1487 };
1488 }
1489 return newFolderAction;
1490 }
1491
1492 @SuppressWarnings("serial") // JDK-implementation class
1493 protected class FileRenderer extends DefaultListCellRenderer {
1494
1495 public Component getListCellRendererComponent(JList list, Object value,
1496 int index, boolean isSelected,
1497 boolean cellHasFocus) {
1498
1499 if (listViewWindowsStyle && !list.isFocusOwner()) {
1500 isSelected = false;
1501 }
1502
1503 super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
1504 File file = (File) value;
1505 String fileName = getFileChooser().getName(file);
1506 setText(fileName);
1507 setFont(list.getFont());
1508
1509 Icon icon = getFileChooser().getIcon(file);
1510 if (icon != null) {
1511 setIcon(icon);
1512 } else {
|