package comeon.ui.actions; import com.google.common.eventbus.Subscribe; import com.google.inject.Inject; import com.google.inject.Singleton; import comeon.core.ProgressListenerAdapter; import comeon.core.events.*; import comeon.model.Media; import comeon.ui.UI; import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.KeyEvent; import java.io.File; import java.text.MessageFormat; import java.util.HashMap; import java.util.Locale; import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; @Singleton public final class TransferMonitor extends JOptionPane { private static final long serialVersionUID = 1L; private final JDialog dialog; private final JProgressBar batchBar; private final Box mediaBarsBox; private final JScrollPane mediaBarsPane; private final CloseAction closeAction; private final Map<File, ProgressPanel> panels; private final AtomicInteger transferCounter; @Inject public TransferMonitor(final AbortAction abortAction, final BrowseToReportAction reportAction, final UI ui) { super(null, JOptionPane.INFORMATION_MESSAGE, JOptionPane.DEFAULT_OPTION, UploadMediaAction.ICON, null); this.getInputMap(JOptionPane.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("pressed ESCAPE"), "none"); this.batchBar = new JProgressBar(SwingConstants.HORIZONTAL); this.batchBar.setStringPainted(true); this.mediaBarsBox = Box.createVerticalBox(); this.mediaBarsPane = new JScrollPane(mediaBarsBox, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); this.setMessage(new Object[]{batchBar, mediaBarsPane}); final Rectangle screenSize = GraphicsEnvironment.getLocalGraphicsEnvironment().getMaximumWindowBounds(); this.dialog = this.createDialog(ui, UI.BUNDLE.getString("upload.title")); this.dialog.setResizable(true); this.dialog.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); this.dialog.setIconImages(UI.ICON_IMAGES); this.dialog.setSize(new Dimension(screenSize.width / 2, screenSize.height / 2)); this.dialog.setLocationRelativeTo(ui); this.closeAction = new CloseAction(); this.setOptions(new Object[]{new JButton(closeAction), new JButton(abortAction), new JButton(reportAction)}); this.panels = new HashMap<>(); this.transferCounter = new AtomicInteger(0); this.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "abort"); this.getActionMap().put("abort", abortAction); } @Subscribe public void uploadStarting(final UploadStartingEvent event) { for (final Media media : event.getMedia()) { final ProgressPanel panel = new ProgressPanel(media.getFile().length(), media.getFileName()); panels.put(media.getFile(), panel); SwingUtilities.invokeLater(() -> mediaBarsBox.add(panel)); } transferCounter.set(0); SwingUtilities.invokeLater(() -> { batchBar.setMaximum(event.getMedia().size()); batchBar.setValue(transferCounter.get()); dialog.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); closeAction.setEnabled(false); dialog.setVisible(true); }); } @Subscribe public void transferStarting(final MediaTransferStartingEvent event) { final ProgressPanel panel = panels.get(event.getMedia().getFile()); event.getProgressListener().addPropertyChangeListener(ProgressListenerAdapter.TRANSFERRED, evt -> SwingUtilities.invokeLater(() -> { final Long transferred = (Long) evt.getNewValue(); panel.getMediaBar().setValue(transferred.intValue()); })); SwingUtilities.invokeLater(() -> mediaBarsPane.getViewport().scrollRectToVisible(panel.getBounds())); } @Subscribe public void transferDone(final MediaTransferDoneEvent event) { SwingUtilities.invokeLater(() -> batchBar.setValue(transferCounter.incrementAndGet())); } @Subscribe public void transferFailed(final MediaTransferFailedEvent event) { final JProgressBar mediaProgressBar = panels.get(event.getMedia().getFile()).getMediaBar(); SwingUtilities.invokeLater(() -> { mediaProgressBar.setValue(mediaProgressBar.getMaximum()); mediaProgressBar.setString(UI.BUNDLE.getString("error.generic.title")); mediaProgressBar.setToolTipText(MessageFormat.format(UI.BUNDLE.getString("error.upload.failed"), event.getCause().getLocalizedMessage())); }); } @Subscribe public void uploadDone(final UploadDoneEvent event) { SwingUtilities.invokeLater(() -> { TransferMonitor.this.dialog.setCursor(Cursor.getDefaultCursor()); TransferMonitor.this.closeAction.setEnabled(true); }); } private final class CloseAction extends AbstractAction { private static final long serialVersionUID = 1L; public CloseAction() { super(UIManager.getString("OptionPane.okButtonText", Locale.getDefault())); } @Override public void actionPerformed(final ActionEvent e) { new SwingWorker<Void, Void>() { @Override protected Void doInBackground() throws Exception { panels.clear(); SwingUtilities.invokeLater(() -> { dialog.setVisible(false); mediaBarsBox.removeAll(); }); return null; } }.execute(); } } static class ProgressPanel extends Box { private static final long serialVersionUID = 1L; private final JProgressBar mediaBar; public ProgressPanel(final long length, final String name) { super(BoxLayout.Y_AXIS); final JLabel label = new JLabel(name); label.setBorder(BorderFactory.createEmptyBorder(1, 1, 1, 1)); label.setToolTipText(name); this.setBackground(Color.WHITE); this.setOpaque(true); this.mediaBar = new JProgressBar(SwingConstants.HORIZONTAL); this.mediaBar.setStringPainted(true); this.mediaBar.setMaximum((int) length); this.mediaBar.setValue(0); this.mediaBar.setBorder(BorderFactory.createEmptyBorder(1, 1, 1, 1)); this.add(label); this.add(this.mediaBar); this.setBorder(BorderFactory.createEmptyBorder(4, 4, 4, 4)); } public JProgressBar getMediaBar() { return mediaBar; } } }