package org.limewire.ui.swing.mainframe; import java.awt.Color; import java.awt.Cursor; import java.awt.Font; import java.awt.GradientPaint; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.MouseEvent; import java.util.EnumMap; import java.util.List; import java.util.Map; import javax.swing.AbstractAction; import javax.swing.Action; import javax.swing.Icon; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JSplitPane; import net.miginfocom.swing.MigLayout; import org.jdesktop.application.Resource; import org.jdesktop.swingx.JXPanel; import org.jdesktop.swingx.painter.RectanglePainter; import org.limewire.core.api.download.DownloadItem; import org.limewire.core.api.network.BandwidthCollector; import org.limewire.core.api.upload.UploadItem; import org.limewire.core.settings.UploadSettings; import org.limewire.setting.evt.SettingEvent; import org.limewire.setting.evt.SettingListener; import org.limewire.ui.swing.components.FancyTab; import org.limewire.ui.swing.components.FancyTabList; import org.limewire.ui.swing.components.LimeComboBox; import org.limewire.ui.swing.components.TabActionMap; import org.limewire.ui.swing.components.decorators.ComboBoxDecorator; import org.limewire.ui.swing.dock.DockIconFactory; import org.limewire.ui.swing.downloads.DownloadMediator; import org.limewire.ui.swing.listener.MousePopupListener; import org.limewire.ui.swing.mainframe.BottomPanel.TabId; import org.limewire.ui.swing.painter.factories.BarPainterFactory; import org.limewire.ui.swing.settings.SwingUiSettings; import org.limewire.ui.swing.transfer.TransferTrayNavigator; import org.limewire.ui.swing.upload.UploadMediator; import org.limewire.ui.swing.util.FontUtils; import org.limewire.ui.swing.util.GuiUtils; import org.limewire.ui.swing.util.I18n; import org.limewire.ui.swing.util.ResizeUtils; import org.limewire.ui.swing.util.SwingUtils; import ca.odell.glazedlists.event.ListEvent; import ca.odell.glazedlists.event.ListEventListener; import com.google.inject.Inject; import com.google.inject.Singleton; /** * Control panel that is displayed above the downloads/uploads tables. */ @Singleton public class BottomHeaderPanel implements TransferTrayNavigator { private static volatile int uploadsViewed = 0; @Resource private Icon moreButtonArrow; @Resource private Icon scrollPaneNubIcon; @Resource private Font hyperlinkFont; @Resource(key="HyperlinkButtonResources.foreground") private Color hyperlinkForeground; @Resource private Color highlightBackground; @Resource private Color highlightBorderColor; @Resource private Color selectionTopGradientColor; @Resource private Color selectionBottomGradientColor; @Resource private Color selectionTopBorderColor; @Resource private Color selectionBottomBorderColor; @Resource private Font textFont; @Resource private Color textForeground; @Resource private Color textSelectedForeground; private final DownloadMediator downloadMediator; private final UploadMediator uploadMediator; private final ComboBoxDecorator comboBoxDecorator; private final BandwidthCollector bandwidthCollector; private final BottomPanel bottomPanel; private final JXPanel component; private JComponent dragComponent; private Map<TabId, Action> actionMap = new EnumMap<TabId, Action>(TabId.class); private List<TabActionMap> tabActionList; private FancyTabList tabList; private JLabel titleTextLabel; private JPanel downloadButtonPanel; private JPanel uploadButtonPanel; private LimeComboBox downloadOptionsButton; private LimeComboBox uploadOptionsButton; private int componentHeight; private JSplitPane parentSplitPane; @Inject public BottomHeaderPanel(DownloadMediator downloadMediator, UploadMediator uploadMediator, ComboBoxDecorator comboBoxDecorator, BarPainterFactory barPainterFactory, DockIconFactory iconFactory, BandwidthCollector bandwidthCollector, BottomPanel bottomPanel) { this.downloadMediator = downloadMediator; this.uploadMediator = uploadMediator; this.comboBoxDecorator = comboBoxDecorator; this.bandwidthCollector = bandwidthCollector; this.bottomPanel = bottomPanel; GuiUtils.assignResources(this); hyperlinkFont = FontUtils.deriveUnderline(hyperlinkFont, true); component = new JXPanel(new MigLayout("insets 0 0 0 0, gap 0, novisualpadding, fill")); component.setBackgroundPainter(barPainterFactory.createDownloadSummaryBarPainter()); setComponentHeight(20); // initialize the dock icon since it registers as a Service iconFactory.createDockIcon(); initialize(); } public JComponent getComponent() { return component; } public JComponent getDragComponent() { return dragComponent; } private void initialize(){ initializeComponents(); initializeTabList(); layoutComponents(); updateSelection(); } private void initializeComponents(){ titleTextLabel = new JLabel(I18n.tr("Downloads")); titleTextLabel.setFont(textFont); titleTextLabel.setForeground(textForeground); dragComponent = new JLabel(scrollPaneNubIcon); dragComponent.setCursor(Cursor.getPredefinedCursor(Cursor.S_RESIZE_CURSOR)); downloadButtonPanel = new JPanel(new MigLayout("insets 0 0 0 0, gap 0, novisualpadding")); downloadButtonPanel.setOpaque(false); uploadButtonPanel = new JPanel(new MigLayout("insets 0 0 0 0, gap 0, novisualpadding")); uploadButtonPanel.setOpaque(false); initializeOptionsButton(); // Install listener to show appropriate popup menu. component.addMouseListener(new MousePopupListener() { @Override public void handlePopupMouseEvent(MouseEvent e) { // Determine popup menu. JPopupMenu popupMenu = null; if (downloadButtonPanel.isVisible()) { popupMenu = downloadMediator.getHeaderPopupMenu(); } else if (uploadButtonPanel.isVisible()) { popupMenu = uploadMediator.getHeaderPopupMenu(); } // Display popup menu. if (popupMenu != null) { popupMenu.show(component, e.getX(), e.getY()); } } }); } private void layoutComponents(){ List<JButton> downloadButtons = downloadMediator.getHeaderButtons(); for (JButton button : downloadButtons) { button.setFont(hyperlinkFont); downloadButtonPanel.add(button, "gapafter 5"); } downloadButtonPanel.add(downloadOptionsButton, "gapafter 5"); List<JButton> uploadButtons = uploadMediator.getHeaderButtons(); for (JButton button : uploadButtons) { button.setFont(hyperlinkFont); uploadButtonPanel.add(button, "gapafter 5"); } uploadButtonPanel.add(uploadOptionsButton, "gapafter 5"); component.add(tabList, "growy, push, hidemode 3"); component.add(titleTextLabel, "gapbefore 5, push, hidemode 3"); component.add(downloadButtonPanel, "hidemode 3"); component.add(uploadButtonPanel, "hidemode 3"); component.add(dragComponent, "pos 0.5al 0"); } @Inject public void register(){ // Add listeners to update header title. downloadMediator.getActiveList().addListEventListener(new LabelUpdateListListener()); uploadMediator.getActiveList().addListEventListener(new ListEventListener<UploadItem>() { @Override public void listChanged(ListEvent<UploadItem> listChanges) { updateUploadTitle(); } }); SwingUiSettings.SHOW_TRANSFERS_TRAY.addSettingListener(new SettingListener() { @Override public void settingChanged(SettingEvent evt) { SwingUtils.invokeNowOrLater(new Runnable() { @Override public void run() { updateSelection(); } }); } }); UploadSettings.SHOW_UPLOADS_IN_TRAY.addSettingListener(new SettingListener() { @Override public void settingChanged(SettingEvent evt) { SwingUtils.invokeNowOrLater(new Runnable() { @Override public void run() { updateSelection(); } }); } }); } private void initializeOptionsButton(){ // Create options button for downloads. downloadOptionsButton = new LimeComboBox(); downloadOptionsButton.setText(I18n.tr("Options")); comboBoxDecorator.decorateMiniComboBox(downloadOptionsButton); downloadOptionsButton.setFocusable(false); downloadOptionsButton.setFont(hyperlinkFont); downloadOptionsButton.setIcon(moreButtonArrow); downloadOptionsButton.setForeground(hyperlinkForeground); ResizeUtils.forceHeight(downloadOptionsButton, 16); downloadOptionsButton.overrideMenu(downloadMediator.getHeaderPopupMenu()); // Create options button for uploads. uploadOptionsButton = new LimeComboBox(); uploadOptionsButton.setText(I18n.tr("Options")); comboBoxDecorator.decorateMiniComboBox(uploadOptionsButton); uploadOptionsButton.setFocusable(false); uploadOptionsButton.setFont(hyperlinkFont); uploadOptionsButton.setIcon(moreButtonArrow); uploadOptionsButton.setForeground(hyperlinkForeground); ResizeUtils.forceHeight(uploadOptionsButton, 16); uploadOptionsButton.overrideMenu(uploadMediator.getHeaderPopupMenu()); } /** * Initializes the tab list to select content. */ private void initializeTabList() { // Create actions for tab list. Action downloadAction = new ShowDownloadsAction(); Action uploadAction = new ShowUploadsAction(); actionMap.put(TabId.DOWNLOADS, downloadAction); actionMap.put(TabId.UPLOADS, uploadAction); tabActionList = TabActionMap.createMapForMainActions(downloadAction, uploadAction); // Create tab list. tabList = new FancyTabList(tabActionList); // Set tab list attributes. tabList.setTabTextColor(textForeground); tabList.setTextFont(textFont); tabList.setTabTextSelectedColor(textSelectedForeground); tabList.setUnderlineEnabled(false); tabList.setSelectionPainter(new TabPainter(selectionTopGradientColor, selectionBottomGradientColor, selectionTopBorderColor, selectionBottomBorderColor)); tabList.setHighlightPainter(new TabPainter(highlightBackground, highlightBackground, highlightBorderColor, highlightBorderColor)); //preselecting tabs so the cardlayout in BottomPanel is setup appropriately. selectTab(TabId.UPLOADS); selectTab(TabId.DOWNLOADS); } /** * Returns the height of the header component. */ public int getComponentHeight() { return componentHeight; } /** * Sets the height of the header component. */ private void setComponentHeight(int height) { componentHeight = height; ResizeUtils.forceHeight(component, height); // Set the divider size of the split pane. if (parentSplitPane != null) { parentSplitPane.setDividerSize(height); } } /** * Sets the split pane for which the header serves as the divider. */ public void setParentSplitPane(JSplitPane splitPane) { this.parentSplitPane = splitPane; } /** * Selects the tab for the specified tab id. */ public void selectTab(TabId tabId) { Action mainAction = actionMap.get(tabId); List<FancyTab> tabs = tabList.getTabs(); for (FancyTab tab : tabs) { if (mainAction == tab.getTabActionMap().getMainAction()) { tab.select(); break; } } } /** * Selects the content for the specified tab id. */ private void select(TabId tabId) { bottomPanel.show(tabId); updateHeader(tabId); } /** * Updates the header title and controls. */ private void updateHeader(TabId tabId) { switch (tabId) { case DOWNLOADS: updateDownloadTitle(); downloadButtonPanel.setVisible(true); uploadButtonPanel.setVisible(false); break; case UPLOADS: updateUploadTitle(); downloadButtonPanel.setVisible(false); uploadButtonPanel.setVisible(true); break; } } /** * Updates the component layout based on the visible tables. */ private void updateLayout() { boolean downloadVisible = SwingUiSettings.SHOW_TRANSFERS_TRAY.getValue(); boolean uploadVisible = UploadSettings.SHOW_UPLOADS_IN_TRAY.getValue(); if (downloadVisible && uploadVisible) { tabList.setVisible(true); titleTextLabel.setVisible(false); setComponentHeight(26); } else { tabList.setVisible(false); titleTextLabel.setVisible(true); setComponentHeight(20); } } private void updateSelection() { boolean downloadVisible = SwingUiSettings.SHOW_TRANSFERS_TRAY.getValue(); boolean uploadVisible = UploadSettings.SHOW_UPLOADS_IN_TRAY.getValue(); if(tabList.getSelectedTab() == null || (downloadVisible && !uploadVisible)) { selectTab(TabId.DOWNLOADS); } updateLayout(); } /** * Updates title for Downloads tray. */ private void updateDownloadTitle() { String title; int size = downloadMediator.getActiveList().size(); // Create title with size and bandwidth. if (SwingUiSettings.SHOW_TOTAL_BANDWIDTH.getValue()) { int bandwidth = bandwidthCollector.getCurrentDownloaderBandwidth(); title = (size > 0) ? I18n.tr("Downloads ({0} at {1} KB/s)", size, bandwidth) : I18n.tr("Downloads"); } else { title = (size > 0) ? I18n.tr("Downloads ({0})", size) : I18n.tr("Downloads"); } // Apply title to tab action and label. actionMap.get(TabId.DOWNLOADS).putValue(Action.NAME, title); titleTextLabel.setText(title); } /** * Updates title for Uploads tray. */ private void updateUploadTitle() { String title; int size = uploadMediator.getActiveList().size(); // Create title with size and bandwidth. if (SwingUiSettings.SHOW_TOTAL_BANDWIDTH.getValue()) { int bandwidth = bandwidthCollector.getCurrentUploaderBandwidth(); title = (size > 0) ? I18n.tr("Uploads ({0} at {1} KB/s)", size, bandwidth) : I18n.tr("Uploads"); } else { title = (size > 0) ? I18n.tr("Uploads ({0})", size) : I18n.tr("Uploads"); } // Apply title to tab action and label. actionMap.get(TabId.UPLOADS).putValue(Action.NAME, title); } /** * Listener to update tab and header title when download list changes. */ private class LabelUpdateListListener implements ListEventListener<DownloadItem> { @Override public void listChanged(ListEvent<DownloadItem> listChanges) { updateDownloadTitle(); } } /** * Action to display downloads table. */ private class ShowDownloadsAction extends AbstractAction { @Override public void actionPerformed(ActionEvent e) { select(TabId.DOWNLOADS); } } /** * Action to display uploads table. */ private class ShowUploadsAction extends AbstractAction { @Override public void actionPerformed(ActionEvent e) { select(TabId.UPLOADS); uploadsViewed++; } } /** * A Painter used to render the selected or highlighted tab. */ private static class TabPainter extends RectanglePainter<FancyTab> { public TabPainter(Color topGradient, Color bottomGradient, Color topBorder, Color bottomBorder) { setFillPaint(new GradientPaint(0, 0, topGradient, 0, 1, bottomGradient)); setBorderPaint(new GradientPaint(0, 0, topBorder, 0, 1, bottomBorder)); setRoundHeight(10); setRoundWidth(10); setRounded(true); setPaintStretched(true); setInsets(new Insets(2,0,1,0)); setAntialiasing(true); setCacheable(true); } } private boolean isSelectedTab(TabId tabId) { Action mainAction = actionMap.get(tabId); FancyTab tab = tabList.getSelectedTab(); if (tab != null && mainAction == tab.getTabActionMap().getMainAction()) { return true; } return false; } @Override public void selectDownloads() { showTray(); selectTab(TabId.DOWNLOADS); } @Override public void selectUploads() { showTray(); UploadSettings.SHOW_UPLOADS_IN_TRAY.setValue(true); selectTab(TabId.UPLOADS); } @Override public void hideTray() { SwingUiSettings.SHOW_TRANSFERS_TRAY.setValue(false); } @Override public boolean isDownloadsSelected() { return isSelectedTab(TabId.DOWNLOADS); } @Override public boolean isTrayShowing() { return SwingUiSettings.SHOW_TRANSFERS_TRAY.getValue(); } @Override public boolean isUploadsSelected() { return isSelectedTab(TabId.UPLOADS); } @Override public void showTray() { SwingUiSettings.SHOW_TRANSFERS_TRAY.setValue(true); } }