1 /*
2 * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25 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();
1250 }
1251
1252 /**
1253 * Data model for a type-face selection combo-box.
1254 */
1255 @SuppressWarnings("serial") // Superclass is not serializable across versions
1256 protected class FilterComboBoxModel extends AbstractListModel<FileFilter> implements ComboBoxModel<FileFilter>,
1257 PropertyChangeListener {
1258 protected FileFilter[] filters;
1259 protected FilterComboBoxModel() {
1260 super();
1261 filters = getFileChooser().getChoosableFileFilters();
1262 }
1263
1264 public void propertyChange(PropertyChangeEvent e) {
1265 String prop = e.getPropertyName();
1266 if(prop == JFileChooser.CHOOSABLE_FILE_FILTER_CHANGED_PROPERTY) {
1267 filters = (FileFilter[]) e.getNewValue();
1268 fireContentsChanged(this, -1, -1);
1269 } else if (prop == JFileChooser.FILE_FILTER_CHANGED_PROPERTY) {
1270 fireContentsChanged(this, -1, -1);
1271 }
1272 }
1273
1274 public void setSelectedItem(Object filter) {
1275 if(filter != null) {
1276 getFileChooser().setFileFilter((FileFilter) filter);
1277 fireContentsChanged(this, -1, -1);
1278 }
1279 }
1280
1281 public Object getSelectedItem() {
1282 // Ensure that the current filter is in the list.
1283 // NOTE: we shouldnt' have to do this, since JFileChooser adds
1284 // the filter to the choosable filters list when the filter
1285 // is set. Lets be paranoid just in case someone overrides
1286 // setFileFilter in JFileChooser.
1287 FileFilter currentFilter = getFileChooser().getFileFilter();
1288 boolean found = false;
1289 if(currentFilter != null) {
1290 for (FileFilter filter : filters) {
1291 if (filter == currentFilter) {
1292 found = true;
1293 }
1294 }
1295 if(found == false) {
1296 getFileChooser().addChoosableFileFilter(currentFilter);
1297 }
1298 }
1299 return getFileChooser().getFileFilter();
1300 }
1301
1302 public int getSize() {
1303 if(filters != null) {
1304 return filters.length;
1305 } else {
1306 return 0;
1307 }
1308 }
1309
1310 public FileFilter getElementAt(int index) {
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 }