/**
*#########################################################################
*
* A component of the Gatherer application, part of the Greenstone digital
* library suite from the New Zealand Digital Library Project at the
* University of Waikato, New Zealand.
*
*
*
* Author: John Thompson, Greenstone Digital Library, University of Waikato
*
*
*
* Copyright (C) 1999 New Zealand Digital Library Project
*
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
*
*
* This program 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 for more details.
*
*
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*########################################################################
*/
package org.greenstone.gatherer.gui;
import java.awt.*;
import java.awt.event.*;
import java.io.File;
import java.util.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.filechooser.*;
import javax.swing.table.*;
import org.greenstone.gatherer.Configuration;
import org.greenstone.gatherer.Dictionary;
import org.greenstone.gatherer.Gatherer;
import org.greenstone.gatherer.file.FileAssociationManager;
import org.greenstone.gatherer.util.TableUtils;
import org.greenstone.gatherer.util.Utility;
/** The file association allows the entry of new file associations and the modification of existing ones.
* @author John Thompson, Greenstone Digital Library, University of Waikato
* @version 2.3
*/
public class FileAssociationDialog
extends ModalDialog {
/** The default size for the dialog. */
static final private Dimension SIZE = new Dimension(600, 450);
private boolean ignore = false;
private FileAssociationDialog self;
private FileAssociationManager file_association_manager;
private JButton add_button;
private JButton browse_button;
private JButton close_button;
private JButton remove_button;
private JButton replace_button;
private JTable existing_associations_table;
private JTextField command_field;
private JTextField extension_field;
/** Create a new file association dialog.
* @param file_association_manager A reference to the FileAssociationManager so we can determine what extensions are already associated.
*/
public FileAssociationDialog(FileAssociationManager file_association_manager) {
super(Gatherer.g_man);
this.file_association_manager = file_association_manager;
this.self = this;
this.setComponentOrientation(Dictionary.getOrientation());
// Creation
setModal(true);
setSize(SIZE);
setTitle(Dictionary.get("FileAssociationDialog.Title"));
setJMenuBar(new SimpleMenuBar("fileassociations"));
JPanel content_pane = (JPanel) getContentPane();
content_pane.setBackground(Configuration.getColor("coloring.collection_heading_background", false));
content_pane.setComponentOrientation(Dictionary.getOrientation());
JTextArea instructions_area = new JTextArea(Dictionary.get("FileAssociationDialog.Instructions"));
instructions_area.setEditable(false);
instructions_area.setLineWrap(true);
instructions_area.setRows(5);
instructions_area.setWrapStyleWord(true);
instructions_area.setComponentOrientation(Dictionary.getOrientation());
JPanel control_pane = new JPanel();
control_pane.setComponentOrientation(Dictionary.getOrientation());
existing_associations_table = new JTable(file_association_manager);
existing_associations_table.setComponentOrientation(Dictionary.getOrientation());
existing_associations_table.setAutoResizeMode(JTable.AUTO_RESIZE_NEXT_COLUMN);
existing_associations_table.setColumnSelectionAllowed(false);
existing_associations_table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
JPanel lower_pane = new JPanel();
lower_pane.setComponentOrientation(Dictionary.getOrientation());
JPanel details_pane = new JPanel();
details_pane.setComponentOrientation(Dictionary.getOrientation());
JPanel extension_pane = new JPanel();
extension_pane.setComponentOrientation(Dictionary.getOrientation());
JLabel extension_label = new JLabel(Dictionary.get("FileAssociationDialog.Extension"));
extension_label.setComponentOrientation(Dictionary.getOrientation());
extension_field = new NonWhitespaceField();
extension_field.setToolTipText(Dictionary.get("FileAssociationDialog.Extension_Tooltip"));
JLabel command_label = new JLabel(Dictionary.get("FileAssociationDialog.Command"));
command_label.setComponentOrientation(Dictionary.getOrientation());
JPanel command_pane = new JPanel();
command_pane.setComponentOrientation(Dictionary.getOrientation());
command_field = new JTextField();
command_field.setComponentOrientation(Dictionary.getOrientation());
command_field.setToolTipText(Dictionary.get("FileAssociationDialog.Command_Tooltip"));
browse_button = new GLIButton(Dictionary.get("FileAssociationDialog.Browse"));
browse_button.setEnabled(!Utility.isMac());
if (Utility.isMac()) {
browse_button.setToolTipText(Dictionary.get("FileAssociationDialog.Browse_Tooltip_Mac"));
} else {
browse_button.setToolTipText(Dictionary.get("FileAssociationDialog.Browse_Tooltip"));
}
JPanel button_pane = new JPanel();
button_pane.setComponentOrientation(Dictionary.getOrientation());
add_button = new GLIButton(Dictionary.get("FileAssociationDialog.Add"), Dictionary.get("FileAssociationDialog.Add_Tooltip"));
add_button.setEnabled(false);
replace_button = new GLIButton(Dictionary.get("FileAssociationDialog.Replace"), Dictionary.get("FileAssociationDialog.Replace_Tooltip"));
replace_button.setEnabled(false);
remove_button = new GLIButton(Dictionary.get("FileAssociationDialog.Remove"), Dictionary.get("FileAssociationDialog.Remove_Tooltip"));
remove_button.setEnabled(false);
close_button = new GLIButton(Dictionary.get("FileAssociationDialog.Close"), Dictionary.get("FileAssociationDialog.Close_Tooltip"));
// Connection
add_button.addActionListener(new AddButtonListener());
browse_button.addActionListener(new BrowseButtonListener());
close_button.addActionListener(new CloseButtonListener());
remove_button.addActionListener(new RemoveButtonListener());
replace_button.addActionListener(new ReplaceButtonListener());
CommandOrExtensionFieldListener coefl = new CommandOrExtensionFieldListener();
command_field.getDocument().addDocumentListener(coefl);
extension_field.getDocument().addDocumentListener(coefl);
coefl = null;
existing_associations_table.getSelectionModel().addListSelectionListener(new ExistingAssociationsTableListener());
// Layout
extension_pane.setBorder(BorderFactory.createEmptyBorder(2,0,2,0));
extension_pane.setLayout(new BorderLayout(5,0));
extension_pane.add(extension_label, BorderLayout.LINE_START);
extension_pane.add(extension_field, BorderLayout.CENTER);
command_pane.setBorder(BorderFactory.createEmptyBorder(2,0,2,0));
command_pane.setLayout(new BorderLayout());
command_pane.add(command_field, BorderLayout.CENTER);
command_pane.add(browse_button, BorderLayout.LINE_END);
details_pane.setBorder(BorderFactory.createTitledBorder(Dictionary.get("FileAssociationDialog.Details")));
details_pane.setLayout(new GridLayout(3,1));
details_pane.add(extension_pane);
details_pane.add(command_label);
details_pane.add(command_pane);
lower_pane.setBorder(BorderFactory.createEmptyBorder(2,0,0,0));
button_pane.setLayout(new GridLayout(2,3));
button_pane.add(add_button);
button_pane.add(replace_button);
button_pane.add(remove_button);
JPanel tmp ;
tmp = new JPanel();
tmp.setComponentOrientation(Dictionary.getOrientation());
button_pane.add(tmp);
tmp = new JPanel();
tmp.setComponentOrientation(Dictionary.getOrientation());
button_pane.add(tmp);
button_pane.add(close_button);
lower_pane.setBorder(BorderFactory.createEmptyBorder(2,0,0,0));
lower_pane.setLayout(new BorderLayout());
lower_pane.add(details_pane, BorderLayout.CENTER);
lower_pane.add(button_pane, BorderLayout.SOUTH);
control_pane.setBorder(BorderFactory.createEmptyBorder(5,0,0,0));
control_pane.setLayout(new BorderLayout());
JScrollPane scrol_tmp;
scrol_tmp = new JScrollPane(existing_associations_table);
scrol_tmp.setComponentOrientation(Dictionary.getOrientation());
control_pane.add(scrol_tmp, BorderLayout.CENTER);
control_pane.add(lower_pane, BorderLayout.SOUTH);
content_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
content_pane.setLayout(new BorderLayout());
scrol_tmp = new JScrollPane(instructions_area);
scrol_tmp.setComponentOrientation(Dictionary.getOrientation());
content_pane.add(scrol_tmp, BorderLayout.NORTH);
content_pane.add(control_pane, BorderLayout.CENTER);
Rectangle screen = Gatherer.g_man.getBounds(null);
setLocation((int)(screen.getX() + (screen.getWidth() - SIZE.width) / 2), (int)(screen.getY() + (screen.getHeight() - SIZE.height) / 2));
screen = null;
}
public void destroy() {
// Disconnect
// Clean up
file_association_manager = null;
self = null;
}
/** Redisplay the dialog, ensuring that the details (or lack thereof) for a certain extension is apparent. In fact if an extension is provided force the user to add it or cancel.
* @param new_extension The extension code as a String.
*/
public String display(String new_extension) {
// Clear the current selection
existing_associations_table.clearSelection();
if(new_extension != null) {
extension_field.setText(new_extension);
}
setVisible(true);
if(new_extension != null) {
return file_association_manager.getCommandString(new_extension);
}
return null;
}
protected void processWindowEvent(WindowEvent event) {
if(event.getID() == WindowEvent.WINDOW_ACTIVATED) {
TableUtils.fixColumnToPreferredWidth(existing_associations_table, 0);
}
else {
super.processWindowEvent(event);
}
}
private class AddButtonListener
implements ActionListener {
public void actionPerformed(ActionEvent event) {
String extension_str = extension_field.getText();
file_association_manager.setCommand(extension_str, command_field.getText());
// Select the appropriate entry in the table
int index = -1;
for(int i = 0; index == -1 && i < file_association_manager.size(); i++) {
if(file_association_manager.getExtension(i).equals(extension_str)) {
index = i;
}
}
if(index > -1) {
existing_associations_table.setRowSelectionInterval(index, index);
}
// And update buttons
add_button.setEnabled(false);
remove_button.setEnabled(true);
}
}
/** Batch filter shows only files ending in bat. Based on ImageFilter.java which is a 1.4 example used by FileChooserDemo2.java. */
private class BatchFileFilter
extends FileFilter {
/** Accept all .exe files
* @param file a File
* @return true is this file should be shown, false otherwise
*/
public boolean accept(File file) {
return file.getName().toLowerCase().endsWith(".bat");
}
/** The description of this filter
* @return a String
*/
public String getDescription() {
return Dictionary.get("FileAssociationDialog.Batch_File");
}
}
/** Whenever the user clicks the browse button, we should open up a file browser to allow them to select an executable file from somewhere in the file system. */
private class BrowseButtonListener
implements ActionListener {
/** Open up a simple JFileChooser when the user clicks the button.
* @param event An ActionEvent containing information about the event.
*/
public void actionPerformed(ActionEvent event) {
JFileChooser chooser = new JFileChooser(new File(Gatherer.getGLIUserDirectoryPath()));
GUIUtils.disableRename(chooser);
chooser.setDialogTitle(Dictionary.get("FileAssociationDialog.Browse_Title"));
chooser.setFileFilter(new BatchFileFilter());
chooser.setFileFilter(new CoreObjectModelFileFilter());
chooser.setFileFilter(new ExecutableFileFilter());
chooser.setAcceptAllFileFilterUsed(true);
if(chooser.showOpenDialog(Gatherer.g_man) == JFileChooser.APPROVE_OPTION) {
command_field.setText(chooser.getSelectedFile().getAbsolutePath());
}
}
}
private class CloseButtonListener
implements ActionListener {
public void actionPerformed(ActionEvent event) {
existing_associations_table.clearSelection();
add_button.setEnabled(false);
remove_button.setEnabled(false);
replace_button.setEnabled(false);
self.dispose();
}
}
/** Command filter shows only files ending in com. Based on ImageFilter.java which is a 1.4 example used by FileChooserDemo2.java. */
private class CoreObjectModelFileFilter
extends FileFilter {
/** Accept all .exe files
* @param file a File
* @return true is this file should be shown, false otherwise
*/
public boolean accept(File file) {
return file.getName().toLowerCase().endsWith(".com");
}
/** The description of this filter
* @return a String
*/
public String getDescription() {
return Dictionary.get("FileAssociationDialog.Command_File");
}
}
private class CommandOrExtensionFieldListener
implements DocumentListener {
/** Gives notification that an attribute or set of attributes changed. */
public void changedUpdate(DocumentEvent e) {
changed();
}
/** Gives notification that there was an insert into the document. */
public void insertUpdate(DocumentEvent e) {
changed();
}
/** Gives notification that a portion of the document has been removed. */
public void removeUpdate(DocumentEvent e) {
changed();
}
private void changed() {
ignore = true;
String extension_str = extension_field.getText();
String command_str = command_field.getText();
// Determine if there is currently an association selected
int selected_index = -1;
if((selected_index = existing_associations_table.getSelectionModel().getMinSelectionIndex()) != -1) {
String current_extension_str = file_association_manager.getExtension(selected_index);
String current_command_str = file_association_manager.getCommandString(current_extension_str);
// What buttons are enabled depends a lot on the file extension, taken to be the 'key'
if(extension_str.equals(current_extension_str)) {
// If the extensions are the same then remove is enabled
remove_button.setEnabled(true);
// But if the command is different, then enable replace
if(current_command_str.length() == 0) {
add_button.setEnabled(true);
replace_button.setEnabled(false);
}
else if(!command_str.equals(current_command_str)) {
add_button.setEnabled(false);
replace_button.setEnabled(true);
}
else {
add_button.setEnabled(false);
replace_button.setEnabled(false);
}
}
// We can add it, but we first clear the selection
else {
existing_associations_table.clearSelection();
add_button.setEnabled(true);
remove_button.setEnabled(false);
replace_button.setEnabled(false);
}
}
// If not, we must first test if the extension is in use
else {
int index = -1;
for(int i = 0; index == -1 && i < file_association_manager.size(); i++) {
String existing_extension_str = file_association_manager.getExtension(i);
if(existing_extension_str.equals(extension_str)) {
index = i;
}
}
if(index != -1) {
// Selection that index
existing_associations_table.setRowSelectionInterval(index, index);
// Set replace and remove enabled
add_button.setEnabled(false);
remove_button.setEnabled(true);
replace_button.setEnabled(true);
}
// Otherwise if there is some text in both extension and command, enable add only
else if(extension_str.length() > 0 && command_str.length() > 0) {
add_button.setEnabled(true);
remove_button.setEnabled(false);
replace_button.setEnabled(false);
}
// Otherwise disable everything
else {
add_button.setEnabled(false);
remove_button.setEnabled(false);
replace_button.setEnabled(false);
}
}
ignore = false;
}
}
/** Executable filter shows only files ending in exe. Based on ImageFilter.java which is a 1.4 example used by FileChooserDemo2.java. */
private class ExecutableFileFilter
extends FileFilter {
/** Accept all .exe files
* @param file a File
* @return true is this file should be shown, false otherwise
*/
public boolean accept(File file) {
return file.getName().toLowerCase().endsWith(".exe");
}
/** The description of this filter
* @return a String
*/
public String getDescription() {
return Dictionary.get("FileAssociationDialog.Executable_File");
}
}
private class ExistingAssociationsTableListener
implements ListSelectionListener {
public void valueChanged(ListSelectionEvent event) {
if(!event.getValueIsAdjusting() && !ignore) {
int selected_index = -1;
if((selected_index = existing_associations_table.getSelectionModel().getMinSelectionIndex()) != -1) {
// Propagate the details of the selection down into the fields
String extension_str = file_association_manager.getExtension(selected_index);
extension_field.setText(extension_str);
command_field.setText(file_association_manager.getCommandString(extension_str));
extension_str = null;
remove_button.setEnabled(true);
}
else {
// Clear the fields
extension_field.setText("");
command_field.setText("");
remove_button.setEnabled(false);
}
add_button.setEnabled(false);
replace_button.setEnabled(false);
}
}
}
private class RemoveButtonListener
implements ActionListener {
public void actionPerformed(ActionEvent event) {
file_association_manager.setCommand(extension_field.getText(), null);
// And update buttons
add_button.setEnabled(true);
remove_button.setEnabled(false);
}
}
private class ReplaceButtonListener
implements ActionListener {
public void actionPerformed(ActionEvent event) {
file_association_manager.setCommand(extension_field.getText(), command_field.getText());
// And update buttons
replace_button.setEnabled(false);
}
}
}