package org.limewire.ui.swing.downloads.table.renderer;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Collection;
import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JTable;
import net.miginfocom.swing.MigLayout;
import org.jdesktop.application.Resource;
import org.limewire.core.api.download.DownloadItem;
import org.limewire.core.api.download.DownloadPropertyKey;
import org.limewire.core.api.download.DownloadState;
import org.limewire.core.api.download.DownloadItem.DownloadItemType;
import org.limewire.core.api.download.DownloadItem.ErrorState;
import org.limewire.core.api.endpoint.RemoteHost;
import org.limewire.core.api.malware.AntivirusUpdateType;
import org.limewire.friend.api.Friend;
import org.limewire.ui.swing.components.IconButton;
import org.limewire.ui.swing.downloads.table.DownloadActionHandler;
import org.limewire.ui.swing.table.TableRendererEditor;
import org.limewire.ui.swing.transfer.TransferRendererResources;
import org.limewire.ui.swing.util.GuiUtils;
import org.limewire.ui.swing.util.I18n;
import org.limewire.util.CommonUtils;
import com.google.inject.Inject;
/**
* Renderer/editor component for the download table to display message.
*/
public class DownloadMessageRendererEditor extends TableRendererEditor {
@Resource private Icon infoIcon;
private final DownloadActionHandler actionHandler;
private final TransferRendererResources resources;
private JLabel messageLabel;
private JButton infoButton;
private DownloadItem downloadItem;
/**
* Constructs a DownloadMessageRendererEditor that uses the specified
* action handler.
*/
@Inject
public DownloadMessageRendererEditor(DownloadActionHandler actionHandler) {
this.actionHandler = actionHandler;
this.resources = new TransferRendererResources();
GuiUtils.assignResources(this);
setLayout(new MigLayout("insets 0, gap 0, aligny center, nogrid, novisualpadding"));
messageLabel = new JLabel();
infoButton = new IconButton(infoIcon);
infoButton.setActionCommand(DownloadActionHandler.INFO_COMMAND);
infoButton.setToolTipText(I18n.tr("Info"));
infoButton.addActionListener(new ButtonListener());
add(messageLabel, "");
add(infoButton, "");
}
@Override
protected Component doTableCellEditorComponent(JTable table, Object value,
boolean isSelected, int row, int column) {
if (value instanceof DownloadItem) {
// Save download item for use by button listener.
downloadItem = (DownloadItem) value;
update(downloadItem);
return this;
} else {
return emptyPanel;
}
}
@Override
protected Component doTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
if (value instanceof DownloadItem) {
update((DownloadItem) value);
return this;
} else {
return emptyPanel;
}
}
/**
* Updates the display components using the specified download item.
*/
private void update(DownloadItem item) {
DownloadState state = item.getState();
resources.decorateComponent(messageLabel);
messageLabel.setText(getPercentMessage(item) + getMessage(item));
if (state == DownloadState.DANGEROUS ||
state == DownloadState.THREAT_FOUND ||
state == DownloadState.SCAN_FAILED) {
messageLabel.setForeground(resources.getDisabledForeground());
}
infoButton.setVisible(item.getDownloadItemType() == DownloadItemType.ANTIVIRUS ||
item.getDownloadItemType() == DownloadItemType.BITTORRENT ||
state == DownloadState.DANGEROUS ||
state == DownloadState.SCANNING ||
state == DownloadState.SCANNING_FRAGMENT ||
state == DownloadState.THREAT_FOUND ||
state == DownloadState.SCAN_FAILED);
}
/**
* Returns the percent complete as a string.
*/
private String getPercentMessage(DownloadItem item) {
int percent = item.getPercentComplete();
DownloadState state = item.getState();
if (percent == 0 || state.isFinished() ||
state == DownloadState.DOWNLOADING ||
state == DownloadState.ERROR ||
state == DownloadState.SCANNING ||
state == DownloadState.APPLYING_DEFINITION_UPDATE) {
return "";
}
return percent + "% - ";
}
/**
* @return the message displayed after the percentage. Can be null for non-covered states.
*/
private String getMessage(DownloadItem item) {
switch (item.getState()) {
case RESUMING:
return I18n.tr("Resuming");
case CANCELLED:
return I18n.tr("Cancelled");
case FINISHING:
return I18n.tr("Finishing...");
case DONE:
return I18n.tr("Done");
case CONNECTING:
Collection<RemoteHost> hosts = item.getRemoteHosts();
if(hosts.size() == 0){
return I18n.tr("Connecting...");
}
//{0}: 1 person, 2 people, etc
return I18n.tr("Connecting to {0}", getPeopleText(item));
case DOWNLOADING:
// {0}: current size
// {1}: total size
// {2}: download speed
// {3}: download source
if(item.getDownloadSourceCount() == 0){
return I18n.tr("{0} of {1} ({2})",
GuiUtils.formatUnitFromBytes(item.getCurrentSize()),
GuiUtils.formatUnitFromBytes(item.getTotalSize()),
GuiUtils.formatKilobytesPerSec(item.getDownloadSpeed()));
} else {
return I18n.tr("{0} of {1} ({2}) from {3}",
GuiUtils.formatUnitFromBytes(item.getCurrentSize()),
GuiUtils.formatUnitFromBytes(item.getTotalSize()),
GuiUtils.formatKilobytesPerSec(item.getDownloadSpeed()),
getPeopleText(item));
}
case TRYING_AGAIN:
return getTryAgainMessage(item.getRemainingTimeInState());
case STALLED:
if(item.getDownloadItemType() == DownloadItemType.BITTORRENT) {
return I18n.tr("Error downloading torrent");
} else {
return I18n.tr("Stalled - {0} of {1}",
GuiUtils.formatUnitFromBytes(item.getCurrentSize()),
GuiUtils.formatUnitFromBytes(item.getTotalSize()));
}
case ERROR:
if(item.getErrorState() == ErrorState.INVALID) {
return I18n.tr(item.getErrorState().getMessage());
} else {
return I18n.tr("Unable to download: ") + I18n.tr(item.getErrorState().getMessage());
}
case PAUSED:
// {0}: current size, {1} total size
return I18n.tr("Paused - {0} of {1}",
GuiUtils.formatUnitFromBytes(item.getCurrentSize()), GuiUtils.formatUnitFromBytes(item.getTotalSize()));
case LOCAL_QUEUED:
return getQueueTimeMessage(item.getRemainingTimeInState());
case REMOTE_QUEUED:
if(item.getRemoteQueuePosition() == -1 || item.getRemoteQueuePosition() == Integer.MAX_VALUE){
return getQueueTimeMessage(item.getRemainingTimeInState());
}
return I18n.trn("Waiting - Next in line",
"Waiting - {0} in line",
item.getRemoteQueuePosition(), item.getRemoteQueuePosition());
case DANGEROUS:
return I18n.tr("File deleted - Dangerous file");
case SCANNING:
return I18n.tr("Scanning for viruses - Powered by AVG");
case SCANNING_FRAGMENT:
return I18n.tr("Scanning preview - Powered by AVG");
case THREAT_FOUND:
return I18n.tr("File deleted - Threat detected by AVG");
case SCAN_FAILED:
return I18n.tr("Done, but unable to scan for viruses");
case APPLYING_DEFINITION_UPDATE:
AntivirusUpdateType type = (AntivirusUpdateType)item.getDownloadProperty(DownloadPropertyKey.ANTIVIRUS_UPDATE_TYPE);
if (type == AntivirusUpdateType.CHECKING) {
return I18n.tr("Evaluating...");
}
return I18n.tr("Applying update...");
default:
return null;
}
}
private String getTryAgainMessage(long tryingAgainTime) {
if(tryingAgainTime == DownloadItem.UNKNOWN_TIME){
return I18n.tr("Looking for file...");
} else {
return I18n.tr("Looking for file ({0} left)", CommonUtils.seconds2time(tryingAgainTime));
}
}
private String getPeopleText(DownloadItem item) {
Collection<RemoteHost> hosts = item.getRemoteHosts();
if (hosts.size() == 0) {
//checking sources to support showing the number of bit torrent hosts.
int downloadSourceCount = item.getDownloadSourceCount();
if(downloadSourceCount < 1) {
return I18n.tr("nobody");
} else {
return I18n.trn("{0} P2P User", "{0} P2P Users", downloadSourceCount);
}
} else if (hosts.size() == 1) {
Friend friend = hosts.iterator().next().getFriendPresence().getFriend();
if (friend.isAnonymous()) {
return I18n.tr("1 P2P User");
} else {
return friend.getRenderName();
}
} else {
boolean hasP2P = false;
boolean hasFriend = false;
for (RemoteHost host : hosts) {
if (host.getFriendPresence().getFriend().isAnonymous()) {
hasP2P = true;
} else {
hasFriend = true;
}
if (hasP2P && hasFriend) {
// We found both. We're done.
break;
}
}
if (hasP2P && hasFriend ) {
return I18n.trn("{0} Person", "{0} People", hosts.size());
} else if (hasP2P) {
return I18n.trn("{0} P2P User", "{0} P2P Users", hosts.size());
} else {
//just friends
return I18n.trn("{0} Friend", "{0} Friends", hosts.size());
}
}
}
private String getQueueTimeMessage(long queueTime){
//if(queueTime == DownloadItem.UNKNOWN_TIME){
return I18n.tr("Waiting...");
//} else {
// return I18n.tr("Waiting...", CommonUtils.seconds2time(queueTime));
//}
}
/**
* Action listener for editor buttons.
*/
private class ButtonListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
// Reset cursor if source component is IconButton. If the action
// displays a modal dialog, then IconButton does not receive the
// mouseExited event to reset the default cursor.
if (e.getSource() instanceof IconButton) {
((IconButton) e.getSource()).resetDefaultCursor();
}
actionHandler.performAction(e.getActionCommand(), downloadItem);
cancelCellEditing();
}
}
}