package org.limewire.ui.swing.properties;
import static org.limewire.ui.swing.util.I18n.tr;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.swing.JButton;
import javax.swing.JPanel;
import net.miginfocom.swing.MigLayout;
import org.jdesktop.application.Resource;
import org.limewire.bittorrent.Torrent;
import org.limewire.core.api.download.DownloadItem;
import org.limewire.core.api.download.DownloadPropertyKey;
import org.limewire.core.api.download.DownloadItem.DownloadItemType;
import org.limewire.core.api.library.PropertiableFile;
import org.limewire.ui.swing.action.AbstractAction;
import org.limewire.ui.swing.components.LimeJDialog;
import org.limewire.ui.swing.properties.FileInfoTabPanel.FileInfoTabListener;
import org.limewire.ui.swing.properties.FileInfoTabPanel.Tabs;
import org.limewire.ui.swing.util.GuiUtils;
import org.limewire.ui.swing.util.I18n;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
/**
* A Dialog for displaying FileInfo about a file. This dialog changes
* depending on the state of the file and the location of the file.
*/
public class FileInfoDialog extends LimeJDialog {
/**
* Type of FileInfoDialog that can be created.
*
* LOCAL_FILE - File exists within the current LimeWire,
* DOWNLOADNG_FILE - File is in the process of downloading or a portion
* of the file has been downloaded already,
* REMOTE_FILE - File exists on one or more computers but not
* within this LimeWire
*/
public static enum FileInfoType {
LOCAL_FILE, DOWNLOADING_FILE, REMOTE_FILE
}
@Resource private Color backgroundColor;
private final FileInfoTabPanel tabPanel;
private final JPanel cardPanel;
private final Map<Tabs, FileInfoPanel> cards;
private JButton okButton;
@Inject
public FileInfoDialog(@Assisted final PropertiableFile propertiableFile, @Assisted final FileInfoType type,
FileInfoTabPanel fileInfoTabPanel,
final FileInfoPanelFactory fileInfoFactory) {
super(GuiUtils.getMainFrame());
tabPanel = fileInfoTabPanel;
cardPanel = new JPanel(new BorderLayout());
cardPanel.setPreferredSize(new Dimension(400,600));
cards = new HashMap<Tabs, FileInfoPanel>();
GuiUtils.assignResources(this);
cardPanel.setOpaque(false);
createTabs(propertiableFile, type);
cards.put(Tabs.GENERAL, fileInfoFactory.createGeneralPanel(type, propertiableFile));
cardPanel.add(cards.get(Tabs.GENERAL).getComponent());
setTitle(I18n.tr("{0} Properties", propertiableFile.getFileName()));
setLayout(new MigLayout("gap 0, insets 0, fill"));
getContentPane().setBackground(backgroundColor);
add(fileInfoFactory.createOverviewPanel(type, propertiableFile).getComponent(), "growx, wrap");
add(tabPanel.getComponent(), "growx, wrap");
add(cardPanel, "grow");
createFooter();
setPreferredSize(new Dimension(500,565));
setModalityType(ModalityType.APPLICATION_MODAL);
setDefaultCloseOperation(FileInfoDialog.DISPOSE_ON_CLOSE);
pack();
setLocationRelativeTo(GuiUtils.getMainFrame());
// listen to the visibility setting/ disposes of the dialog when it becomes invisible
addComponentListener(new ComponentListener(){
@Override
public void componentHidden(ComponentEvent e) {
//unregister any listeners used and dispose of dialog when made invisible
for(FileInfoPanel panel : cards.values()) {
panel.unregisterListeners();
}
FileInfoDialog.this.dispose();
}
@Override
public void componentMoved(ComponentEvent e) {}
@Override
public void componentResized(ComponentEvent e) {}
@Override
public void componentShown(ComponentEvent e) {
if(okButton != null)
okButton.requestFocusInWindow();
}
});
tabPanel.addSearchTabListener(new FileInfoTabListener(){
@Override
public void tabSelected(Tabs tab) {
if(!cards.containsKey(tab)) {
if(tab == Tabs.GENERAL) {
cards.put(tab, fileInfoFactory.createGeneralPanel(type, propertiableFile));
} else if(tab == Tabs.SHARING) {
cards.put(tab, fileInfoFactory.createSharingPanel(type, propertiableFile));
} else if(tab == Tabs.TRANSFERS) {
cards.put(tab, fileInfoFactory.createTransferPanel(type, propertiableFile));
} else if(tab == Tabs.BITTORENT) {
if(propertiableFile instanceof DownloadItem && ((DownloadItem)propertiableFile).getDownloadProperty(DownloadPropertyKey.TORRENT) != null) {
Torrent torrent = (Torrent)((DownloadItem)propertiableFile).getDownloadProperty(DownloadPropertyKey.TORRENT);
cards.put(tab, fileInfoFactory.createBittorentPanel(torrent));
} else {
throw new IllegalStateException("No DownloadItem or Torrent found for BITTORENT tab.");
}
} else {
throw new IllegalStateException("Unknown state:" + tab);
}
}
cardPanel.removeAll();
cardPanel.add(cards.get(tab).getComponent());
FileInfoDialog.this.validate();
FileInfoDialog.this.repaint();
}
});
setVisible(true);
}
private void createTabs(PropertiableFile propertiableFile, final FileInfoType type) {
List<Tabs> tabs = new ArrayList<Tabs>();
// general tab is always shown
tabs.add(Tabs.GENERAL);
switch(type) {
case LOCAL_FILE:
tabs.add(Tabs.SHARING);
break;
case DOWNLOADING_FILE:
if(propertiableFile instanceof DownloadItem && ((DownloadItem)propertiableFile).getDownloadItemType() == DownloadItemType.BITTORRENT)
tabs.add(Tabs.BITTORENT);
tabs.add(Tabs.TRANSFERS);
break;
case REMOTE_FILE:
break;
}
tabPanel.setTabs(tabs);
}
/**
* Adds a footer with the cancel/ok button to close the dialog.
*/
private void createFooter() {
okButton = new JButton(new OKAction());
JPanel footerPanel = new JPanel(new MigLayout("fill, insets 0 15 10 15"));
footerPanel.add(okButton, "alignx right, aligny bottom, split, tag ok");
footerPanel.add(new JButton(new CancelAction()), "aligny bottom, tag cancel");
footerPanel.setBackground(backgroundColor);
add(footerPanel, "grow, south");
}
/**
* Closes the dialog and saves any data that may have changed.
*/
private class OKAction extends AbstractAction {
public OKAction() {
super(tr("OK"));
}
@Override
public void actionPerformed(ActionEvent e) {
setVisible(false);
for(FileInfoPanel panel : cards.values()) {
panel.save();
}
}
}
/**
* Closes the data and does not save any data even if it
* has changed.
*/
private class CancelAction extends AbstractAction {
public CancelAction() {
super(tr("Cancel"));
}
@Override
public void actionPerformed(ActionEvent e) {
setVisible(false);
}
}
}