package games.strategy.engine.data.properties;
import java.awt.FileDialog;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.File;
import java.util.Arrays;
import javax.swing.JComponent;
import javax.swing.JFileChooser;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.filechooser.FileFilter;
import games.strategy.engine.framework.startup.ui.MainFrame;
import games.strategy.engine.framework.system.SystemProperties;
/**
* User editable property representing a file.
*
* <p>
* Presents a clickable label with the currently selected file name, through which a file dialog panel is accessible to
* change the file.
* </p>
*/
public class FileProperty extends AEditableProperty {
private static final long serialVersionUID = 6826763550643504789L;
private static final String[] defaultImageSuffixes = {"png", "jpg", "jpeg", "gif"};
private final String[] m_acceptableSuffixes;
private File m_file;
/**
* Construct a new file property.
*
* @param name - The name of the property
* @param fileName - The name of the file to be associated with this property
*/
public FileProperty(final String name, final String description, final String fileName) {
this(name, description, getFileIfExists(new File(fileName)));
}
private static File getFileIfExists(final File file) {
if (file.exists()) {
return file;
}
return null;
}
public FileProperty(final String name, final String description, final File file) {
this(name, description, file, defaultImageSuffixes);
}
public FileProperty(final String name, final String description, final File file, final String[] acceptableSuffixes) {
super(name, description);
m_file = getFileIfExists(file);
m_acceptableSuffixes = acceptableSuffixes;
}
/**
* Gets the file associated with this property.
*
* @return The file associated with this property
*/
@Override
public Object getValue() {
return m_file;
}
@Override
public void setValue(final Object value) throws ClassCastException {
m_file = (File) value;
}
/**
* Gets a Swing component to display this property.
*
* @return a non-editable JTextField
*/
@Override
public JComponent getEditorComponent() {
final JTextField label;
if (m_file == null) {
label = new JTextField();
} else {
label = new JTextField(m_file.getAbsolutePath());
}
label.setEditable(false);
label.addMouseListener(new MouseListener() {
@Override
public void mouseClicked(final MouseEvent e) {
final File selection = getFileUsingDialog(m_acceptableSuffixes);
if (selection != null) {
m_file = selection;
label.setText(m_file.getAbsolutePath());
// Ask Swing to repaint this label when it's convenient
SwingUtilities.invokeLater(() -> label.repaint());
}
}
@Override
public void mouseEntered(final MouseEvent e) {}
@Override
public void mouseExited(final MouseEvent e) {}
@Override
public void mousePressed(final MouseEvent e) {}
@Override
public void mouseReleased(final MouseEvent e) {}
});
return label;
}
/**
* Prompts the user to select a file.
*/
private File getFileUsingDialog(final String... acceptableSuffixes) {
// For some strange reason,
// the only way to get a Mac OS X native-style file dialog
// is to use an AWT FileDialog instead of a Swing JDialog
if (SystemProperties.isMac()) {
final FileDialog fileDialog = new FileDialog(MainFrame.getInstance());
fileDialog.setMode(FileDialog.LOAD);
fileDialog.setFilenameFilter((dir, name) -> {
if (acceptableSuffixes == null || acceptableSuffixes.length == 0) {
return true;
}
for (final String suffix : acceptableSuffixes) {
if (name.toLowerCase().endsWith(suffix)) {
return true;
}
}
return false;
});
fileDialog.setVisible(true);
final String fileName = fileDialog.getFile();
final String dirName = fileDialog.getDirectory();
if (fileName == null) {
return null;
}
return new File(dirName, fileName);
}
final JFileChooser fileChooser = new JFileChooser();
fileChooser.setFileFilter(new FileFilter() {
@Override
public boolean accept(final File file) {
if (file == null) {
return false;
} else if (file.isDirectory()) {
return true;
} else {
final String name = file.getAbsolutePath().toLowerCase();
for (final String suffix : acceptableSuffixes) {
if (name.endsWith(suffix)) {
return true;
}
}
return false;
}
}
@Override
public String getDescription() {
return Arrays.toString(acceptableSuffixes);
}
});
final int rVal = fileChooser.showOpenDialog(MainFrame.getInstance());
if (rVal == JFileChooser.APPROVE_OPTION) {
return fileChooser.getSelectedFile();
}
return null;
}
@Override
public boolean validate(final Object value) {
if (value == null) {
return true;
}
if (value instanceof File) {
final File file = (File) value;
for (final String suff : m_acceptableSuffixes) {
if (file.getName() != null && file.getName().endsWith(suff)) {
return true;
}
}
}
return false;
}
}