package org.limewire.ui.swing.downloads;
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.List;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.BorderFactory;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.table.TableCellEditor;
import org.jdesktop.application.Application;
import org.limewire.core.api.URN;
import org.limewire.core.api.download.DownloadItem;
import org.limewire.core.api.download.DownloadListManager;
import org.limewire.core.api.download.DownloadState;
import org.limewire.core.api.download.DownloadItem.DownloadItemType;
import org.limewire.inject.EagerSingleton;
import org.limewire.setting.evt.SettingEvent;
import org.limewire.setting.evt.SettingListener;
import org.limewire.ui.swing.downloads.table.AVInfoPanel;
import org.limewire.ui.swing.downloads.table.DownloadTable;
import org.limewire.ui.swing.downloads.table.DownloadTableFactory;
import org.limewire.ui.swing.player.PlayerMediator;
import org.limewire.ui.swing.settings.SwingUiSettings;
import org.limewire.ui.swing.tray.Notification;
import org.limewire.ui.swing.tray.TrayNotifier;
import org.limewire.ui.swing.util.GuiUtils;
import org.limewire.ui.swing.util.I18n;
import org.limewire.ui.swing.util.SwingUtils;
import com.google.inject.Inject;
import com.google.inject.Provider;
/**
* Container to display the Downloads table.
*
* <p>Note: This is an EagerSingleton to ensure that register() is called and
* the listeners are in place at startup.</p>
*/
@EagerSingleton
public class MainDownloadPanel extends JPanel {
public static final String NAME = "MainDownloadPanel";
private final DownloadMediator downloadMediator;
private final Provider<DownloadTableFactory> downloadTableFactory;
private final DownloadListManager downloadListManager;
private final Provider<PlayerMediator> playerMediator;
private final Provider<AVInfoPanel> avInfoPanelFactory;
private TrayNotifier notifier;
private boolean isInitialized = false;
private DownloadTable table;
/**
* Create the panel.
*/
@Inject
public MainDownloadPanel(Provider<DownloadTableFactory> downloadTableFactory,
DownloadMediator downloadMediator,
TrayNotifier notifier,
DownloadListManager downloadListManager,
Provider<PlayerMediator> playerMediator,
Provider<AVInfoPanel> avInfoPanelFactory) {
this.downloadMediator = downloadMediator;
this.downloadTableFactory = downloadTableFactory;
this.downloadListManager = downloadListManager;
this.playerMediator = playerMediator;
this.avInfoPanelFactory = avInfoPanelFactory;
this.notifier = notifier;
GuiUtils.assignResources(this);
}
public void selectAndScrollTo(URN urn) {
// its possible the table hasn't been initialized yet
// after the first download starts
if(table == null) {
initialize();
}
table.selectAndScrollTo(urn);
}
@Inject
public void register() {
// Add listener for "show downloads" setting.
SwingUiSettings.SHOW_TRANSFERS_TRAY.addSettingListener(new SettingListener() {
@Override
public void settingChanged(SettingEvent evt) {
SwingUtils.invokeNowOrLater(new Runnable() {
@Override
public void run() {
initialize();
}
});
}
});
//we have to eagerly initialize the table when the SHOW_DOWNLOAD_TRAY setting
//is set to true on startup, otherwise the table space will be empty and the lines will
//be put in the first time a download comes in, which looks a little weird
if (SwingUiSettings.SHOW_TRANSFERS_TRAY.getValue()) {
initialize();
}
// Add listener for downloads added and completed.
downloadListManager.addPropertyChangeListener(new DownloadPropertyListener());
}
//Lazily initialized - initialize() is called when the first downloadItem is added to the list.
private void initialize() {
if(!isInitialized){
isInitialized = true;
setLayout(new BorderLayout());
table = downloadTableFactory.get().create(downloadMediator.getDownloadList());
table.setTableHeader(null);
JScrollPane pane = new JScrollPane(table);
pane.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
add(pane, BorderLayout.CENTER);
}
}
public List<DownloadItem> getSelectedDownloadItems(){
return table.getSelectedItems();
}
/**
* Listener to handle download added/completed events from the download
* list manager.
*/
private class DownloadPropertyListener implements PropertyChangeListener {
public void propertyChange(PropertyChangeEvent event) {
if (event.getPropertyName().equals(DownloadListManager.DOWNLOAD_COMPLETED)) {
final DownloadItem downloadItem = (DownloadItem) event.getNewValue();
DownloadState state = downloadItem.getState();
if(downloadItem.getDownloadItemType() == DownloadItemType.ANTIVIRUS) {
// Don't show a popup when an antivirus download completes
} else if (state == DownloadState.THREAT_FOUND) {
avInfoPanelFactory.get().showThreatMessage(downloadItem, true);
} else if (state == DownloadState.SCAN_FAILED) {
avInfoPanelFactory.get().showFailureMessage(downloadItem, true);
} else if (state == DownloadState.DANGEROUS) {
avInfoPanelFactory.get().showDangerMessage(downloadItem, true);
} else {
notifier.showMessage(new Notification(I18n.tr("Download Complete"), downloadItem.getFileName(),
new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
ActionMap map = Application.getInstance().getContext().getActionManager()
.getActionMap();
map.get("restoreView").actionPerformed(e);
if (downloadItem.isLaunchable()) {
DownloadItemUtils.launch(downloadItem, playerMediator);
}
}
}));
}
// For LWC-4733. It is possible with extremely small file
// downloads that the download can complete before initialize()
// is called. We are planning to refactor so that this won't
// happen but this null check will prevent the NPE in the release.
if(table == null) {
initialize();
}
// the user might be editing one of the cell's while the download completes,
// i.e. the user might have the mouse hovering over the pause button. (Bug LWC-4317)
// Let's manually cancel cell editing here after the download completes
TableCellEditor editor = table.getCellEditor();
if ( editor != null )
{
editor.cancelCellEditing();
}
}
}
}
}