package org.ripple.power.ui; import java.awt.BorderLayout; import java.awt.Component; import java.awt.Dimension; import java.awt.Window; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import javax.swing.*; import java.io.InputStream; import java.io.RandomAccessFile; import java.net.HttpURLConnection; import java.net.URL; import java.util.ArrayList; import java.util.Observable; import java.util.Observer; import javax.swing.border.TitledBorder; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import javax.swing.table.AbstractTableModel; import javax.swing.table.TableCellRenderer; import org.ripple.power.config.LSystem; import org.ripple.power.ui.graphics.LColor; import org.ripple.power.ui.view.ABaseDialog; import org.ripple.power.ui.view.RPTextBox; import org.ripple.power.ui.view.log.ErrorLog; import org.ripple.power.utils.SwingUtils; public class RPDownloadDialog extends ABaseDialog implements Observer { public class Download extends Observable implements Runnable { public static final int READY = 0; public static final int DOWNLOADING = 1; public static final int PAUSED = 2; public static final int COMPLETE = 3; public static final int CANCELLED = 4; public static final int ERROR = 5; protected String errorMessage; protected int downloaded; protected int size; protected int state; protected URL url; protected String urlString; protected HttpURLConnection connection; protected RandomAccessFile file; protected InputStream stream; protected static final int MAX_BUFFER_SIZE = 1024; public Download(String urlString) { downloaded = 0; size = -1; this.urlString = urlString; errorMessage = ""; initialize(); state = READY; } public void initialize() { try { url = new URL(urlString); if (LSystem.applicationProxy != null) { connection = (HttpURLConnection) url .openConnection(LSystem.applicationProxy.getProxy()); } else { connection = (HttpURLConnection) url.openConnection(); } connection.setRequestProperty("Range", "bytes=" + downloaded + "-"); connection.connect(); if (connection.getResponseCode() / 100 != 2) { state = ERROR; errorMessage = "Bad response code: " + connection.getResponseCode() + ", " + connection.getResponseMessage(); stateChanged(); } int contentLength = connection.getContentLength(); if (contentLength < 1) { state = Download.ERROR; errorMessage = "Bad content length: " + contentLength; stateChanged(); } if (size == -1) { size = contentLength; } file = new RandomAccessFile(LSystem.getCurrentDirectory() + getFileName(), "rw"); file.seek(downloaded); stream = connection.getInputStream(); } catch (Exception e) { state = Download.ERROR; e.printStackTrace(); errorMessage = "Exception: " + e.getMessage(); stateChanged(); } } public void download() { if (state == READY) { state = DOWNLOADING; } try { while (state == DOWNLOADING) { byte[] buffer; if (size - downloaded > MAX_BUFFER_SIZE) { buffer = new byte[MAX_BUFFER_SIZE]; } else { buffer = new byte[size - downloaded]; } int read = stream.read(buffer); if (read == -1) { break; } file.write(buffer, 0, read); downloaded += read; stateChanged(); } if (state == DOWNLOADING) { state = COMPLETE; } } catch (Exception e) { state = Download.ERROR; e.printStackTrace(); errorMessage = "Exception: " + e.getMessage(); stateChanged(); } } public void start() { state = DOWNLOADING; stateChanged(); download(); } public void pause() { state = PAUSED; stateChanged(); } public void resume() { state = DOWNLOADING; stateChanged(); download(); } public void cancel() { state = CANCELLED; stateChanged(); } public void error() { state = Download.ERROR; stateChanged(); } public int getProgress() { return (int) ((float) downloaded / size * 100); } public int getState() { return state; } public String getStateName() { switch (state) { case READY: return "Ready"; case DOWNLOADING: return "Downloading"; case Download.ERROR: return "Error"; case PAUSED: return "Paused"; case COMPLETE: return "Complete"; case CANCELLED: return "Cancelled"; default: return "Unknown"; } } public String getError() { return errorMessage; } public String getSize() { if (size / 1024 <= 0) { return size + " B"; } else if (size / (1024 * 1024) <= 0) { return (size / 1024) + " KB"; } else if (size / (1024 * 1024 * 1024) <= 0) { return (size / (1024 * 1024)) + " MB"; } else { return (size / (1024 * 1024 * 1024)) + " GB"; } } public String getFileName() { String fileName = url.getFile(); return fileName.substring(fileName.lastIndexOf("/") + 1); } private void stateChanged() { setChanged(); notifyObservers(); } public void run() { initialize(); download(); } } public class DownloadPrgBar extends JProgressBar implements TableCellRenderer { /** * */ private static final long serialVersionUID = 1L; public DownloadPrgBar(int min, int max) { super(min, max); } @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { if (value instanceof Integer) { setValue((int) value); } else { setValue((int) ((Float) value).floatValue()); } return this; } } public static class DownloadTable extends AbstractTableModel implements Observer { /** * */ private static final long serialVersionUID = 1L; private static final String[] columns = { "Name", "Size", "State", "Progress" }; private static final Class<?>[] colClasses = { String.class, String.class, String.class, JProgressBar.class }; private static ArrayList<Download> downloads = new ArrayList<Download>(); public void addDownload(Download newDownload) { newDownload.addObserver(this); downloads.add(newDownload); fireTableRowsInserted(getRowCount() - 1, getRowCount() - 1); } public Download getDownload(int row) { return downloads.get(row); } public void removeDownload(int row) { downloads.remove(row); fireTableRowsDeleted(row, row); } @Override public String getColumnName(int row) { return columns[row]; } @Override public int getRowCount() { return downloads.size(); } @Override public int getColumnCount() { return columns.length; } public Class<?> getColumnClass(int col) { return colClasses[col]; } @Override public Object getValueAt(int rowIndex, int columnIndex) { switch (columnIndex) { case 0: return downloads.get(rowIndex).getFileName(); case 1: return downloads.get(rowIndex).getSize(); case 2: return downloads.get(rowIndex).getStateName(); case 3: return downloads.get(rowIndex).getProgress(); } return null; } @Override public void update(Observable o, Object arg) { int index = downloads.indexOf(arg); fireTableRowsUpdated(index, index); } } /** * */ private static final long serialVersionUID = 1L; private DownloadTable downloadTable; private RPCButton btnPause, btnRemove, btnResume, btnCancel, btnDownload; private Download selectedDownload; private RPTextBox txtAdd; private JTable table; private boolean isRemoving = false; public static void showDialog(Window parent) { try { RPDownloadDialog dialog = new RPDownloadDialog(parent); dialog.pack(); dialog.setLocationRelativeTo(parent); dialog.setVisible(true); } catch (Exception exc) { ErrorLog.get().logException("RPDownloadDialog Exception", exc); } } public RPDownloadDialog(Window parent) { super(parent, "Download", ModalityType.MODELESS); setIconImage(UIRes.getIcon()); Dimension dim = new Dimension(590, 400); setPreferredSize(dim); setSize(dim); setResizable(false); addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { SwingUtils.close(RPDownloadDialog.this); } }); JPanel addPanel = new JPanel(); txtAdd = new RPTextBox(30); addPanel.add(txtAdd); RPCButton addButton = new RPCButton("Add Download"); addButton.setIcon(UIRes.getImage("images/add.png")); addButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { actionAdd(); } }); addPanel.add(addButton); downloadTable = new DownloadTable(); table = new JTable(downloadTable); table.getSelectionModel().addListSelectionListener( new ListSelectionListener() { public void valueChanged(ListSelectionEvent e) { tableSelectionChanged(); } }); UIRes.addStyle(table); table.getTableHeader().setBackground(UIConfig.dialogbackground); table.getTableHeader().setForeground(LColor.white); table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); DownloadPrgBar progressBar = new DownloadPrgBar(0, 100); progressBar.setStringPainted(true); table.setDefaultRenderer(JProgressBar.class, progressBar); table.setRowHeight((int) progressBar.getPreferredSize().getHeight()); JPanel downloadsPanel = new JPanel(); TitledBorder border = BorderFactory.createTitledBorder("Downloads"); downloadsPanel.setForeground(LColor.white); border.setTitleColor(LColor.white); downloadsPanel.setBorder(border); downloadsPanel.setLayout(new BorderLayout()); downloadsPanel.add(new JScrollPane(table), BorderLayout.CENTER); JPanel buttonsPanel = new JPanel(); btnPause = new RPCButton("Pause"); btnPause.setIcon(UIRes.getImage("images/stop.png")); btnPause.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { actionPause(); } }); btnPause.setEnabled(false); btnResume = new RPCButton("Resume"); btnResume.setIcon(UIRes.getImage("images/reset.png")); btnResume.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { actionResume(); } }); btnCancel = new RPCButton("Cancel"); btnCancel.setIcon(UIRes.getImage("images/exit.png")); btnCancel.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { actionCancel(); } }); btnCancel.setEnabled(false); btnRemove = new RPCButton("Remove"); btnRemove.setIcon(UIRes.getImage("images/remove.png")); btnRemove.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { actionRemove(); } }); btnDownload = new RPCButton("Download"); btnDownload.setIcon(UIRes.getImage("images/download.png")); btnDownload.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { actionStart(); } }); btnDownload.setEnabled(false); buttonsPanel.add(btnPause); buttonsPanel.add(btnResume); buttonsPanel.add(btnCancel); buttonsPanel.add(btnRemove); buttonsPanel.add(btnDownload); getContentPane().setLayout(new BorderLayout()); getContentPane().add(addPanel, BorderLayout.NORTH); getContentPane().add(downloadsPanel, BorderLayout.CENTER); getContentPane().add(buttonsPanel, BorderLayout.SOUTH); downloadsPanel.setBackground(UIConfig.dialogbackground); buttonsPanel.setBackground(UIConfig.dialogbackground); addPanel.setBackground(UIConfig.dialogbackground); } private void actionPause() { selectedDownload.pause(); updateButtons(); } private void actionResume() { selectedDownload.resume(); updateButtons(); } private void actionCancel() { selectedDownload.cancel(); updateButtons(); } private void actionRemove() { isRemoving = true; downloadTable.removeDownload(table.getSelectedRow()); selectedDownload = null; updateButtons(); isRemoving = false; } private void actionStart() { selectedDownload.start(); updateButtons(); } private void actionAdd() { String url = txtAdd.getText(); if (tryURL(url)) { downloadTable.addDownload(new Download(url)); txtAdd.setText(""); } else { alert("Invalid URL"); } } private void tableSelectionChanged() { if (selectedDownload != null) { selectedDownload.deleteObserver(this); } if (!isRemoving && table.getSelectedRow() != -1) { selectedDownload = downloadTable .getDownload(table.getSelectedRow()); selectedDownload.addObserver(this); updateButtons(); } } private void updateButtons() { if (selectedDownload != null) { switch (selectedDownload.state) { case Download.READY: btnPause.setEnabled(false); btnResume.setEnabled(false); btnCancel.setEnabled(false); btnRemove.setEnabled(true); btnDownload.setEnabled(true); break; case Download.DOWNLOADING: btnPause.setEnabled(true); btnResume.setEnabled(false); btnCancel.setEnabled(false); btnRemove.setEnabled(false); btnDownload.setEnabled(false); break; case Download.PAUSED: btnPause.setEnabled(false); btnResume.setEnabled(true); btnCancel.setEnabled(true); btnRemove.setEnabled(false); btnDownload.setEnabled(false); break; case Download.ERROR: btnPause.setEnabled(false); btnResume.setEnabled(false); btnCancel.setEnabled(false); btnRemove.setEnabled(true); btnDownload.setEnabled(false); break; case Download.COMPLETE: btnPause.setEnabled(false); btnResume.setEnabled(false); btnCancel.setEnabled(false); btnRemove.setEnabled(true); btnDownload.setEnabled(false); break; case Download.CANCELLED: btnPause.setEnabled(false); btnResume.setEnabled(false); btnCancel.setEnabled(false); btnRemove.setEnabled(true); btnDownload.setEnabled(false); break; default: btnPause.setEnabled(false); btnResume.setEnabled(false); btnCancel.setEnabled(false); btnRemove.setEnabled(false); btnDownload.setEnabled(false); break; } } else { btnPause.setEnabled(false); btnResume.setEnabled(false); btnCancel.setEnabled(false); btnRemove.setEnabled(false); } } private boolean tryURL(String url) { if (url.startsWith("http://") || url.startsWith("https://")) { return true; } return false; } @Override public void update(Observable o, Object arg) { if (selectedDownload != null && selectedDownload.equals(o)) { updateButtons(); } } }