Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.smallmind.swing.file.FileChooserPanel Maven / Gradle / Ivy
/*
* Copyright (c) 2007 through 2024 David Berkman
*
* This file is part of the SmallMind Code Project.
*
* The SmallMind Code Project is free software, you can redistribute
* it and/or modify it under either, at your discretion...
*
* 1) The terms of GNU Affero General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* ...or...
*
* 2) The terms of the Apache License, Version 2.0.
*
* The SmallMind Code Project 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 or Apache License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* and the Apache License along with the SmallMind Code Project. If not, see
* or .
*
* Additional permission under the GNU Affero GPL version 3 section 7
* ------------------------------------------------------------------
* If you modify this Program, or any covered work, by linking or
* combining it with other code, such other code is not for that reason
* alone subject to any of the requirements of the GNU Affero GPL
* version 3.
*/
package org.smallmind.swing.file;
import java.awt.BorderLayout;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.File;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.swing.GroupLayout;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.LayoutStyle;
import javax.swing.ListSelectionModel;
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 org.smallmind.nutsnbolts.util.StringUtility;
import org.smallmind.nutsnbolts.util.WeakEventListenerList;
import org.smallmind.swing.ColorUtility;
import org.smallmind.swing.SmallMindGrayFilter;
import org.smallmind.swing.dialog.DialogState;
import org.smallmind.swing.dialog.OptionButton;
import org.smallmind.swing.dialog.OptionDialog;
import org.smallmind.swing.dialog.OptionType;
import org.smallmind.swing.dialog.WarningDialog;
import org.smallmind.swing.dialog.YesNoDialog;
import org.smallmind.swing.panel.OptionPanel;
public class FileChooserPanel extends JPanel implements ComponentListener, MouseListener, KeyListener, ActionListener, ListSelectionListener, ListDataListener {
private static final ImageIcon NEW_FOLDER_ICON = new ImageIcon(ClassLoader.getSystemResource("org/smallmind/swing/system/folder_new_16.png"));
private static final ImageIcon EDIT_FOLDER_ICON = new ImageIcon(ClassLoader.getSystemResource("org/smallmind/swing/system/folder_edit_16.png"));
private final WeakEventListenerList listenerList = new WeakEventListenerList();
private final Window parentWindow;
private final FileChooserState state;
private final JTable directoryTable;
private final JList filePickList;
private final DirectoryTableModel directoryTableModel;
private final FilePickListModel filePickListModel;
private final JComboBox filterComboBox;
private final FilterComboBoxModel filterComboBoxModel;
private final JButton newFolderButton;
private final JButton editFolderButton;
private final JButton chooseButton;
private final JButton cancelButton;
private final JScrollPane directoryTableScrollPane;
private final JTextField fileNameTextField;
private final AtomicBoolean selectionSensitive = new AtomicBoolean(true);
private File chosenFile;
public FileChooserPanel (Window parentWindow, FileChooserState state) {
this(parentWindow, state, null, null);
}
public FileChooserPanel (Window parentWindow, FileChooserState state, File directory) {
this(parentWindow, state, directory, null);
}
public FileChooserPanel (Window parentWindow, FileChooserState state, File directory, FileFilter filter) {
super();
this.parentWindow = parentWindow;
this.state = state;
GroupLayout layout;
GroupLayout.SequentialGroup topBarSequentialGroup;
GroupLayout.SequentialGroup fileNameSequentialGroup;
GroupLayout.SequentialGroup buttonSequentialGroup;
GroupLayout.ParallelGroup topBarParallelGroup;
GroupLayout.ParallelGroup fileNameParallelGroup;
GroupLayout.ParallelGroup buttonParallelGroup;
DirectoryTableCellRenderer directoryTableCellRenderer;
JLabel fileLabel;
JLabel filterLabel;
JScrollPane filePickListScrollPane;
int directoryTableHeight;
int fileNameTextFieldHeight;
int fileLabelWidth;
int filterLabelWidth;
setLayout(layout = new GroupLayout(this));
newFolderButton = new JButton(NEW_FOLDER_ICON);
newFolderButton.setFocusable(false);
newFolderButton.setToolTipText("create a new folder");
newFolderButton.addActionListener(this);
editFolderButton = new JButton(EDIT_FOLDER_ICON);
editFolderButton.setDisabledIcon(new ImageIcon(SmallMindGrayFilter.createDisabledImage(EDIT_FOLDER_ICON.getImage())));
editFolderButton.setEnabled(false);
editFolderButton.setFocusable(false);
editFolderButton.setToolTipText("rename a document or folder");
editFolderButton.addActionListener(this);
chooseButton = new JButton(StringUtility.toDisplayCase(state.name(), '_'));
chooseButton.setFocusable(false);
chooseButton.addActionListener(this);
cancelButton = new JButton("Cancel");
cancelButton.setFocusable(false);
cancelButton.addActionListener(this);
filterComboBox = new JComboBox(filterComboBoxModel = new FilterComboBoxModel(filter));
filterComboBox.setEditable(false);
filterComboBox.setRenderer(new FilterListCellRenderer());
filterComboBox.setBackground(ColorUtility.TEXT_COLOR);
filterComboBox.setFocusable(false);
filterComboBox.addActionListener(this);
directoryTable = new JTable(directoryTableModel = new DirectoryTableModel(directory));
directoryTable.setDefaultRenderer(File.class, directoryTableCellRenderer = new DirectoryTableCellRenderer());
directoryTable.setShowGrid(false);
directoryTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
directoryTable.setFillsViewportHeight(true);
directoryTable.setAutoscrolls(false);
directoryTable.setRowSelectionAllowed(false);
directoryTable.setColumnSelectionAllowed(false);
directoryTable.setCellSelectionEnabled(true);
directoryTable.getColumnModel().setColumnMargin(0);
directoryTable.addComponentListener(this);
directoryTable.addMouseListener(this);
filePickList = new JList(filePickListModel = new FilePickListModel(directory, filter));
filePickList.setCellRenderer(new FilePickListCellRenderer());
filePickList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
filePickList.setLayoutOrientation(JList.VERTICAL_WRAP);
filePickList.addComponentListener(this);
filePickList.addMouseListener(this);
filePickList.addKeyListener(this);
filePickList.addListSelectionListener(this);
filePickListModel.addListDataListener(this);
fileNameTextField = new JTextField();
fileLabel = new JLabel("File:");
filterLabel = new JLabel("Filter:");
directoryTableHeight = (int)directoryTableCellRenderer.getTableCellRendererComponent(directoryTable, directoryTableModel.getValueAt(0, 0), false, false, 0, 0).getPreferredSize().getHeight();
directoryTable.setRowMargin((directoryTableHeight / 2) * -1);
fileNameTextFieldHeight = (int)fileNameTextField.getPreferredSize().getHeight() + 2;
fileLabelWidth = (int)fileLabel.getPreferredSize().getWidth();
filterLabelWidth = (int)filterLabel.getPreferredSize().getWidth();
directoryTableScrollPane = new JScrollPane(directoryTable, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
directoryTableScrollPane.getViewport().setBackground(directoryTable.getBackground());
directoryTableScrollPane.addComponentListener(this);
filePickListScrollPane = new JScrollPane(filePickList, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
layout.setAutoCreateContainerGaps(true);
topBarSequentialGroup = layout.createSequentialGroup().addComponent(directoryTableScrollPane).addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED).addComponent(newFolderButton).addPreferredGap(LayoutStyle.ComponentPlacement.RELATED).addComponent(editFolderButton);
topBarParallelGroup = layout.createParallelGroup().addComponent(directoryTableScrollPane, directoryTableHeight, directoryTableHeight, directoryTableHeight).addComponent(newFolderButton, directoryTableHeight, directoryTableHeight, directoryTableHeight).addComponent(editFolderButton, directoryTableHeight, directoryTableHeight, directoryTableHeight);
fileNameSequentialGroup = layout.createSequentialGroup().addComponent(fileLabel, fileLabelWidth, fileLabelWidth, fileLabelWidth).addPreferredGap(LayoutStyle.ComponentPlacement.RELATED).addComponent(fileNameTextField).addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED).addComponent(filterLabel, filterLabelWidth, filterLabelWidth, filterLabelWidth).addPreferredGap(LayoutStyle.ComponentPlacement.RELATED).addComponent(filterComboBox, 200, 200, 200);
fileNameParallelGroup = layout.createParallelGroup().addComponent(fileLabel, fileNameTextFieldHeight, fileNameTextFieldHeight, fileNameTextFieldHeight).addComponent(fileNameTextField, fileNameTextFieldHeight, fileNameTextFieldHeight, fileNameTextFieldHeight).addComponent(filterLabel, fileNameTextFieldHeight, fileNameTextFieldHeight, fileNameTextFieldHeight).addComponent(filterComboBox, fileNameTextFieldHeight, fileNameTextFieldHeight, fileNameTextFieldHeight);
buttonSequentialGroup = layout.createSequentialGroup().addComponent(chooseButton).addPreferredGap(LayoutStyle.ComponentPlacement.RELATED).addComponent(cancelButton);
buttonParallelGroup = layout.createParallelGroup().addComponent(chooseButton).addComponent(cancelButton);
layout.setHorizontalGroup(layout.createParallelGroup(GroupLayout.Alignment.TRAILING).addGroup(topBarSequentialGroup).addComponent(filePickListScrollPane).addGroup(fileNameSequentialGroup).addGroup(buttonSequentialGroup));
layout.setVerticalGroup(layout.createSequentialGroup().addGroup(topBarParallelGroup).addPreferredGap(LayoutStyle.ComponentPlacement.RELATED).addComponent(filePickListScrollPane).addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED).addGroup(fileNameParallelGroup).addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED).addGroup(buttonParallelGroup));
}
public File getChosenFile () {
return chosenFile;
}
public FileFilter getFilter () {
return filePickListModel.getFilter();
}
public void setFilter (FileFilter filter) {
filterComboBoxModel.setFilter(filter);
}
private void finishingTouches () {
File originallyChosenFile = chosenFile;
if ((chosenFile == null) && (fileNameTextField.getText() != null) && (fileNameTextField.getText().length() > 0)) {
chosenFile = new File(directoryTableModel.getDirectory(), fileNameTextField.getText());
}
if ((chosenFile != null) && (!chosenFile.getName().equals(fileNameTextField.getText().trim()))) {
if ((fileNameTextField.getText() == null) || (fileNameTextField.getText().length() == 0)) {
chosenFile = null;
} else if (fileNameTextField.getText().contains(System.getProperty("file.separator"))) {
chosenFile = new File(fileNameTextField.getText());
} else {
chosenFile = new File(chosenFile.getParentFile(), fileNameTextField.getText());
}
}
if (state.equals(FileChooserState.SAVE) && (chosenFile != null) && chosenFile.exists()) {
if (YesNoDialog.showYesNoDialog(parentWindow, OptionType.WARNING, chosenFile.getName() + " already exists. Overwrite the file?").equals(DialogState.YES)) {
fireFileChosen(new FileChoiceEvent(this, chosenFile));
} else {
chosenFile = originallyChosenFile;
}
} else {
fireFileChosen(new FileChoiceEvent(this, chosenFile));
}
}
@Override
public void intervalAdded (ListDataEvent listDataEvent) {
}
@Override
public void intervalRemoved (ListDataEvent listDataEvent) {
}
@Override
public void contentsChanged (ListDataEvent listDataEvent) {
if (filePickListModel.getSize() > 0) {
filePickList.scrollRectToVisible(filePickList.getCellBounds(0, 0));
}
}
@Override
public synchronized void valueChanged (ListSelectionEvent listSelectionEvent) {
if (selectionSensitive.get()) {
directoryTable.clearSelection();
editFolderButton.setEnabled(true);
if (!((File)filePickListModel.getElementAt(filePickList.getSelectedIndex())).isDirectory()) {
chosenFile = (File)filePickListModel.getElementAt(filePickList.getSelectedIndex());
fileNameTextField.setText(((File)filePickListModel.getElementAt(filePickList.getSelectedIndex())).getName());
} else {
chosenFile = null;
fileNameTextField.setText("");
}
}
}
@Override
public void actionPerformed (ActionEvent actionEvent) {
if ((actionEvent.getSource() == filterComboBox) && ((filterComboBox.getSelectedItem() != null) || (filePickListModel.getFilter() != null)) && (((filterComboBox.getSelectedItem() != null) && (!filterComboBox.getSelectedItem().equals(filePickListModel.getFilter()))) || ((filePickListModel.getFilter() != null) && (!filePickListModel.getFilter().equals(filterComboBox.getSelectedItem()))))) {
selectionSensitive.set(false);
filePickList.clearSelection();
selectionSensitive.set(true);
filePickListModel.setFilter((FileFilter)filterComboBox.getSelectedItem());
chosenFile = null;
fileNameTextField.setText("");
} else if (actionEvent.getSource() == newFolderButton) {
boolean success;
int count = 0;
do {
success = new File(directoryTableModel.getDirectory(), (count == 0) ? "New file" : "New file (" + count + ")").mkdir();
count++;
} while (!success);
filePickListModel.setDirectory(filePickListModel.getDirectory());
} else if (actionEvent.getSource() == editFolderButton) {
final File selectedFile = (File)filePickList.getSelectedValue();
final JTextField renameTextField = new JTextField(selectedFile.getName());
OptionDialog renameDialog;
OptionPanel renamePanel = new OptionPanel(new BorderLayout()) {
@Override
public String validateOption (DialogState dialogState) {
if (dialogState.equals(DialogState.APPLY) && (!renameTextField.getText().trim().equals(selectedFile.getName()))) {
if ((renameTextField.getText() == null) || (renameTextField.getText().trim().length() == 0)) {
return "You need to fill in a name";
}
if (new File(selectedFile.getParentFile(), renameTextField.getText().trim()).exists()) {
return "That name is already in use";
}
if (selectedFile.renameTo(new File(selectedFile.getParentFile(), renameTextField.getText().trim()))) {
selectionSensitive.set(false);
filePickList.clearSelection();
selectionSensitive.set(true);
if (!selectedFile.isDirectory()) {
chosenFile = null;
fileNameTextField.setText("");
}
filePickListModel.setDirectory(filePickListModel.getDirectory());
}
}
return null;
}
};
renamePanel.add(renameTextField);
renameTextField.setColumns(25);
renameDialog = new OptionDialog(parentWindow, "Rename " + (((File)filePickList.getSelectedValue()).isDirectory() ? "folder" : "document") + "...", OptionType.QUESTION, new OptionButton[] {new OptionButton("Apply", DialogState.APPLY), new OptionButton("Cancel", DialogState.CANCEL)}, renamePanel);
renameDialog.setModal(true);
renameDialog.setVisible(true);
} else if (actionEvent.getSource() == chooseButton) {
finishingTouches();
} else if (actionEvent.getSource() == cancelButton) {
fireFileChosen(new FileChoiceEvent(this, null));
}
}
@Override
public void keyTyped (KeyEvent keyEvent) {
}
@Override
public void keyPressed (KeyEvent keyEvent) {
}
@Override
public void keyReleased (KeyEvent keyEvent) {
int selectedIndex;
if ((keyEvent.getKeyCode() == KeyEvent.VK_DELETE) && (keyEvent.getModifiers() == 0) && ((selectedIndex = filePickList.getSelectedIndex()) >= 0)) {
File vanishingFile;
if (((vanishingFile = (File)filePickListModel.getElementAt(selectedIndex)).isDirectory()) && (vanishingFile.listFiles().length > 0)) {
WarningDialog.showWarningDialog(parentWindow, "Directories must be empty before deletion");
} else if (vanishingFile.delete()) {
fileNameTextField.setText("");
filePickListModel.setDirectory(filePickListModel.getDirectory());
if (filePickListModel.getSize() == 0) {
editFolderButton.setEnabled(false);
}
}
}
}
@Override
public void mouseClicked (MouseEvent mouseEvent) {
Object selectedValue;
if (mouseEvent.getSource() == directoryTable) {
selectionSensitive.set(false);
filePickList.clearSelection();
selectionSensitive.set(true);
editFolderButton.setEnabled(false);
chosenFile = null;
fileNameTextField.setText("");
if ((mouseEvent.getButton() == MouseEvent.BUTTON1) && (mouseEvent.getClickCount() == 2) && (directoryTable.getSelectedColumn() < directoryTableModel.getColumnCount() - 1)) {
File directory = (File)directoryTableModel.getValueAt(0, directoryTable.getSelectedColumn());
directoryTableModel.setDirectory(directory);
directoryTable.createDefaultColumnsFromModel();
filePickListModel.setDirectory(directory);
}
} else if (mouseEvent.getSource() == filePickList) {
if ((mouseEvent.getButton() == MouseEvent.BUTTON1) && (mouseEvent.getClickCount() == 2) && ((selectedValue = filePickList.getSelectedValue()) != null)) {
selectionSensitive.set(false);
filePickList.clearSelection();
selectionSensitive.set(true);
if (((File)selectedValue).isDirectory()) {
directoryTableModel.setDirectory((File)selectedValue);
directoryTable.createDefaultColumnsFromModel();
filePickListModel.setDirectory((File)selectedValue);
editFolderButton.setEnabled(false);
chosenFile = null;
fileNameTextField.setText("");
} else {
finishingTouches();
}
}
}
}
@Override
public void mousePressed (MouseEvent mouseEvent) {
}
@Override
public void mouseReleased (MouseEvent mouseEvent) {
}
@Override
public void mouseEntered (MouseEvent mouseEvent) {
}
@Override
public void mouseExited (MouseEvent mouseEvent) {
}
@Override
public void componentResized (ComponentEvent componentEvent) {
if ((componentEvent.getSource() == directoryTable) || (componentEvent.getSource() == directoryTableScrollPane)) {
directoryTable.scrollRectToVisible(directoryTable.getCellRect(0, directoryTableModel.getColumnCount() - 1, true));
} else if (componentEvent.getSource() == filePickList) {
filePickList.setVisibleRowCount(Math.max(10, (int)(filePickList.getVisibleRect().getHeight() / ((FilePickListCellRenderer)filePickList.getCellRenderer()).getRowHeight())));
}
}
@Override
public void componentMoved (ComponentEvent componentEvent) {
}
@Override
public void componentShown (ComponentEvent componentEvent) {
}
@Override
public void componentHidden (ComponentEvent componentEvent) {
}
private void fireFileChosen (FileChoiceEvent fileChoiceEvent) {
for (FileChoiceListener fileChoiceListener : listenerList) {
fileChoiceListener.fileChosen(fileChoiceEvent);
}
}
public synchronized void addFileChoiceListener (FileChoiceListener fileChoiceListener) {
listenerList.addListener(fileChoiceListener);
}
public synchronized void removeFileChoiceListener (FileChoiceListener fileChoiceListener) {
listenerList.removeListener(fileChoiceListener);
}
}