/*
* XNap
*
* A pure java file sharing client.
*
* See AUTHORS for copyright information.
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package xnap.gui;
import xnap.*;
import xnap.gui.action.CopyFileAction;
import xnap.gui.action.CutFileAction;
import xnap.gui.action.PasteFileAction;
import xnap.gui.action.OpenFileWithMenu;
import xnap.gui.event.*;
import xnap.gui.table.*;
import xnap.gui.tree.*;
import xnap.plugin.*;
import xnap.util.*;
import xnap.util.event.StateEvent;
import xnap.util.event.StateListener;
import xnap.util.audio.*;
import xnap.io.*;
import java.awt.*;
import java.awt.event.*;
import java.beans.*;
import java.util.*;
import java.io.*;
import java.net.*;
import java.text.MessageFormat;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.event.*;
import javax.swing.table.*;
import javax.swing.tree.*;
public class LibraryPanel extends AbstractPanel
implements PropertyChangeListener, TreeSelectionListener,
ListSelectionListener, DirectoryCollector, FileCollector {
//--- Constant(s) ---
public static final String HISTORY_FILENAME
= FileHelper.getHomeDir() + "repository_search_history";
//--- Data field(s) ---
private AudioPlayer player = null;
private EditableComboBox jcSearch;
private JTree jt;
private JTable jta;
private JFileChooser jfc = null;
private LibraryTableModel ltm;
private DefaultMutableTreeNode root;
private FileTreeModel ftm;
private DragFilesSupport dfs;
private JSplitPane jspH;
private JSplitPane jspV;
// preview
private JPanel jpPreview;
private JScrollPane jspPreview;
private JLabel jlStatus;
private PlayAction playAction = new PlayAction();
private PlayFileAction playFileAction = new PlayFileAction();
private RefreshAction refreshAction = new RefreshAction();
private StopAction stopAction = new StopAction();
private EnqueueAction enqueueAction = new EnqueueAction();
private PlayFolderAction playFolderAction = new PlayFolderAction();
private EnqueueFolderAction enqueueFolderAction = new EnqueueFolderAction();
private OpenFileAction acOpenFile = new OpenFileAction(this);
private ShareFolderAction shareFolderAction = new ShareFolderAction();
private UnshareFolderAction unshareFolderAction = new UnshareFolderAction();
private ReloadTreeAction acReloadTree = new ReloadTreeAction();
private DeleteAction deleteAction = new DeleteAction();
private RenameAction renameAction = new RenameAction();
private CopyFileAction acCopyFile = new CopyFileAction(this);
private CutFileAction acCutFile = new CutFileAction(this);
private PasteFileAction acPasteFile = new PasteFileAction(this);
private File currentDir;
private int currentRow;
private javax.swing.Timer delayTimer;
private DisplayThread displayThread = new DisplayThread();
//--- Constructor(s) ---
public LibraryPanel()
{
initialize();
}
//--- Method(s) ---
private void initialize()
{
// search panel
Box boxOne = new Box(BoxLayout.X_AXIS);
QueryAction acQuery = new QueryAction();
EraseAction acErase = new EraseAction();
JButton jbErase = new JButton(acErase);
jbErase.setMargin(new Insets(1, 1, 1, 1));
boxOne.add(jbErase);
jcSearch = new EditableComboBox(acQuery, prefs.getSearchHistorySize());
jcSearch.readHistoryFile(new File(HISTORY_FILENAME));
boxOne.add(jcSearch);
acErase.setJTextField(jcSearch.getJTextField());
JButton jbQuery = new JButton(acQuery);
boxOne.add(jbQuery);
JPanel jpTop = new JPanel(new BorderLayout());
jpTop.setBorder(new TitledBorder(XNap.tr("Library Search", 1)));
jpTop.add(boxOne, "Center");
/* tree context menu */
JPopupMenu treePopup = new JPopupMenu();
treePopup.add(new JMenuItem(playFolderAction));
treePopup.add(new JMenuItem(enqueueFolderAction));
treePopup.addSeparator();
treePopup.add(new JMenuItem(shareFolderAction));
treePopup.add(new JMenuItem(unshareFolderAction));
treePopup.addSeparator();
treePopup.add(acPasteFile);
treePopup.addSeparator();
treePopup.add(new JMenuItem(acReloadTree));
/* tree */
ftm = new FileTreeModel(XNap.tr("Files"));
// jt = new JTree(ftm);
jt = new DroppableJTree(ftm, this);
jt.addTreeSelectionListener(this);
jt.setCellRenderer(new FileCellRenderer());
jt.putClientProperty("JTree.lineStyle", "Angled");
MouseListener treePopupListener = new PopupListener(treePopup);
jt.addMouseListener(treePopupListener);
/* allow multiple selections in tree */
jt.getSelectionModel().setSelectionMode
(TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION);
JScrollPane jspTree = new JScrollPane();
jspTree.setViewportView(jt);
/* table context menu */
JPopupMenu popup = new JPopupMenu();
popup.add(new JMenuItem(playAction));
popup.add(new JMenuItem(enqueueAction));
popup.addSeparator();
popup.add(new JMenuItem(acOpenFile));
popup.add(new OpenFileWithMenu(this));
popup.addSeparator();
popup.add(createViewerMenu());
popup.addSeparator();
popup.add(acCopyFile);
popup.add(acCutFile);
popup.add(acPasteFile);
popup.addSeparator();
popup.add(renameAction);
popup.add(deleteAction);
/* table */
ltm = new LibraryTableModel();
jta = ltm.createJTable();
dfs = new DragFilesSupport(jta, this);
jta.getSelectionModel().addListSelectionListener(this);
jta.setShowGrid(false);
MouseListener popupListener = new PopupListener(popup);
jta.addMouseListener(popupListener);
jta.addMouseListener(new DoubleClickListener(acOpenFile, jta));
/* set up Emacs keybindings for move actions */
ActionListener al =
jta.getActionForKeyStroke(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN,
0));
jta.registerKeyboardAction
(al,KeyStroke.getKeyStroke(KeyEvent.VK_N, InputEvent.CTRL_MASK),
WHEN_FOCUSED);
al = jta.getActionForKeyStroke(KeyStroke.getKeyStroke(KeyEvent.VK_UP,
0));
jta.registerKeyboardAction
(al, KeyStroke.getKeyStroke(KeyEvent.VK_P, InputEvent.CTRL_MASK),
WHEN_FOCUSED);
al = jta.getActionForKeyStroke
(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_DOWN, 0));
jta.registerKeyboardAction
(al, KeyStroke.getKeyStroke(KeyEvent.VK_V, InputEvent.CTRL_MASK),
WHEN_FOCUSED);
al = jta.getActionForKeyStroke
(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_UP, 0));
jta.registerKeyboardAction
(al, KeyStroke.getKeyStroke(KeyEvent.VK_V, InputEvent.ALT_MASK),
WHEN_FOCUSED);
al = jta.getActionForKeyStroke
(KeyStroke.getKeyStroke(KeyEvent.VK_HOME, InputEvent.CTRL_MASK));
jta.registerKeyboardAction
(al, KeyStroke.getKeyStroke(KeyEvent.VK_LESS, InputEvent.ALT_MASK),
WHEN_FOCUSED);
al = jta.getActionForKeyStroke
(KeyStroke.getKeyStroke(KeyEvent.VK_END, InputEvent.CTRL_MASK));
jta.registerKeyboardAction
(al, KeyStroke.getKeyStroke(KeyEvent.VK_LESS, InputEvent.ALT_MASK
+ InputEvent.SHIFT_MASK),
WHEN_FOCUSED);
jta.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0),
acOpenFile);
jta.getActionMap().put(acOpenFile, acOpenFile);
jta.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_F5, 0),
refreshAction);
jta.getActionMap().put(refreshAction, refreshAction);
jta.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0),
deleteAction);
jta.getActionMap().put(deleteAction, deleteAction);
jta.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_F2, 0),
renameAction);
jta.getActionMap().put(renameAction, renameAction);
jta.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_Q, 0),
enqueueAction);
jta.getActionMap().put(enqueueAction, enqueueAction);
JScrollPane jspTable = new JScrollPane();
jspTable.setViewportView(jta);
/* selection delay, which ensures the user really wants the plugin to
be activated. */
delayTimer = new javax.swing.Timer(500, new SelectionListener());
delayTimer.setRepeats(false);
/* preview pane */
jpPreview = new JPanel(new BorderLayout());
jpPreview.setBackground(Color.gray);
jspPreview = new JScrollPane(jpPreview);
al = jspPreview.getActionForKeyStroke
(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_DOWN, 0));
jspPreview.registerKeyboardAction
(al, KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, KeyEvent.CTRL_MASK),
WHEN_IN_FOCUSED_WINDOW);
al = jspPreview.getActionForKeyStroke
(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_UP, 0));
jspPreview.registerKeyboardAction
(al, KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, KeyEvent.CTRL_MASK
| KeyEvent.SHIFT_MASK),
WHEN_IN_FOCUSED_WINDOW);
/* split panels */
jspV = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
jspV.add(jspTable, JSplitPane.TOP);
jspV.add(jspPreview, JSplitPane.BOTTOM);
jspV.setDividerLocation(prefs.getLibraryVerticalDividerLocation());
jspV.setOneTouchExpandable(true);
jlStatus = new JLabel(" ");
JPanel jpV = new JPanel(new BorderLayout());
jpV.add(jspV, "Center");
jpV.add(jlStatus, "South");
jspH = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
jspH.add(jspTree, JSplitPane.LEFT);
jspH.add(jpV, JSplitPane.RIGHT);
jspH.setDividerLocation(prefs.getLibraryHorizontalDividerLocation());
jspH.setOneTouchExpandable(true);
/* content */
setLayout(new BorderLayout());
add(jpTop, BorderLayout.NORTH);
add(jspH, BorderLayout.CENTER);
// make sure we are set
updateAudioPlayer();
// show directories
updateTree();
// make sure we are notified when the downloadDir changes
prefs.addPropertyChangeListener(this);
}
/**
* Lazy instantiation.
*/
public JFileChooser getFileChooser()
{
if (jfc == null) {
jfc = new JFileChooser();
MP3FileFilter filter = new MP3FileFilter();
jfc.setFileFilter(filter);
}
return jfc;
}
public JMenu getTableMenu()
{
return ltm.createJMenu();
}
public void hasChanged(File directory)
{
if (currentDir != null) {
showDirectory(currentDir);
}
}
/**
* This hack sets the focus to jcSearch after the searchpanel has been
* activated. This only works for java 1.3 and the JTabbedPane and not for
* the IconSplitPane.
*/
// public void setVisible(boolean visible)
// {
// super.setVisible(visible);
// if (visible) {
// SwingUtilities.invokeLater(new Runnable()
// {
// public void run()
// {
// // System.out.println("swing invoke runnable");
// jcSearch.grabFocus();
// }
// });
// }
// }
public void purgeHistory()
{
jcSearch.removeAllItems();
}
public void propertyChange(PropertyChangeEvent e)
{
String p = e.getPropertyName();
if (e.getSource() == prefs) {
if (p.equals("incompleteDir")) {
ftm.removeChildrenOfSubRoot(XNap.tr("Incomplete Files"));
ftm.addChildOfSubRoot(new File(prefs.getIncompleteDir()),
XNap.tr("Incomplete Files"));
}
else if (p.equals("uploadDirs")) {
ftm.removeChildrenOfSubRoot(XNap.tr("Shared Files"));
String[] dirs = prefs.getUploadDirsArray();
for (int i = 0; i < dirs.length; i++) {
ftm.addChildOfSubRoot(new File(dirs[i]),
XNap.tr("Shared Files"));
}
}
else if (p.equals("mp3PlayerCmd") || p.equals("mp3PlayerType")) {
updateAudioPlayer();
}
else if (p.equals("downloadDir") || p.indexOf("DownloadDir")
!= -1) {
ftm.removeChildrenOfSubRoot(XNap.tr("Downloaded Files"));
addDownloadDirs();
}
}
}
public void savePrefs()
{
prefs.setLibraryHorizontalDividerLocation(jspH.getDividerLocation());
prefs.setLibraryVerticalDividerLocation(jspV.getDividerLocation());
jcSearch.setHistorySize(prefs.getSearchHistorySize());
jcSearch.writeHistoryFile(new File(HISTORY_FILENAME));
}
private void updateAudioPlayer()
{
player = AudioSupport.getInstance(prefs.getMP3PlayerType(),
prefs.getMP3PlayerCmd());
}
/**
* Clears the tree and adds a couple of nodes.
*/
private void updateTree()
{
ftm.removeSubRoots();
int failed = 0;
String[] nodes = prefs.getLibraryTreeNodesArray();
for (int j = 0; j < nodes.length; j++) {
if (nodes[j].equals("shares")) {
// add shares
ftm.addSubRoot(XNap.tr("Shared Files"));
String[] dirs = prefs.getUploadDirsArray();
for (int i = 0; i < dirs.length; i++) {
ftm.addChildOfSubRoot(new File(dirs[i]),
XNap.tr("Shared Files"));
}
jt.expandRow(jt.getRowCount() - 1);
}
else if (nodes[j].equals("incompletes")) {
// add incomplete dir
ftm.addChildOfSubRoot(new File(prefs.getIncompleteDir()),
XNap.tr("Incomplete Files"));
// ensure that the actual incomplete directory is viewable
jt.expandRow(jt.getRowCount() - 1);
}
else if (nodes[j].equals("downloads")) {
addDownloadDirs();
jt.expandRow(jt.getRowCount() - 1);
}
else if (nodes[j].equals("home")) {
ftm.addChildOfSubRoot(new File
(System.getProperty("user.home")), XNap.tr("Home Directory"));
jt.expandRow(jt.getRowCount() - 1);
}
else if (nodes[j].equals("root")) {
// add system roots
File[] roots = File.listRoots();
for (int i = 0; i < roots.length; i++) {
ftm.addChildOfSubRoot(roots[i], XNap.tr("Root Directory"));
}
jt.expandRow(jt.getRowCount() - 1);
}
else {
failed++;
}
}
if (failed == nodes.length) {
// always show at least system roots
ftm.addSubRoot(XNap.tr("Root Directory"));
File[] roots = File.listRoots();
for (int i = 0; i < roots.length; i++) {
ftm.addChildOfSubRoot(roots[i], XNap.tr("Root Directory"));
}
jt.expandRow(jt.getRowCount() - 1);
}
}
/**
* Adds the main download directory and all media type download
* directories which are set to the tree.
*/
private void addDownloadDirs()
{
// add download dir
ftm.addChildOfSubRoot(new File(prefs.getDownloadDir()),
XNap.tr("Downloaded Files"));
for (int i = 0; i < SearchFilter.media.length; i++) {
String type = (String)SearchFilter.media[i];
String dir = prefs.getMediaTypeDownloadDir(type);
if (i != SearchFilter.MEDIA_ANYTHING && dir.length() > 0) {
ftm.addChildOfSubRoot(new File(dir),
XNap.tr("Downloaded Files"),
" (" + type + ")");
}
}
}
private void showDirectory(File f)
{
currentDir = f;
ltm.clear();
// check if directory is readable by xnap user
if (f.canRead()) {
ltm.add(f);
ltm.resort();
}
resetPanel();
}
private void showFiles(File[] files)
{
ltm.clear();
ltm.add(files);
ltm.resort();
resetPanel();
}
/**
* Called when a new directory has been selected.
*/
public void valueChanged(TreeSelectionEvent e)
{
Object target = e.getPath().getLastPathComponent();
if (target instanceof File) {
File f = (File)target;
showDirectory(f);
}
}
/**
* Called when the table's selection changes, we check what kind of
* file was selected and call the respective viewer plugin if available.
*/
public void valueChanged(ListSelectionEvent e)
{
/* user is about to select some files, don't show anything */
if (jta.getSelectedRowCount() > 1) {
resetPanel();
return;
}
int row = jta.getSelectedRow();
if (row != -1) {
currentRow = row;
delayTimer.restart();
}
}
public AbstractAction[] getActions()
{
return (new AbstractAction[]
{
playFileAction, enqueueAction, playAction, stopAction, null,
refreshAction, null, shareFolderAction, unshareFolderAction
});
}
private void playFile(final File f)
{
if (player != null) {
(new Thread("PlayFile " + f) {
public void run()
{
boolean success;
if (f == null)
success = player.play();
else
success = player.play(f);
if (!success) {
if (f == null)
setStatus(XNap.tr("Could not start player"));
else
setStatus(XNap.tr("Could not play file", 0,
1) + f);
}
else if (f != null)
setStatus(XNap.tr("Playing", 0, 1) + f);
else
setStatus(XNap.tr("Starting player"));
}
}
).start();
}
else {
setStatus(XNap.tr("Could not launch player"));
}
}
private void enqueueFiles(final LinkedList files)
{
if (player != null) {
(new Thread("EnqueueFiles") {
public void run()
{
int size = files.size();
while (files.size() > 0) {
final File f = (File)files.removeFirst();
if (!player.enqueue(f))
setStatus(XNap.tr("Could not enqueue file") + f);
}
if (size > 0) {
setStatus(XNap.tr("Enqueued", 0, 1) + size
+ XNap.tr("file(s)", 1, 0));
}
}
}
).start();
}
else {
setStatus(XNap.tr("Could not launch audio player, please check your preferences"));
}
}
private void doPlay(int[] rows)
{
if (rows.length == 0) {
playFile(null);
}
else if (rows.length > 0 && player.canPlay(ltm.get(rows[0]))) {
playFile(ltm.get(rows[0]));
}
if (rows.length > 1) {
// if more than one file is selected the following files are
// enqueued to be played later on
LinkedList filestoEnqueue = new LinkedList();
for (int i = 1; i < rows.length; i++) {
if (player.canPlay(ltm.get(rows[i]))) {
filestoEnqueue.add(ltm.get(rows[i]));
}
}
enqueueFiles(filestoEnqueue);
}
}
public File getDirectory()
{
TreePath selected = jt.getSelectionPath();
if (selected != null) {
Object o = selected.getLastPathComponent();
if (o instanceof File) {
return (File)o;
}
}
return null;
}
public File[] getFiles(boolean showMessage)
{
int rowC = jta.getSelectedRowCount();
int rows[] = jta.getSelectedRows();
if (showMessage && rowC == 0) {
setStatus(XNap.tr("Please select something first"));
return null;
}
File[] files = new File[rowC];
for (int i = 0; i < rowC; i++) {
files[i] = ltm.get(rows[i]);
}
return files;
}
public File[] getFiles()
{
return getFiles(true);
}
/**
* displays given file if possible in lower preview frame
*/
private void displayFile(File f)
{
if (!f.canRead()) {
jspPreview.setViewportView(jpPreview);
jlStatus.setText(XNap.tr("Do not have permission to read file"));
return;
}
ViewerPanel panel
= GUIPluginManager.getGUIInstance().getViewer(f);
if (panel != null) {
jlStatus.setText(panel.getStatus());
displayThread.setPanel(panel);
}
else {
resetPanel();
}
}
public void resetPanel()
{
jspPreview.setViewportView(jpPreview);
updateStatus();
}
public int getHorizontalDividerLocation()
{
return jspH.getDividerLocation();
}
public void setHorizontalDividerLocation(int newValue)
{
if (newValue == -1) {
jspH.setDividerLocation(200);
}
else {
jspH.setDividerLocation(newValue);
}
}
public int getVerticalDividerLocation()
{
return jspV.getDividerLocation();
}
public void setVerticalDividerLocation(int newValue)
{
if (newValue == -1) {
jspV.setDividerLocation(200);
}
else {
jspV.setDividerLocation(newValue);
}
}
/**
* Updates the status line below the file table.
*/
public void updateStatus()
{
StringBuffer sb = new StringBuffer();
File[] files = getFiles(false);
if (files.length == 0) {
// nothing is selected
sb.append(ltm.getRowCount());
sb.append(" files - ");
sb.append(Formatter.formatSize(ltm.getTotalSize()));
}
else if (files.length == 1) {
sb.append("1 file - ");
sb.append(Formatter.formatNumber(files[0].length()) + " bytes");
}
else {
long totalSize = 0;
for (int i = 0; i < files.length; i++) {
totalSize += files[i].length();
}
sb.append("selected - ");
sb.append(files.length);
sb.append(" files - ");
sb.append(Formatter.formatSize(totalSize));
}
// FIX: we need some kind of padding
sb.insert(0, " ");
jlStatus.setText(sb.toString());
}
private JMenu createViewerMenu()
{
JMenu jm = new JMenu(XNap.tr("View with Plugin"));
jm.setIcon(XNapFrame.getEmptyIcon());
IPlugin[] plugins = PluginManager.getInstance().getPlugins();
for (int i = 0; i < plugins.length; i++) {
if (plugins[i] instanceof IViewerPlugin) {
jm.add(new ViewerAction((IViewerPlugin)plugins[i], this));
}
}
return jm;
}
/* inner classes */
private class ViewerAction extends AbstractAction implements StateListener
{
private IViewerPlugin plugin;
private FileCollector fc;
public ViewerAction(IViewerPlugin plugin, FileCollector fc)
{
this.plugin = plugin;
this.fc = fc;
putValue(Action.NAME, plugin.getName());
this.setEnabled(plugin.isEnabled());
GUIPluginManager.getInstance().addStateListener(this);
}
public void actionPerformed(ActionEvent event)
{
File[] files = fc.getFiles();
if (files != null && files.length > 0) {
ViewerPanel vp = plugin.handle(files[0]);
jlStatus.setText(vp.getStatus());
displayThread.setPanel(vp);
}
}
public void stateDisabled(StateEvent e)
{
if (plugin == e.getSource()) {
this.setEnabled(false);
}
}
public void stateEnabled(StateEvent e)
{
if (plugin == e.getSource()) {
this.setEnabled(true);
}
}
}
/**
* Plays a file selected via a FileOpenDialog
*/
private class PlayFileAction extends AbstractAction {
public PlayFileAction()
{
putValue(Action.NAME, XNap.tr("Play File"));
putValue(Action.SHORT_DESCRIPTION,
XNap.tr("Open a file to play"));
putValue(Action.SMALL_ICON, XNapFrame.getIcon("fileopen.png"));
putValue(Action.MNEMONIC_KEY, new Integer('O'));
}
public void actionPerformed(ActionEvent event)
{
if (getFileChooser().showOpenDialog(LibraryPanel.this)
== JFileChooser.APPROVE_OPTION) {
playFile(jfc.getSelectedFile());
}
}
}
/**
* Plays selected file
*/
private class PlayAction extends AbstractAction {
public PlayAction()
{
putValue(Action.NAME, XNap.tr("Play"));
putValue(Action.SHORT_DESCRIPTION,
XNap.tr("Plays selected file(s)"));
putValue(Action.SMALL_ICON, XNapFrame.getIcon("1rightarrow.png"));
putValue(Action.MNEMONIC_KEY, new Integer('P'));
}
public void actionPerformed(ActionEvent event)
{
doPlay(jta.getSelectedRows());
}
}
/**
* Stops playing file
*/
private class StopAction extends AbstractAction {
public StopAction()
{
putValue(Action.NAME, XNap.tr("Stop"));
putValue(Action.SHORT_DESCRIPTION,
XNap.tr("Stop player"));
putValue(Action.SMALL_ICON, XNapFrame.getIcon("player_stop.png"));
putValue(Action.MNEMONIC_KEY, new Integer('S'));
}
public void actionPerformed(ActionEvent event)
{
if (player != null)
player.stop();
}
}
/**
* Refresh file and directory listings
*/
private class RefreshAction extends AbstractAction {
public RefreshAction()
{
putValue(Action.NAME, XNap.tr("Refresh"));
putValue(Action.SHORT_DESCRIPTION,
XNap.tr("Refresh list of files"));
putValue(Action.SMALL_ICON, XNapFrame.getIcon("reload.png"));
putValue(Action.MNEMONIC_KEY, new Integer('R'));
}
public void actionPerformed(ActionEvent event)
{
if (currentDir != null) {
showDirectory(currentDir);
}
}
}
/**
* Refresh file and directory listings
*/
private class ReloadTreeAction extends AbstractAction {
public ReloadTreeAction()
{
putValue(Action.NAME, XNap.tr("Reload Tree"));
putValue(Action.SHORT_DESCRIPTION,
XNap.tr("Reload Tree"));
putValue(Action.SMALL_ICON, XNapFrame.getIcon("reload.png"));
}
public void actionPerformed(ActionEvent event)
{
ftm.reload();
}
}
private class DeleteAction extends AbstractAction
{
public DeleteAction()
{
putValue(Action.NAME, XNap.tr("Delete"));
putValue(Action.SHORT_DESCRIPTION,
XNap.tr("Delete selected file(s)"));
putValue(Action.SMALL_ICON, XNapFrame.getIcon("editdelete.png"));
putValue(Action.MNEMONIC_KEY, new Integer('D'));
}
public void actionPerformed(ActionEvent event)
{
File[] files = getFiles();
if (files == null)
return;
files = Dialogs.showDeleteFilesDialog(LibraryPanel.this, files);
if (files != null) {
for (int i = 0; i < files.length; i++) {
if (!ltm.delete(files[i])) {
setStatus(XNap.tr("Could not delete file", 0, 1)
+ files[i].getName());
}
}
}
}
}
/**
* Enqueues a selected file.
*/
private class EnqueueAction extends AbstractAction {
public EnqueueAction()
{
putValue(Action.NAME, XNap.tr("Enqueue"));
putValue(Action.SHORT_DESCRIPTION,
XNap.tr("Enqueue selected file"));
putValue(Action.SMALL_ICON, XNapFrame.getIcon("queue.png"));
putValue(Action.MNEMONIC_KEY, new Integer('Q'));
}
public void actionPerformed(ActionEvent event)
{
{
LinkedList filestoEnqueue = new LinkedList();
int rowC = jta.getSelectedRowCount();
int[] rows = jta.getSelectedRows();
// collects selected files
for (int i = 0; i < rowC; i++) {
if (player.canPlay(ltm.get(rows[i]))) {
filestoEnqueue.add(ltm.get(rows[i]));
}
}
enqueueFiles(filestoEnqueue);
}
}
}
/**
* Enqueues selected Folder
*/
private class EnqueueFolderAction extends AbstractAction {
public EnqueueFolderAction()
{
putValue(Action.NAME, XNap.tr("Enqueue Folder"));
putValue(Action.SHORT_DESCRIPTION,
XNap.tr("Enqueue selected folder"));
putValue(Action.SMALL_ICON, XNapFrame.getIcon("queue.png"));
putValue(Action.MNEMONIC_KEY, new Integer('F'));
}
public void actionPerformed(ActionEvent event)
{
{
/* this is a very simple approach to enqueue the files in the
specified folder and relies on the shortcomings of our
current implementation: When you select a folder in the
tree with the right mousebutton the folder is shown in the
table, that's why we can just add all files of the table to
enqueueFiles */
LinkedList filestoEnqueue = new LinkedList();
for (int i = 0; i < ltm.getRowCount(); i++) {
if (player.canPlay(ltm.get(i))) {
filestoEnqueue.add(ltm.get(i));
}
}
enqueueFiles(filestoEnqueue);
}
}
}
/**
* Plays selected Folder
*/
private class PlayFolderAction extends AbstractAction {
public PlayFolderAction()
{
putValue(Action.NAME, XNap.tr("Play Folder"));
putValue(Action.SHORT_DESCRIPTION,
XNap.tr("Plays selected folder"));
putValue(Action.SMALL_ICON, XNapFrame.getIcon("1rightarrow.png"));
putValue(Action.MNEMONIC_KEY, new Integer('L'));
}
public void actionPerformed(ActionEvent event)
{
int[] rows = new int[ltm.getRowCount()];
for (int i = 1; i < rows.length; i++) {
rows[i] = i;
}
doPlay(rows);
}
}
private class RenameAction extends AbstractAction
{
public RenameAction()
{
putValue(Action.NAME, XNap.tr("Rename"));
putValue(Action.SHORT_DESCRIPTION, XNap.tr("Rename selected file"));
putValue(Action.MNEMONIC_KEY, new Integer('R'));
putValue(Action.SMALL_ICON, XNapFrame.getEmptyIcon());
}
public void actionPerformed(ActionEvent event)
{
int i = jta.getSelectedRow();
if (i != -1) {
ltm.setCellEditable(i, ltm.NAME);
jta.editCellAt(i, ltm.NAME);
DefaultCellEditor dce = (DefaultCellEditor)jta.getCellEditor();
JTextField jtf = (JTextField)dce.getComponent();
// jtf.setSelectionStart(0);
// jtf.setSelectionEnd(jtf.getText().length());
jtf.grabFocus();
jtf.setCaretPosition(0);
ltm.setCellEditable(-1, -1);
}
}
}
/**
* Share selected Folder
*/
private class ShareFolderAction extends AbstractAction {
public ShareFolderAction()
{
putValue(Action.NAME, XNap.tr("Share Folder"));
putValue(Action.SHORT_DESCRIPTION, XNap.tr("Share selected folder"));
putValue(Action.SMALL_ICON,
XNapFrame.getIcon("connect_established.png"));
putValue(Action.MNEMONIC_KEY, new Integer('H'));
}
public void actionPerformed(ActionEvent event)
{
Dialogs.showNotification(LibraryPanel.this, "ShareFolder",
XNap.tr("Sharing Folder information"),
XNap.tr("Please note: Folders are shared recursively, so all subfolders and their content will be shared on the network too."));
TreePath[] selected = jt.getSelectionPaths();
for (int i = 0; i < selected.length; i++) {
final Object o = selected[i].getLastPathComponent();
if (o instanceof FileNode) {
prefs.appendToUploadDirs(((FileNode)o).getPath());
prefs.write();
}
else {
setStatus(XNap.tr("Can not share \"") + o + "\"");
}
}
}
}
/**
* unshare selected Folder
*/
private class UnshareFolderAction extends AbstractAction {
public UnshareFolderAction()
{
putValue(Action.NAME, XNap.tr("Unshare Folder"));
putValue(Action.SHORT_DESCRIPTION,
XNap.tr("Unshare selected folder"));
putValue(Action.SMALL_ICON, XNapFrame.getIcon("connect_no.png"));
putValue(Action.MNEMONIC_KEY, new Integer('U'));
}
public void actionPerformed(ActionEvent event)
{
TreePath[] selected = jt.getSelectionPaths();
for (int i = 0; i < selected.length; i++) {
Object o = selected[i].getLastPathComponent();
if (o instanceof FileNode) {
prefs.removeFromUploadDirs(((FileNode)o).getPath());
prefs.write();
}
else {
setStatus(XNap.tr("Can not unshare \"") + o + "\"");
}
}
}
}
/**
* Performs a search.
*/
private class QueryAction extends AbstractAction {
public QueryAction()
{
putValue(Action.NAME, XNap.tr("Query"));
putValue(Action.SHORT_DESCRIPTION, XNap.tr("Perform search"));
putValue(Action.MNEMONIC_KEY, new Integer('Q'));
}
public void actionPerformed(ActionEvent event)
{
String s = jcSearch.getText().trim();
if (s.length() > 0) {
File[] files = Repository.getInstance().search(s);
if (files != null && files.length > 0) {
jt.clearSelection();
showFiles(files);
// having this as well is more consistent and even nicer...
Object[] arguments = { new Integer(files.length) };
setStatus(MessageFormat.format
(XNap.tr("Found {0} files"), arguments));
}
else {
setStatus(s + XNap.tr("not found in library", 1, 0));
}
jcSearch.addDistinctItemAtTop(s);
}
else {
setStatus(XNap.tr("What are you trying to search for?"));
}
}
}
protected class SelectionListener implements ActionListener
{
public void actionPerformed(ActionEvent event)
{
int row = jta.getSelectedRow();
if (row == -1 || jta.getSelectedRowCount() != 1)
return;
if (row == currentRow) {
displayFile(ltm.get(row));
}
}
}
private class DisplayThread extends Thread
{
private ViewerPanel panel;
public DisplayThread()
{
super("LibraryPanelLoader");
start();
}
public void setPanel(ViewerPanel newValue)
{
panel = newValue;
this.interrupt();
synchronized(this) {
this.notify();
}
// seems to have died, start again
if (!isAlive()) {
start();
}
}
public void run()
{
while (true) {
while (panel == null) {
synchronized (this) {
try {
this.wait();
}
catch (InterruptedException e) {
}
}
}
panel.display();
Runnable r = new Runnable()
{
private ViewerPanel p = panel;
public void run()
{
jspPreview.getHorizontalScrollBar().setValue(0);
jspPreview.getVerticalScrollBar().setValue(0);
jspPreview.setViewportView(p);
jlStatus.setText(p.getStatus());
}
};
try {
SwingUtilities.invokeAndWait(r);
}
catch (Exception e) {
}
panel = null;
}
}
}
}