8240690: Race condition between EDT and BasicDirectoryModel.FilesLoader.run0()
Reviewed-by: psadhukhan
This commit is contained in:
parent
40e667c174
commit
3399842d7e
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -22,30 +22,83 @@
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.java.swing.plaf.gtk;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import java.beans.*;
|
||||
import java.awt.AWTKeyStroke;
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Component;
|
||||
import java.awt.Container;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.FlowLayout;
|
||||
import java.awt.GridBagConstraints;
|
||||
import java.awt.GridBagLayout;
|
||||
import java.awt.GridLayout;
|
||||
import java.awt.Insets;
|
||||
import java.awt.KeyboardFocusManager;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.MouseListener;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashSet;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
import java.util.Vector;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.border.*;
|
||||
import javax.swing.filechooser.*;
|
||||
import javax.swing.event.*;
|
||||
import javax.swing.plaf.*;
|
||||
import javax.accessibility.AccessibleContext;
|
||||
import javax.swing.AbstractAction;
|
||||
import javax.swing.AbstractListModel;
|
||||
import javax.swing.Action;
|
||||
import javax.swing.ActionMap;
|
||||
import javax.swing.Box;
|
||||
import javax.swing.BoxLayout;
|
||||
import javax.swing.ComboBoxModel;
|
||||
import javax.swing.DefaultListCellRenderer;
|
||||
import javax.swing.DefaultListSelectionModel;
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JComboBox;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JFileChooser;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JList;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JRootPane;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JSplitPane;
|
||||
import javax.swing.JTextField;
|
||||
import javax.swing.KeyStroke;
|
||||
import javax.swing.ListSelectionModel;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.TransferHandler;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
import javax.swing.event.ListDataEvent;
|
||||
import javax.swing.event.ListDataListener;
|
||||
import javax.swing.event.ListSelectionEvent;
|
||||
import javax.swing.event.ListSelectionListener;
|
||||
import javax.swing.filechooser.FileFilter;
|
||||
import javax.swing.filechooser.FileSystemView;
|
||||
import javax.swing.filechooser.FileView;
|
||||
import javax.swing.plaf.ActionMapUIResource;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.basic.BasicDirectoryModel;
|
||||
import javax.swing.table.*;
|
||||
import javax.accessibility.*;
|
||||
import javax.swing.table.JTableHeader;
|
||||
import javax.swing.table.TableCellRenderer;
|
||||
|
||||
import sun.swing.SwingUtilities2;
|
||||
|
||||
import sun.swing.plaf.synth.*;
|
||||
import sun.swing.FilePane;
|
||||
import sun.awt.shell.ShellFolder;
|
||||
import sun.swing.FilePane;
|
||||
import sun.swing.SwingUtilities2;
|
||||
import sun.swing.plaf.synth.SynthFileChooserUI;
|
||||
|
||||
/**
|
||||
* GTK FileChooserUI.
|
||||
@ -914,21 +967,18 @@ class GTKFileChooserUI extends SynthFileChooserUI {
|
||||
}
|
||||
|
||||
@SuppressWarnings("serial") // Superclass is not serializable across versions
|
||||
private class GTKDirectoryModel extends BasicDirectoryModel {
|
||||
FileSystemView fsv;
|
||||
private Comparator<File> fileComparator = new Comparator<File>() {
|
||||
public int compare(File o, File o1) {
|
||||
return fsv.getSystemDisplayName(o).compareTo(fsv.getSystemDisplayName(o1));
|
||||
}
|
||||
};
|
||||
|
||||
public GTKDirectoryModel() {
|
||||
private final class GTKDirectoryModel extends BasicDirectoryModel {
|
||||
private GTKDirectoryModel() {
|
||||
super(getFileChooser());
|
||||
}
|
||||
|
||||
protected void sort(Vector<? extends File> v) {
|
||||
fsv = getFileChooser().getFileSystemView();
|
||||
Collections.sort(v, fileComparator);
|
||||
FileSystemView fsv = getFileChooser().getFileSystemView();
|
||||
if (fsv == null) {
|
||||
super.sort(v);
|
||||
} else {
|
||||
v.sort(Comparator.comparing(fsv::getSystemDisplayName));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -22,35 +22,48 @@
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package javax.swing;
|
||||
|
||||
import javax.swing.event.*;
|
||||
import javax.swing.filechooser.*;
|
||||
import javax.swing.filechooser.FileFilter;
|
||||
import javax.swing.plaf.FileChooserUI;
|
||||
|
||||
import javax.accessibility.*;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
import java.util.Vector;
|
||||
import java.awt.AWTEvent;
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Component;
|
||||
import java.awt.Container;
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Window;
|
||||
import java.awt.Dialog;
|
||||
import java.awt.EventQueue;
|
||||
import java.awt.Frame;
|
||||
import java.awt.GraphicsEnvironment;
|
||||
import java.awt.HeadlessException;
|
||||
import java.awt.EventQueue;
|
||||
import java.awt.Toolkit;
|
||||
import java.awt.event.*;
|
||||
import java.beans.JavaBean;
|
||||
import java.awt.Window;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.event.HierarchyEvent;
|
||||
import java.awt.event.HierarchyListener;
|
||||
import java.awt.event.InputEvent;
|
||||
import java.awt.event.WindowAdapter;
|
||||
import java.awt.event.WindowEvent;
|
||||
import java.beans.BeanProperty;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.beans.JavaBean;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InvalidObjectException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.Serializable;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.Vector;
|
||||
|
||||
import javax.accessibility.Accessible;
|
||||
import javax.accessibility.AccessibleContext;
|
||||
import javax.accessibility.AccessibleRole;
|
||||
import javax.swing.event.EventListenerList;
|
||||
import javax.swing.filechooser.FileFilter;
|
||||
import javax.swing.filechooser.FileSystemView;
|
||||
import javax.swing.filechooser.FileView;
|
||||
import javax.swing.plaf.FileChooserUI;
|
||||
|
||||
/**
|
||||
* <code>JFileChooser</code> provides a simple mechanism for the user to
|
||||
@ -1610,20 +1623,23 @@ public class JFileChooser extends JComponent implements Accessible {
|
||||
public boolean isTraversable(File f) {
|
||||
Boolean traversable = null;
|
||||
if (f != null) {
|
||||
if (getFileView() != null) {
|
||||
traversable = getFileView().isTraversable(f);
|
||||
FileView fileView = getFileView();
|
||||
if (fileView != null) {
|
||||
traversable = fileView.isTraversable(f);
|
||||
}
|
||||
|
||||
FileView uiFileView = getUI().getFileView(this);
|
||||
|
||||
if (traversable == null && uiFileView != null) {
|
||||
traversable = uiFileView.isTraversable(f);
|
||||
FileChooserUI ui = getUI();
|
||||
if (traversable == null && ui != null) {
|
||||
FileView uiFileView = ui.getFileView(this);
|
||||
if (uiFileView != null) {
|
||||
traversable = uiFileView.isTraversable(f);
|
||||
}
|
||||
}
|
||||
if (traversable == null) {
|
||||
traversable = getFileSystemView().isTraversable(f);
|
||||
FileSystemView fileSystemView = getFileSystemView();
|
||||
if (traversable == null && fileSystemView != null) {
|
||||
traversable = fileSystemView.isTraversable(f);
|
||||
}
|
||||
}
|
||||
return (traversable != null && traversable.booleanValue());
|
||||
return traversable != null && traversable;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1633,11 +1649,8 @@ public class JFileChooser extends JComponent implements Accessible {
|
||||
* @see FileFilter#accept
|
||||
*/
|
||||
public boolean accept(File f) {
|
||||
boolean shown = true;
|
||||
if(f != null && fileFilter != null) {
|
||||
shown = fileFilter.accept(f);
|
||||
}
|
||||
return shown;
|
||||
FileFilter filter = fileFilter;
|
||||
return f == null || filter == null || filter.accept(f);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1998, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -25,11 +25,6 @@
|
||||
|
||||
package javax.swing.plaf.basic;
|
||||
|
||||
import sun.awt.shell.ShellFolder;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.ListDataEvent;
|
||||
import javax.swing.filechooser.FileSystemView;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.beans.PropertyChangeSupport;
|
||||
@ -37,6 +32,15 @@ import java.io.File;
|
||||
import java.util.List;
|
||||
import java.util.Vector;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import javax.swing.AbstractListModel;
|
||||
import javax.swing.JFileChooser;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.event.ListDataEvent;
|
||||
import javax.swing.filechooser.FileSystemView;
|
||||
|
||||
import sun.awt.shell.ShellFolder;
|
||||
|
||||
/**
|
||||
* Basic implementation of a file list.
|
||||
@ -46,13 +50,13 @@ import java.util.concurrent.Callable;
|
||||
@SuppressWarnings("serial") // Superclass is not serializable across versions
|
||||
public class BasicDirectoryModel extends AbstractListModel<Object> implements PropertyChangeListener {
|
||||
|
||||
private JFileChooser filechooser = null;
|
||||
private final JFileChooser filechooser;
|
||||
// PENDING(jeff) pick the size more sensibly
|
||||
private Vector<File> fileCache = new Vector<File>(50);
|
||||
private final Vector<File> fileCache = new Vector<File>(50);
|
||||
private FilesLoader filesLoader = null;
|
||||
private Vector<File> files = null;
|
||||
private Vector<File> directories = null;
|
||||
private int fetchID = 0;
|
||||
private final AtomicInteger fetchID = new AtomicInteger();
|
||||
|
||||
private PropertyChangeSupport changeSupport;
|
||||
|
||||
@ -157,9 +161,9 @@ public class BasicDirectoryModel extends AbstractListModel<Object> implements Pr
|
||||
filesLoader.cancelRunnables();
|
||||
}
|
||||
|
||||
setBusy(true, ++fetchID);
|
||||
|
||||
filesLoader = new FilesLoader(currentDirectory, fetchID);
|
||||
int fid = fetchID.incrementAndGet();
|
||||
setBusy(true, fid);
|
||||
filesLoader = new FilesLoader(currentDirectory, fid);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -260,18 +264,24 @@ public class BasicDirectoryModel extends AbstractListModel<Object> implements Pr
|
||||
}
|
||||
|
||||
|
||||
class FilesLoader implements Runnable {
|
||||
File currentDirectory = null;
|
||||
int fid;
|
||||
Vector<DoChangeContents> runnables = new Vector<DoChangeContents>(10);
|
||||
final Thread loadThread;
|
||||
private final class FilesLoader implements Runnable {
|
||||
private final FileSystemView fileSystemView;
|
||||
private final boolean useFileHiding;
|
||||
private final boolean fileSelectionEnabled;
|
||||
private final int fid;
|
||||
private final File currentDirectory;
|
||||
private volatile DoChangeContents runnable;
|
||||
private final Thread loadThread;
|
||||
|
||||
public FilesLoader(File currentDirectory, int fid) {
|
||||
private FilesLoader(File currentDirectory, int fid) {
|
||||
this.currentDirectory = currentDirectory;
|
||||
this.fid = fid;
|
||||
fileSystemView = filechooser.getFileSystemView();
|
||||
useFileHiding = filechooser.isFileHidingEnabled();
|
||||
fileSelectionEnabled = filechooser.isFileSelectionEnabled();
|
||||
String name = "Basic L&F File Loading Thread";
|
||||
this.loadThread = new Thread(null, this, name, 0, false);
|
||||
this.loadThread.start();
|
||||
loadThread = new Thread(null, this, name, 0, false);
|
||||
loadThread.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -280,14 +290,14 @@ public class BasicDirectoryModel extends AbstractListModel<Object> implements Pr
|
||||
setBusy(false, fid);
|
||||
}
|
||||
|
||||
public void run0() {
|
||||
FileSystemView fileSystem = filechooser.getFileSystemView();
|
||||
private void run0() {
|
||||
FileSystemView fileSystem = fileSystemView;
|
||||
|
||||
if (loadThread.isInterrupted()) {
|
||||
return;
|
||||
}
|
||||
|
||||
File[] list = fileSystem.getFiles(currentDirectory, filechooser.isFileHidingEnabled());
|
||||
File[] list = fileSystem.getFiles(currentDirectory, useFileHiding);
|
||||
|
||||
if (loadThread.isInterrupted()) {
|
||||
return;
|
||||
@ -305,7 +315,7 @@ public class BasicDirectoryModel extends AbstractListModel<Object> implements Pr
|
||||
|
||||
if (isTraversable) {
|
||||
newFileCache.addElement(file);
|
||||
} else if (filechooser.isFileSelectionEnabled()) {
|
||||
} else if (fileSelectionEnabled) {
|
||||
newFiles.addElement(file);
|
||||
}
|
||||
|
||||
@ -323,7 +333,7 @@ public class BasicDirectoryModel extends AbstractListModel<Object> implements Pr
|
||||
|
||||
// To avoid loads of synchronizations with Invoker and improve performance we
|
||||
// execute the whole block on the COM thread
|
||||
DoChangeContents doChangeContents = ShellFolder.invoke(new Callable<DoChangeContents>() {
|
||||
runnable = ShellFolder.invoke(new Callable<DoChangeContents>() {
|
||||
public DoChangeContents call() {
|
||||
int newSize = newFileCache.size();
|
||||
int oldSize = fileCache.size();
|
||||
@ -372,7 +382,7 @@ public class BasicDirectoryModel extends AbstractListModel<Object> implements Pr
|
||||
}
|
||||
if (!fileCache.equals(newFileCache)) {
|
||||
if (loadThread.isInterrupted()) {
|
||||
cancelRunnables(runnables);
|
||||
cancelRunnables();
|
||||
}
|
||||
return new DoChangeContents(newFileCache, 0, fileCache, 0, fid);
|
||||
}
|
||||
@ -380,22 +390,16 @@ public class BasicDirectoryModel extends AbstractListModel<Object> implements Pr
|
||||
}
|
||||
});
|
||||
|
||||
if (doChangeContents != null) {
|
||||
runnables.addElement(doChangeContents);
|
||||
SwingUtilities.invokeLater(doChangeContents);
|
||||
if (runnable != null && !loadThread.isInterrupted()) {
|
||||
SwingUtilities.invokeLater(runnable);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void cancelRunnables(Vector<DoChangeContents> runnables) {
|
||||
for (DoChangeContents runnable : runnables) {
|
||||
private void cancelRunnables() {
|
||||
if (runnable != null) {
|
||||
runnable.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
public void cancelRunnables() {
|
||||
cancelRunnables(runnables);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -486,7 +490,7 @@ public class BasicDirectoryModel extends AbstractListModel<Object> implements Pr
|
||||
* thread in order to load the contents of a directory.
|
||||
*/
|
||||
private synchronized void setBusy(final boolean busy, int fid) {
|
||||
if (fid == fetchID) {
|
||||
if (fid == fetchID.get()) {
|
||||
boolean oldValue = this.busy;
|
||||
this.busy = busy;
|
||||
|
||||
@ -501,15 +505,16 @@ public class BasicDirectoryModel extends AbstractListModel<Object> implements Pr
|
||||
}
|
||||
|
||||
|
||||
class DoChangeContents implements Runnable {
|
||||
private List<File> addFiles;
|
||||
private List<File> remFiles;
|
||||
private final class DoChangeContents implements Runnable {
|
||||
private final List<File> addFiles;
|
||||
private final List<File> remFiles;
|
||||
private boolean doFire = true;
|
||||
private int fid;
|
||||
private final int fid;
|
||||
private int addStart = 0;
|
||||
private int remStart = 0;
|
||||
|
||||
public DoChangeContents(List<File> addFiles, int addStart, List<File> remFiles, int remStart, int fid) {
|
||||
DoChangeContents(List<File> addFiles, int addStart, List<File> remFiles,
|
||||
int remStart, int fid) {
|
||||
this.addFiles = addFiles;
|
||||
this.addStart = addStart;
|
||||
this.remFiles = remFiles;
|
||||
@ -518,11 +523,11 @@ public class BasicDirectoryModel extends AbstractListModel<Object> implements Pr
|
||||
}
|
||||
|
||||
synchronized void cancel() {
|
||||
doFire = false;
|
||||
doFire = false;
|
||||
}
|
||||
|
||||
public synchronized void run() {
|
||||
if (fetchID == fid && doFire) {
|
||||
if (fetchID.get() == fid && doFire) {
|
||||
int remSize = (remFiles == null) ? 0 : remFiles.size();
|
||||
int addSize = (addFiles == null) ? 0 : addFiles.size();
|
||||
synchronized(fileCache) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -22,31 +22,106 @@
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.swing;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.ComponentOrientation;
|
||||
import java.awt.Container;
|
||||
import java.awt.Cursor;
|
||||
import java.awt.DefaultKeyboardFocusManager;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Font;
|
||||
import java.awt.Insets;
|
||||
import java.awt.KeyboardFocusManager;
|
||||
import java.awt.Point;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.event.ComponentAdapter;
|
||||
import java.awt.event.ComponentEvent;
|
||||
import java.awt.event.FocusAdapter;
|
||||
import java.awt.event.FocusEvent;
|
||||
import java.awt.event.FocusListener;
|
||||
import java.awt.event.KeyAdapter;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.awt.event.KeyListener;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.MouseListener;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.io.*;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.text.DateFormat;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
import javax.accessibility.AccessibleContext;
|
||||
import javax.swing.*;
|
||||
import javax.swing.border.*;
|
||||
import javax.swing.event.*;
|
||||
import javax.swing.filechooser.*;
|
||||
import javax.swing.plaf.basic.*;
|
||||
import javax.swing.table.*;
|
||||
import javax.swing.text.*;
|
||||
import javax.swing.AbstractAction;
|
||||
import javax.swing.AbstractListModel;
|
||||
import javax.swing.Action;
|
||||
import javax.swing.ActionMap;
|
||||
import javax.swing.ButtonGroup;
|
||||
import javax.swing.DefaultCellEditor;
|
||||
import javax.swing.DefaultListCellRenderer;
|
||||
import javax.swing.DefaultListSelectionModel;
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.InputMap;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JFileChooser;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JList;
|
||||
import javax.swing.JMenu;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JPopupMenu;
|
||||
import javax.swing.JRadioButtonMenuItem;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JTable;
|
||||
import javax.swing.JTextField;
|
||||
import javax.swing.KeyStroke;
|
||||
import javax.swing.ListModel;
|
||||
import javax.swing.ListSelectionModel;
|
||||
import javax.swing.LookAndFeel;
|
||||
import javax.swing.RowSorter;
|
||||
import javax.swing.SwingConstants;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.TransferHandler;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.border.Border;
|
||||
import javax.swing.event.ListDataEvent;
|
||||
import javax.swing.event.ListDataListener;
|
||||
import javax.swing.event.ListSelectionListener;
|
||||
import javax.swing.event.RowSorterEvent;
|
||||
import javax.swing.event.RowSorterListener;
|
||||
import javax.swing.event.TableModelEvent;
|
||||
import javax.swing.event.TableModelListener;
|
||||
import javax.swing.filechooser.FileSystemView;
|
||||
import javax.swing.plaf.basic.BasicDirectoryModel;
|
||||
import javax.swing.table.AbstractTableModel;
|
||||
import javax.swing.table.DefaultTableCellRenderer;
|
||||
import javax.swing.table.DefaultTableColumnModel;
|
||||
import javax.swing.table.TableCellEditor;
|
||||
import javax.swing.table.TableCellRenderer;
|
||||
import javax.swing.table.TableColumn;
|
||||
import javax.swing.table.TableColumnModel;
|
||||
import javax.swing.table.TableModel;
|
||||
import javax.swing.table.TableRowSorter;
|
||||
import javax.swing.text.Position;
|
||||
|
||||
import sun.awt.AWTAccessor;
|
||||
import sun.awt.AWTAccessor.MouseEventAccessor;
|
||||
import sun.awt.shell.*;
|
||||
import sun.awt.shell.ShellFolder;
|
||||
import sun.awt.shell.ShellFolderColumnInfo;
|
||||
|
||||
/**
|
||||
* <b>WARNING:</b> This class is an implementation detail and is only
|
||||
@ -694,8 +769,8 @@ public class FilePane extends JPanel implements PropertyChangeListener {
|
||||
|
||||
@SuppressWarnings("serial") // JDK-implementation class
|
||||
class DetailsTableModel extends AbstractTableModel implements ListDataListener {
|
||||
JFileChooser chooser;
|
||||
BasicDirectoryModel directoryModel;
|
||||
private final JFileChooser chooser;
|
||||
private final BasicDirectoryModel directoryModel;
|
||||
|
||||
ShellFolderColumnInfo[] columns;
|
||||
int[] columnMap;
|
||||
@ -806,7 +881,7 @@ public class FilePane extends JPanel implements PropertyChangeListener {
|
||||
JOptionPane.showMessageDialog(chooser, MessageFormat.format(renameErrorFileExistsText,
|
||||
oldFileName), renameErrorTitleText, JOptionPane.ERROR_MESSAGE);
|
||||
} else {
|
||||
if (FilePane.this.getModel().renameFile(f, f2)) {
|
||||
if (directoryModel.renameFile(f, f2)) {
|
||||
if (fsv.isParent(chooser.getCurrentDirectory(), f2)) {
|
||||
// The setSelectedFile method produces a new setValueAt invocation while the JTable
|
||||
// is editing. Postpone file selection to be sure that edit mode of the JTable
|
||||
@ -849,7 +924,7 @@ public class FilePane extends JPanel implements PropertyChangeListener {
|
||||
int i0 = e.getIndex0();
|
||||
int i1 = e.getIndex1();
|
||||
if (i0 == i1) {
|
||||
File file = (File)getModel().getElementAt(i0);
|
||||
File file = (File)directoryModel.getElementAt(i0);
|
||||
if (file.equals(newFolderFile)) {
|
||||
new DelayedSelectionUpdater(file);
|
||||
newFolderFile = null;
|
||||
|
81
test/jdk/javax/swing/JFileChooser/4966171/bug4966171.java
Normal file
81
test/jdk/javax/swing/JFileChooser/4966171/bug4966171.java
Normal file
@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
import java.awt.EventQueue;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.swing.JFileChooser;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.UnsupportedLookAndFeelException;
|
||||
|
||||
import static javax.swing.UIManager.getInstalledLookAndFeels;
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @bug 4966171 8240690
|
||||
* @key headful
|
||||
* @summary Tests that JFileChooser can be serialized
|
||||
*/
|
||||
public final class bug4966171 {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
for (UIManager.LookAndFeelInfo laf : getInstalledLookAndFeels()) {
|
||||
EventQueue.invokeAndWait(() -> setLookAndFeel(laf));
|
||||
EventQueue.invokeAndWait(bug4966171::test);
|
||||
}
|
||||
}
|
||||
|
||||
private static void test() {
|
||||
// Will run the test no more than 10 seconds per L&F
|
||||
long endtime = System.nanoTime() + TimeUnit.SECONDS.toNanos(10);
|
||||
while (System.nanoTime() < endtime) {
|
||||
try {
|
||||
var byteOut = new ByteArrayOutputStream();
|
||||
try (var out = new ObjectOutputStream(byteOut)) {
|
||||
out.writeObject(new JFileChooser());
|
||||
}
|
||||
var byteIn = new ByteArrayInputStream(byteOut.toByteArray());
|
||||
try (var in = new ObjectInputStream(byteIn)) {
|
||||
JFileChooser readFc = (JFileChooser) in.readObject();
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void setLookAndFeel(UIManager.LookAndFeelInfo laf) {
|
||||
try {
|
||||
UIManager.setLookAndFeel(laf.getClassName());
|
||||
} catch (UnsupportedLookAndFeelException ignored) {
|
||||
System.out.println("Unsupported L&F: " + laf.getClassName());
|
||||
} catch (ClassNotFoundException | InstantiationException
|
||||
| IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user