Last active
February 24, 2016 13:09
-
-
Save yushijinhun/31199262cf01fa9abae3 to your computer and use it in GitHub Desktop.
Gui for jmccc-mcdownloader
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package org.to2mbn.jmccc.mcdownloader.gui; | |
import javax.swing.JFrame; | |
import javax.swing.JScrollPane; | |
import org.to2mbn.jmccc.mcdownloader.MinecraftDownloader; | |
import org.to2mbn.jmccc.mcdownloader.MinecraftDownloaderBuilder; | |
import org.to2mbn.jmccc.mcdownloader.download.combine.AbstractCombinedDownloadCallback; | |
import org.to2mbn.jmccc.option.MinecraftDirectory; | |
import org.to2mbn.jmccc.version.Version; | |
public class DownloaderExample { | |
public static void main(String[] args) throws Exception { | |
DownloadTable downloadTable = new DownloadTable(); | |
downloadTable.setRemoveDownloadAfterDone(true); | |
JFrame window = new JFrame("Downioad"); | |
window.add(new JScrollPane(downloadTable)); | |
window.setSize(640, 480); | |
window.setVisible(true); | |
MinecraftDirectory mcdir = new MinecraftDirectory("/home/yushijinhun/.minecraft"); | |
MinecraftDownloader downloader = MinecraftDownloaderBuilder.create().setMaxConnections(8000).setMaxConnectionsPerRouter(2000).build(); | |
downloader.downloadIncrementally(mcdir, "16w06a", downloadTable.display(new AbstractCombinedDownloadCallback<Version>() { | |
@Override | |
public void failed(Throwable e) { | |
e.printStackTrace(); | |
cleanup(); | |
} | |
@Override | |
public void done(Version result) { | |
cleanup(); | |
} | |
@Override | |
public void cancelled() { | |
System.err.println("cancelled"); | |
cleanup(); | |
} | |
private void cleanup() { | |
window.dispose(); | |
downloader.shutdown(); | |
} | |
})); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package org.to2mbn.jmccc.mcdownloader.gui; | |
import java.awt.event.ActionEvent; | |
import java.awt.event.ActionListener; | |
import java.net.URI; | |
import java.util.Vector; | |
import java.util.concurrent.atomic.AtomicInteger; | |
import java.util.concurrent.atomic.AtomicLong; | |
import javax.swing.JTable; | |
import javax.swing.SwingUtilities; | |
import javax.swing.Timer; | |
import javax.swing.event.TableModelEvent; | |
import javax.swing.event.TableModelListener; | |
import javax.swing.table.TableModel; | |
import org.to2mbn.jmccc.mcdownloader.download.DownloadCallback; | |
import org.to2mbn.jmccc.mcdownloader.download.DownloadCallbackGroup; | |
import org.to2mbn.jmccc.mcdownloader.download.DownloadTask; | |
import org.to2mbn.jmccc.mcdownloader.download.combine.CombinedDownloadCallback; | |
public class DownloadTable extends JTable { | |
private static class DownloadInfoElement { | |
private volatile int index; | |
private URI uri; | |
private volatile String status; | |
} | |
private static final long serialVersionUID = 1L; | |
/** | |
* Stores the download tasks The index is the row number | |
*/ | |
private Vector<DownloadInfoElement> tasks = new Vector<>(); | |
/** | |
* The table model listeners | |
*/ | |
private Vector<TableModelListener> listeners = new Vector<>(); | |
private TableModel model; | |
private boolean removeDownloadAfterDone = true; | |
private AtomicLong downloadedCount = new AtomicLong(); | |
private AtomicInteger tasksCount = new AtomicInteger(); | |
private Timer speedTimer; | |
private volatile long currentSpeed; | |
public DownloadTable() { | |
model = new DownloadTableModel(); | |
setModel(model); | |
speedTimer = new Timer(1000, new ActionListener() { | |
@Override | |
public void actionPerformed(ActionEvent e) { | |
currentSpeed = downloadedCount.getAndSet(0); | |
updateTotalRow(); | |
} | |
}); | |
speedTimer.setInitialDelay(0); | |
} | |
public <T> CombinedDownloadCallback<T> display() { | |
return display(null); | |
} | |
public <T> CombinedDownloadCallback<T> display(CombinedDownloadCallback<T> callback) { | |
return new DownloadListener<T>(callback); | |
} | |
public boolean isRemoveDownloadAfterDone() { | |
return removeDownloadAfterDone; | |
} | |
public void setRemoveDownloadAfterDone(boolean removeDownloadAfterDone) { | |
this.removeDownloadAfterDone = removeDownloadAfterDone; | |
} | |
private class DownloadTableModel implements TableModel { | |
private static final int COLUMN_URL = 0; | |
private static final int COLUMN_STATUS = 1; | |
@Override | |
public int getRowCount() { | |
return tasks.size() + 1; | |
} | |
@Override | |
public int getColumnCount() { | |
// two columns - URL, Status | |
return 2; | |
} | |
@Override | |
public String getColumnName(int columnIndex) { | |
switch (columnIndex) { | |
case COLUMN_URL: | |
return "URL"; | |
case COLUMN_STATUS: | |
return "Status"; | |
default: | |
throw new IndexOutOfBoundsException(String.valueOf(columnIndex)); | |
} | |
} | |
@Override | |
public Class<?> getColumnClass(int columnIndex) { | |
switch (columnIndex) { | |
case COLUMN_URL: | |
return URI.class; | |
case COLUMN_STATUS: | |
return String.class; | |
default: | |
throw new IndexOutOfBoundsException(String.valueOf(columnIndex)); | |
} | |
} | |
@Override | |
public boolean isCellEditable(int rowIndex, int columnIndex) { | |
return false; | |
} | |
@Override | |
public Object getValueAt(int rowIndex, int columnIndex) { | |
if (rowIndex == tasks.size()) { | |
switch (columnIndex) { | |
case 0: | |
return "Total:"; | |
case 1: | |
return getCurrentSpeed() / 1024 + "kb/s"; | |
default: | |
throw new IndexOutOfBoundsException(String.valueOf(columnIndex)); | |
} | |
} | |
DownloadInfoElement element = tasks.get(rowIndex); | |
switch (columnIndex) { | |
case COLUMN_URL: | |
return element.uri; | |
case COLUMN_STATUS: | |
return element.status; | |
default: | |
throw new IndexOutOfBoundsException(String.valueOf(columnIndex)); | |
} | |
} | |
@Override | |
public void setValueAt(Object aValue, int rowIndex, int columnIndex) { | |
throw new UnsupportedOperationException("Modifying this table is not allowed."); | |
} | |
@Override | |
public void addTableModelListener(TableModelListener l) { | |
listeners.add(l); | |
} | |
@Override | |
public void removeTableModelListener(TableModelListener l) { | |
listeners.remove(l); | |
} | |
} | |
private class DownloadListener<T> implements CombinedDownloadCallback<T> { | |
private CombinedDownloadCallback<T> proxied; | |
public DownloadListener(CombinedDownloadCallback<T> proxied) { | |
this.proxied = proxied; | |
} | |
@Override | |
public void done(T result) { | |
if (proxied != null) { | |
proxied.done(result); | |
} | |
} | |
@Override | |
public void failed(Throwable e) { | |
if (proxied != null) { | |
proxied.failed(e); | |
} | |
} | |
@Override | |
public void cancelled() { | |
if (proxied != null) { | |
proxied.cancelled(); | |
} | |
} | |
@Override | |
public <R> DownloadCallback<R> taskStart(DownloadTask<R> task) { | |
tasksCountup(); | |
DownloadInfoElement element = new DownloadInfoElement(); | |
element.uri = task.getURI(); | |
element.status = "Waiting"; | |
SwingUtilities.invokeLater(() -> { | |
int id = tasks.size(); | |
element.index = id; | |
tasks.add(element); | |
listeners.forEach(l -> l.tableChanged(new TableModelEvent(model, element.index, element.index, TableModelEvent.ALL_COLUMNS, TableModelEvent.INSERT))); | |
}); | |
DownloadCallback<R> monitor = new DownloadCallback<R>() { | |
private AtomicLong lastProgress = new AtomicLong(); | |
@Override | |
public void done(R result) { | |
tasksCountdown(); | |
element.status = "Done"; | |
elementChanged(); | |
if (removeDownloadAfterDone) { | |
SwingUtilities.invokeLater(() -> { | |
int index = element.index; | |
tasks.remove(index); | |
for (int i = index; i < tasks.size(); i++) { | |
tasks.get(i).index--; | |
} | |
listeners.forEach(l -> l.tableChanged(new TableModelEvent(model, element.index, element.index, TableModelEvent.ALL_COLUMNS, TableModelEvent.DELETE))); | |
}); | |
} | |
} | |
@Override | |
public void failed(Throwable e) { | |
tasksCountdown(); | |
element.status = "Failure: " + e; | |
elementChanged(); | |
} | |
@Override | |
public void cancelled() { | |
tasksCountdown(); | |
element.status = "Cancelled"; | |
elementChanged(); | |
} | |
@Override | |
public void updateProgress(long done, long total) { | |
long downloaded = done - lastProgress.getAndSet(done); | |
if (downloaded > 0) { | |
downloadedCount.getAndAdd(downloaded); | |
} | |
element.status = String.format("%d/%dkb", done / 1024, total / 1024); | |
elementChanged(); | |
} | |
@Override | |
public void retry(Throwable e, int current, int max) { | |
lastProgress.set(0); | |
element.status = String.format("Retry: %d/%d: %s", current, max, e); | |
elementChanged(); | |
} | |
private void elementChanged() { | |
SwingUtilities.invokeLater(() -> listeners.forEach(l -> l.tableChanged(new TableModelEvent(model, element.index, element.index, DownloadTableModel.COLUMN_STATUS, TableModelEvent.UPDATE)))); | |
} | |
}; | |
DownloadCallback<R> extra = proxied == null ? null : proxied.taskStart(task); | |
if (extra == null) { | |
return monitor; | |
} else { | |
return DownloadCallbackGroup.group(monitor, extra); | |
} | |
} | |
} | |
private void tasksCountup() { | |
int currentCount = tasksCount.getAndIncrement(); | |
if (currentCount < 0) { | |
throw new IllegalStateException("tasksCount = " + currentCount); | |
} else if (currentCount == 0) { | |
speedTimer.start(); | |
} | |
} | |
private void tasksCountdown() { | |
int currentCount = tasksCount.getAndDecrement(); | |
if (currentCount < 1) { | |
throw new IllegalStateException("tasksCount = " + currentCount); | |
} else if (currentCount == 1) { | |
speedTimer.stop(); | |
updateTotalRow(); | |
} | |
} | |
private long getCurrentSpeed() { | |
if (speedTimer.isRunning()) { | |
return currentSpeed; | |
} else { | |
return 0; | |
} | |
} | |
private void updateTotalRow() { | |
SwingUtilities.invokeLater(() -> { | |
int elementIndex = tasks.size(); | |
listeners.forEach(l -> l.tableChanged(new TableModelEvent(model, elementIndex, elementIndex, 1, TableModelEvent.UPDATE))); | |
}); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment