/*
* FileChooserField.java
*
* created: 10.10.2011
* charset: UTF-8
* license: MIT (X11) (See LICENSE file for full license)
*/
package cz.mp.k3bg.gui.component;
import cz.mp.k3bg.Images;
import cz.mp.k3bg.gui.MainFrame;
import cz.mp.k3bg.gui.helper.FileChooserBuilder;
import cz.mp.k3bg.log.LoggerManager;
import cz.mp.k3bg.misc.DirectoryRestrictedFileSystemView;
import cz.mp.k3bg.misc.ExtFileFilter;
import cz.mp.k3bg.util.DesktopUtils;
import cz.mp.util.FileUtils;
import cz.mp.util.GuiUtils;
import cz.mp.util.StringUtils;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.io.File;
import java.util.logging.Logger;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.EventListenerList;
import javax.swing.filechooser.FileFilter;
import net.miginfocom.swing.MigLayout;
/**
* Komponenta {@code FileChooserField} pro pohodlnější výběr souboru.
* <p>
* Komponenta je složena ze tří částí:
* <ol>
* <li>tlačítko, které otevře java dialog pro výběr souboru,
* </li><li>textové pole pro zobrazení vybraného souboru a pro zadání souboru ručně,
* </li><li>tlačítko, které otevře operačním systémem přidružený program vybraného
* souboru.
* </li></ol>
* <p>
* Lze zadat kořenový adresář. Pak se budou v textovém poli zobrazovat
* cesty k souborům vzhledem ke kořenovému adresáři ("ralativní cesty").
*
* @author Martin Pokorný
* @version 0.3
* @see FileChooserBuilder
* @see DirectoryRestrictedFileSystemView
*/
public class FileChooserField extends JPanel {
private static final boolean DEBUG = false;
private static final Logger logger =
LoggerManager.getLogger(FileChooserField.class, DEBUG);
private static final JButton tempButton = new JButton("...");
private JButton fileSearchButton = new JButton("", Images.getImage(Images.FOLDER)) {
@Override
public Dimension getPreferredSize() {
return new Dimension(
super.getPreferredSize().width,
tempButton.getPreferredSize().height);
}
};
private JButton openFileButton = new JButton("", Images.getImage(Images.DETAIL));
private boolean openButtonVisible = true;
private JTextField fileField = new JTextField() {
@Override
public void setText(String text) {
super.setText(text);
moveCaretToEnd();
}
/**
*
*/
private void moveCaretToEnd() {
String text = getText();
if (! StringUtils.isEmpty(text)) {
setCaretPosition(text.length());
}
}
};
private FileChooserBuilder fileChooserBuilder = new FileChooserBuilder();
public static final String DEFAULT_DIR =
System.getProperty("user.home");
// -----
/** */
public FileChooserField() {
this(DEFAULT_DIR, true);
}
/**
*
* @param openButtonVisible
*/
public FileChooserField(boolean openButtonVisible) {
this(DEFAULT_DIR, openButtonVisible);
}
/**
*
* @param selectedFilePath
*/
public FileChooserField(String selectedFilePath) {
this(selectedFilePath, true);
}
/**
*
* @param selectedFilePath
* @param openButtonVisible
*/
public FileChooserField(String selectedFilePath, boolean openButtonVisible) {
setOpenButtonVisibleImpl(openButtonVisible);
setSelectedFileImpl(selectedFilePath);
initComponents();
initLayout();
initEventHandlers();
}
// -----
/**
*
*/
private void initComponents() {
fileChooserBuilder.setSelectionMode(JFileChooser.FILES_ONLY);
}
/**
*
*/
private void initLayout() {
this.setLayout(new MigLayout("",
"0[fill,grow,120:pref:max]rel[]0",
"0[]0"));
this.add(fileField, "sgy");
this.add(fileSearchButton, "hidemode 3, sgy");
if (openButtonVisible) {
this.add(openFileButton, "hidemode 0, sgy");
openFileButton.setVisible(false);
}
}
/**
*
*/
private void initEventHandlers() {
fileField.addKeyListener(new KeyAdapter() {
String oldValue = "";
@Override
public void keyReleased(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_F3) {
openFile();
}
else {
if (! (e.getSource() instanceof JTextField)) {
return;
}
JTextField textField = (JTextField)e.getSource();
String value = textField.getText().trim();
if (! oldValue.equals(value)) {
logger.finest("(fileField) oldValue = " + oldValue);
oldValue = value;
logger.finest("(fileField) value = " + value);
logger.finest("---");
handleChange();
}
}
}
});
fileSearchButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
logger.finer("(fileSearchButton)");
JFileChooser fileChooser = fileChooserBuilder.getFileChooser();
String rootDirPath = fileChooserBuilder.getRoot();
File actualFile = new File(fileField.getText());
if (rootDirPath != null) {
actualFile = new File(rootDirPath);
}
if (actualFile.isDirectory()) {
fileChooser.setCurrentDirectory(actualFile);
}
else {
fileChooser.setSelectedFile(actualFile);
}
int returnVal = fileChooser.showOpenDialog(
MainFrame.getInstance());
if (returnVal != JFileChooser.APPROVE_OPTION) {
return;
}
setSelectedFileImpl(
FileUtils.getAbsoluteFilePath(
fileChooser.getSelectedFile()));
handleChange();
}
});
openFileButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
logger.finer("(openFileButton)");
openFile();
}
});
}
/**
*
*/
private void handleChange() {
SwingUtilities.invokeLater(
new Runnable() {
@Override
public void run() {
logger.finer("(change)");
openFileButton.setVisible(
openButtonVisible
&& isSelectedFile());
fireChangeEvent();
}
});
}
/**
* Zjistí zda je v textovém poli zadán platný soubor.
*
* @return
*/
public boolean isSelectedFile() {
String filePath = getSelectedFileAbsolutePath();
if (StringUtils.isBlank(filePath)) {
return false;
}
File file = new File(filePath);
if (!file.exists()) {
return false;
}
// (pokud se zadá soubor se špatnou příponou do textového pole...
// vrátí false)
boolean acceptedFile = true;
JFileChooser fileChooser = fileChooserBuilder.getFileChooser();
FileFilter ffilter = fileChooser.getFileFilter();
if (ffilter != null &&
! ffilter.equals(fileChooser.getAcceptAllFileFilter())) {
acceptedFile = ffilter.accept(getSelectedFile());
}
if (fileChooser.getFileSelectionMode() ==
JFileChooser.DIRECTORIES_ONLY) {
return acceptedFile && file.isDirectory();
}
if (fileChooser.getFileSelectionMode() ==
JFileChooser.FILES_ONLY) {
return acceptedFile && !file.isDirectory();
}
return true;
}
/**
* Nastaví zadanou cestu jako vybranou.
*
* @param path
* @return
* @throws IllegalArgumentException
*/
public void setSelectedFile(String path) {
setSelectedFileImpl(path);
}
/**
* Nastaví zadanou cestu jako vybranou.
*
* @param path
* @return
* @throws IllegalArgumentException
*/
private void setSelectedFileImpl(String path) {
if (StringUtils.isBlank(path)) {
fileField.setText("");
}
if (fileChooserBuilder.getRoot() != null) {
String relativePath = FileUtils.getAbsoluteFilePath(path)
.replace(fileChooserBuilder.getRoot() + File.separator, "");
fileField.setText(relativePath);
}
else {
fileField.setText(
FileUtils.getAbsoluteFilePath(path));
}
handleChange();
}
/**
*
* @return prázdný řetězec, pokud ...
*/
public String getSelectedFileAbsolutePath() {
String path = getSelectedFilePath();
if (StringUtils.isBlank(path)) {
return "";
}
if (fileChooserBuilder.getRoot() == null ||
path.startsWith(fileChooserBuilder.getRoot())) {
return path;
}
else {
return fileChooserBuilder.getRoot() + File.separator + path;
}
}
/**
* Získá cestu vybraného souboru.
*
* @return prázdný řetězec, pro případ, kdy není nic zadáno.
*/
public String getSelectedFilePath() {
String path = fileField.getText();
if (StringUtils.isBlank(path)) {
return "";
}
return path;
}
/**
* Zjistí zda je v textovém poli zadána absolutní cesta.
*
* @return
*/
boolean isSelectedAbsolutePath() {
String filePath = getSelectedFilePath();
if (filePath.startsWith(fileChooserBuilder.getRoot())) {
return true;
}
return false;
}
/**
* Získá vybraný souboru.
*
* @return {@code null} pokud není zadána cesta k souboru.
*/
public File getSelectedFile() {
String absPath = getSelectedFileAbsolutePath();
if (StringUtils.isBlank(absPath)) {
return null;
}
else {
return new File(absPath);
}
}
/**
*
* @param selectionMode {@code JFileChooser.DIRECTORIES_ONLY}
* nebo {@code JFileChooser.FILES_ONLY}
* nebo {@code JFileChooser.FILES_AND_DIRECTORIES}
*/
public void setSelectionMode(int selectionMode) {
fileChooserBuilder.setSelectionMode(selectionMode);
}
/**
*
* @param openButtonVisible
*/
private void setOpenButtonVisibleImpl(boolean openButtonVisible) {
this.openButtonVisible = openButtonVisible;
openFileButton.setVisible(openButtonVisible);
}
/**
* Nastaví filtr definovaný seznamem přípon souboru a popisem filtru.
*
* @param baseDescription
* @param exts
*/
public void setFilter(String baseDescription, String... exts) {
ExtFileFilter filter = new ExtFileFilter(baseDescription, exts);
setFilter(filter);
}
/**
*
* @param filter
*/
public void setFilter(ExtFileFilter filter) {
fileChooserBuilder.setFilter(filter);
}
/**
*
*/
public void clear() {
SwingUtilities.invokeLater(
new Runnable() {
@Override
public void run() {
fileField.setText("");
openFileButton.setVisible(false);
fireChangeEvent();
}
});
}
/**
*
* @return
*/
public boolean isEmpty() {
return fileField.getText().isEmpty();
}
/**
*
* @return
*/
public int getSelectionMode() {
return fileChooserBuilder.getFileChooser().getFileSelectionMode();
}
/**
*
* @param editable
*/
public void setEditable(boolean editable) {
fileField.setEditable(editable);
fileSearchButton.setVisible(editable);
}
/**
*
* @return
*/
public boolean isEditable() {
return fileField.isEditable();
}
/**
*
* @param text
*/
public void setText(String text) {
fileField.setText(text);
}
/**
* Nastaví kořenový adresář.
*
* @param rootDirPath
*/
public void setRoot(String rootDirPath) {
clear();
fileChooserBuilder.setRoot(rootDirPath);
handleChange();
}
/**
*
* @return
*/
public String getRoot() {
return fileChooserBuilder.getRoot();
}
/**
*
*/
private void openFile() {
String filePath = getSelectedFileAbsolutePath();
if (filePath != null && openFileButton.isVisible()) {
GuiUtils.setWaitCursorForAmoment(MainFrame.getInstance());
DesktopUtils.openFile(filePath);
}
}
private boolean enabledInternal = true;
@Override
public void setEnabled(boolean enabled) {
setOpaque(enabled);
fileField.setEnabled(enabled);
fileSearchButton.setEnabled(enabled);
openFileButton.setEnabled(enabled);
enabledInternal = enabled;
}
@Override
public boolean isEnabled() {
return enabledInternal;
}
// ----- ChangeEvent
private EventListenerList changeListeners = new EventListenerList();
/**
* Zaregistruje posluchače změny -- {@code ChangeEvent}.
* <em>poznámka:</em> událost {@code ChangeEvent} má být vystřelena při
* změně textu v poli s cestou k souboru nebo adresáři.
*/
public void addChangeListener(ChangeListener listener) {
changeListeners.add(ChangeListener.class, listener);
}
public void removeChangeListener(ChangeListener listener) {
changeListeners.remove(ChangeListener.class, listener);
}
private ChangeEvent changeEvent = new ChangeEvent(this);
void fireChangeEvent() {
fireChangeEvent(changeEvent);
}
/**
* Událost má být vystřelena při změně textu v poli s cestou k souboru.
*
* @param ed (nemělo by být {@code null}!)
*/
private void fireChangeEvent(ChangeEvent ed) {
Object[] listeners = changeListeners.getListenerList();
for (int i = listeners.length - 2; i >= 0; i -= 2) {
if (listeners[i] == ChangeListener.class) {
((ChangeListener) listeners[i + 1]).stateChanged(ed);
}
}
}
} // FileChooserField