package org.limewire.ui.swing.downloads.table; import java.awt.Component; import java.awt.event.ActionEvent; import java.util.ArrayList; import java.util.List; import javax.swing.AbstractAction; import javax.swing.Action; import javax.swing.table.TableCellRenderer; import org.jdesktop.application.Resource; import org.jdesktop.swingx.decorator.ComponentAdapter; import org.jdesktop.swingx.decorator.HighlightPredicate; import org.limewire.core.api.URN; import org.limewire.core.api.download.DownloadItem; import org.limewire.core.api.download.DownloadState; import org.limewire.ui.swing.downloads.DownloadItemUtils; import org.limewire.ui.swing.downloads.table.renderer.DownloadButtonRendererEditor; import org.limewire.ui.swing.downloads.table.renderer.DownloadCancelRendererEditor; import org.limewire.ui.swing.downloads.table.renderer.DownloadMessageRendererEditorFactory; import org.limewire.ui.swing.downloads.table.renderer.DownloadProgressRenderer; import org.limewire.ui.swing.downloads.table.renderer.DownloadTitleRenderer; import org.limewire.ui.swing.player.PlayerMediator; import org.limewire.ui.swing.table.TableDoubleClickHandler; import org.limewire.ui.swing.table.TablePopupHandler; import org.limewire.ui.swing.transfer.TransferTable; import org.limewire.ui.swing.util.GuiUtils; import ca.odell.glazedlists.EventList; import ca.odell.glazedlists.ListSelection; import ca.odell.glazedlists.swing.DefaultEventSelectionModel; import com.google.inject.Inject; import com.google.inject.Provider; import com.google.inject.assistedinject.Assisted; /** * Table showing DownloadItems. Provides popup menus and double click handling. */ public class DownloadTable extends TransferTable<DownloadItem> { @Resource private int rowHeight; @Resource private int gapMinWidth; @Resource private int gapPrefWidth; @Resource private int gapMaxWidth; @Resource private int titleMinWidth; @Resource private int titlePrefWidth; @Resource private int titleMaxWidth; @Resource private int progressMinWidth; @Resource private int progressPrefWidth; @Resource private int progressMaxWidth; @Resource private int messageMinWidth; @Resource private int messagePrefWidth; @Resource private int messageMaxWidth; @Resource private int actionMinWidth; @Resource private int actionPrefWidth; @Resource private int actionMaxWidth; @Resource private int cancelMinWidth; @Resource private int cancelPrefWidth; @Resource private int cancelMaxWidth; private DownloadTableModel model; private EventList<DownloadItem> selectedItems; private final DownloadActionHandler actionHandler; private final Provider<PlayerMediator> playerMediator; private final DownloadMessageRendererEditorFactory messageRendererEditorFactory; @Inject public DownloadTable(DownloadTitleRenderer downloadTitleRenderer, DownloadProgressRenderer downloadProgressRenderer, DownloadMessageRendererEditorFactory messageRendererEditorFactory, DownloadCancelRendererEditor cancelEditor, DownloadButtonRendererEditor buttonEditor, DownloadActionHandler actionHandler, DownloadPopupHandlerFactory downloadPopupHandlerFactory, @Assisted EventList<DownloadItem> downloadItems, DownloadableTransferHandler downloadableTransferHandler, Provider<PlayerMediator> playerMediator) { super(new DownloadTableModel(downloadItems)); this.actionHandler = actionHandler; this.playerMediator = playerMediator; this.messageRendererEditorFactory = messageRendererEditorFactory; GuiUtils.assignResources(this); initialize(downloadItems, buttonEditor, cancelEditor, downloadPopupHandlerFactory); addHighlighter(createDisabledHighlighter(new ThreatHighlightPredicate())); TableCellRenderer gapRenderer = new GapRenderer(); setUpColumn(DownloadTableFormat.TITLE, downloadTitleRenderer, titleMinWidth, titlePrefWidth, titleMaxWidth); setUpColumn(DownloadTableFormat.TITLE_GAP, gapRenderer, gapMinWidth, gapPrefWidth, gapMaxWidth); setUpColumn(DownloadTableFormat.PROGRESS, downloadProgressRenderer, progressMinWidth, progressPrefWidth, progressMaxWidth); setUpColumn(DownloadTableFormat.PROGRESS_GAP, gapRenderer, gapMinWidth, gapPrefWidth, gapMaxWidth); setUpColumn(DownloadTableFormat.MESSAGE, messageRendererEditorFactory.create(null), messageMinWidth, messagePrefWidth, messageMaxWidth); setUpColumn(DownloadTableFormat.MESSAGE_GAP, gapRenderer, gapMinWidth, gapPrefWidth, gapMaxWidth); setUpColumn(DownloadTableFormat.ACTION, new DownloadButtonRendererEditor(), actionMinWidth, actionPrefWidth, actionMaxWidth); setUpColumn(DownloadTableFormat.ACTION_GAP, gapRenderer, gapMinWidth, gapPrefWidth, gapMaxWidth); setUpColumn(DownloadTableFormat.CANCEL, new DownloadCancelRendererEditor(), cancelMinWidth, cancelPrefWidth, cancelMaxWidth); setTransferHandler(downloadableTransferHandler); setDragEnabled(true); setRowHeight(rowHeight); } public DownloadItem getDownloadItem(int row){ return model.getDownloadItem(convertRowIndexToModel(row)); } /** Returns a copy of all selected items. */ public List<DownloadItem> getSelectedItems() { return new ArrayList<DownloadItem>(selectedItems); } public void selectAndScrollTo(URN urn) { if(urn != null) { for(int y=0; y < model.getRowCount(); y++) { DownloadItem item = getDownloadItem(y); if(item != null && item.getUrn() != null && urn.equals(item.getUrn())) { getSelectionModel().setSelectionInterval(y, y); ensureRowVisible(y); break; } } } } public void selectAndScrollTo(DownloadItem item) { for(int y = 0; y < model.getRowCount(); y++) { if(item == getDownloadItem(y)) { getSelectionModel().setSelectionInterval(y, y); ensureRowVisible(y); break; } } } private void setUpColumn(int index, TableCellRenderer renderer, int minWidth, int prefWidth, int maxWidth){ setColumnRenderer(index, renderer); setColumnWidths(index, minWidth, prefWidth, maxWidth); } private void initialize(EventList<DownloadItem> downloadItems, DownloadButtonRendererEditor buttonEditor, DownloadCancelRendererEditor cancelEditor, DownloadPopupHandlerFactory downloadPopupHandlerFactory) { model = (DownloadTableModel) getModel(); DefaultEventSelectionModel<DownloadItem> model = new DefaultEventSelectionModel<DownloadItem>(downloadItems); setSelectionModel(model); model.setSelectionMode(ListSelection.MULTIPLE_INTERVAL_SELECTION_DEFENSIVE); this.selectedItems = model.getSelected(); TablePopupHandler popupHandler = downloadPopupHandlerFactory.create(this); setPopupHandler(popupHandler); TableDoubleClickHandler clickHandler = new TableDoubleClickHandler() { @Override public void handleDoubleClick(int row) { launch(row); } }; setDoubleClickHandler(clickHandler); Action enterAction = new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { int row = getSelectedRow(); if (row > -1) { launch(row); } } }; setEnterKeyAction(enterAction); getColumnModel().getColumn(DownloadTableFormat.MESSAGE).setCellEditor(messageRendererEditorFactory.create(actionHandler)); getColumnModel().getColumn(DownloadTableFormat.ACTION).setCellEditor(buttonEditor); getColumnModel().getColumn(DownloadTableFormat.CANCEL).setCellEditor(cancelEditor); } private void launch(int row){ DownloadItem item = getDownloadItem(row); if(item != null && item.isLaunchable()) { DownloadItemUtils.launch(item, playerMediator); } } /** * Implementation of Predicate that specifies rules to highlight table row * containing download threat. */ private class ThreatHighlightPredicate implements HighlightPredicate { @Override public boolean isHighlighted(Component renderer, ComponentAdapter adapter) { DownloadItem item = getDownloadItem(adapter.row); DownloadState state = item.getState(); return (state == DownloadState.DANGEROUS || state == DownloadState.THREAT_FOUND || state == DownloadState.SCAN_FAILED); } } }