/**
* Created : May 26, 2012
*
* @author pquiring
*/
import java.io.*;
import java.net.*;
import java.util.*;
import javax.net.ssl.*;
import javax.swing.*;
import javax.swing.table.*;
import javax.swing.filechooser.*;
import javaforce.*;
import javaforce.linux.*;
public class MainPanel extends javax.swing.JPanel {
/**
* Creates new form MainPanel
*/
public MainPanel() {
initComponents();
This = this;
tableModel = (DefaultTableModel)table.getModel();
new File(JF.getUserPath() + "/Torrents").mkdirs();
// JFLog.init(JF.getUserPath() + "/.jftorrent.log", true);
loadConfig();
updateList();
startServer();
startTorrents();
initHttps();
java.util.Timer timer = new java.util.Timer();
timer.schedule(new TimerTask() {
public void run() {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
updateGUI();
}
});
}
}, 5000, 5000);
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
jToolBar1 = new javax.swing.JToolBar();
addFile = new javax.swing.JButton();
addURL = new javax.swing.JButton();
jSeparator1 = new javax.swing.JToolBar.Separator();
delete = new javax.swing.JButton();
jSeparator2 = new javax.swing.JToolBar.Separator();
start = new javax.swing.JButton();
pause = new javax.swing.JButton();
stop = new javax.swing.JButton();
jSeparator3 = new javax.swing.JToolBar.Separator();
editConfig = new javax.swing.JButton();
jSeparator5 = new javax.swing.JToolBar.Separator();
status = new javax.swing.JLabel();
jSplitPane2 = new javax.swing.JSplitPane();
jScrollPane1 = new javax.swing.JScrollPane();
list = new javax.swing.JList();
jScrollPane2 = new javax.swing.JScrollPane();
table = new javax.swing.JTable();
jToolBar1.setFloatable(false);
jToolBar1.setRollover(true);
addFile.setText("Add File");
addFile.setFocusable(false);
addFile.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
addFile.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
addFile.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
addFileActionPerformed(evt);
}
});
jToolBar1.add(addFile);
addURL.setText("Add URL");
addURL.setFocusable(false);
addURL.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
addURL.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
addURL.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
addURLActionPerformed(evt);
}
});
jToolBar1.add(addURL);
jToolBar1.add(jSeparator1);
delete.setText("Delete");
delete.setFocusable(false);
delete.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
delete.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
delete.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
deleteActionPerformed(evt);
}
});
jToolBar1.add(delete);
jToolBar1.add(jSeparator2);
start.setText("Start");
start.setFocusable(false);
start.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
start.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
start.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
startActionPerformed(evt);
}
});
jToolBar1.add(start);
pause.setText("Pause");
pause.setFocusable(false);
pause.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
pause.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
pause.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
pauseActionPerformed(evt);
}
});
jToolBar1.add(pause);
stop.setText("Stop");
stop.setFocusable(false);
stop.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
stop.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
stop.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
stopActionPerformed(evt);
}
});
jToolBar1.add(stop);
jToolBar1.add(jSeparator3);
editConfig.setText("Config");
editConfig.setFocusable(false);
editConfig.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
editConfig.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
editConfig.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
editConfigActionPerformed(evt);
}
});
jToolBar1.add(editConfig);
jToolBar1.add(jSeparator5);
status.setText("Status:?");
jToolBar1.add(status);
jSplitPane2.setDividerLocation(150);
jSplitPane2.setResizeWeight(0.1);
list.setModel(listModel);
list.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
list.addListSelectionListener(new javax.swing.event.ListSelectionListener() {
public void valueChanged(javax.swing.event.ListSelectionEvent evt) {
listValueChanged(evt);
}
});
jScrollPane1.setViewportView(list);
jSplitPane2.setLeftComponent(jScrollPane1);
table.setModel(new javax.swing.table.DefaultTableModel(
new Object [][] {
},
new String [] {
"Name", "#", "Size", "Done", "Status", "Seeds", "Peers", "Down Speed", "Up Speed", "ETA", "Uploaded", "Ratio", "Available"
}
) {
Class[] types = new Class [] {
java.lang.String.class, java.lang.Integer.class, java.lang.String.class, java.lang.String.class, java.lang.String.class, java.lang.String.class, java.lang.String.class, java.lang.String.class, java.lang.String.class, java.lang.String.class, java.lang.String.class, java.lang.String.class, java.lang.String.class
};
boolean[] canEdit = new boolean [] {
false, false, false, false, false, false, false, false, false, false, false, false, false
};
public Class getColumnClass(int columnIndex) {
return types [columnIndex];
}
public boolean isCellEditable(int rowIndex, int columnIndex) {
return canEdit [columnIndex];
}
});
jScrollPane2.setViewportView(table);
jSplitPane2.setRightComponent(jScrollPane2);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jToolBar1, javax.swing.GroupLayout.DEFAULT_SIZE, 609, Short.MAX_VALUE)
.addComponent(jSplitPane2, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE)
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(jToolBar1, javax.swing.GroupLayout.PREFERRED_SIZE, 25, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jSplitPane2, javax.swing.GroupLayout.DEFAULT_SIZE, 519, Short.MAX_VALUE))
);
}// </editor-fold>//GEN-END:initComponents
private void addFileActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_addFileActionPerformed
addFile();
updateList();
}//GEN-LAST:event_addFileActionPerformed
private void editConfigActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_editConfigActionPerformed
int orgPort = TorrentServer.port;
ConfigDialog dialog = new ConfigDialog(null, true);
dialog.setVisible(true);
if (!dialog.accepted) return;
if (config.port == orgPort) return;
saveConfig();
server.changePort(config.port);
status.setText("?");
for(int a=0;a<clients.size();a++) {
clients.get(a).recontactTracker();
}
}//GEN-LAST:event_editConfigActionPerformed
private void addURLActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_addURLActionPerformed
addURL();
updateList();
}//GEN-LAST:event_addURLActionPerformed
private void listValueChanged(javax.swing.event.ListSelectionEvent evt) {//GEN-FIRST:event_listValueChanged
updateTable();
}//GEN-LAST:event_listValueChanged
private void deleteActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deleteActionPerformed
int row = table.getSelectedRow();
if (row == -1) return;
int idx = (Integer)table.getValueAt(row, 1);
TorrentClient client = clients.get(idx);
client.close();
clients.remove(client);
removeTorrent(idx);
updateTable();
updateList();
}//GEN-LAST:event_deleteActionPerformed
private void startActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_startActionPerformed
int row = table.getSelectedRow();
if (row == -1) return;
int idx = (Integer)table.getValueAt(row, 1);
TorrentClient client = clients.get(idx);
client._start();
config.torrent[idx].active = true;
config.torrent[idx].paused = false;
saveConfig();
}//GEN-LAST:event_startActionPerformed
private void pauseActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_pauseActionPerformed
int row = table.getSelectedRow();
if (row == -1) return;
int idx = (Integer)table.getValueAt(row, 1);
TorrentClient client = clients.get(idx);
client.pause();
config.torrent[idx].paused = true;
saveConfig();
}//GEN-LAST:event_pauseActionPerformed
private void stopActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_stopActionPerformed
int row = table.getSelectedRow();
if (row == -1) return;
int idx = (Integer)table.getValueAt(row, 1);
TorrentClient client = clients.get(idx);
client._stop();
config.torrent[idx].active = false;
saveConfig();
}//GEN-LAST:event_stopActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton addFile;
private javax.swing.JButton addURL;
private javax.swing.JButton delete;
private javax.swing.JButton editConfig;
private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JScrollPane jScrollPane2;
private javax.swing.JToolBar.Separator jSeparator1;
private javax.swing.JToolBar.Separator jSeparator2;
private javax.swing.JToolBar.Separator jSeparator3;
private javax.swing.JToolBar.Separator jSeparator5;
private javax.swing.JSplitPane jSplitPane2;
private javax.swing.JToolBar jToolBar1;
private javax.swing.JList list;
private javax.swing.JButton pause;
private javax.swing.JButton start;
private javax.swing.JLabel status;
private javax.swing.JButton stop;
private javax.swing.JTable table;
// End of variables declaration//GEN-END:variables
private ArrayList<TorrentClient> clients = new ArrayList<TorrentClient>();
public static Config config;
private String configFolder = JF.getUserPath();
private String configFile = "/.jftorrent.xml";
private TorrentServer server;
private DefaultListModel listModel = new DefaultListModel();
private DefaultTableModel tableModel;
public static MainPanel This;
public static class Torrent {
public String file;
public String dest;
public boolean active = true, paused = false;
}
public static class Config {
public Torrent torrent[];
public int port;
}
private void loadConfig() {
defaultConfig();
try {
XML xml = new XML();
FileInputStream fis = new FileInputStream(configFolder + configFile);
xml.read(fis);
xml.writeClass(config);
} catch (FileNotFoundException e1) {
defaultConfig();
} catch (Exception e2) {
JFLog.log(e2);
defaultConfig();
}
}
private void defaultConfig() {
config = new Config();
config.torrent = new Torrent[0];
config.port = 6881;
}
private void saveConfig() {
try {
XML xml = new XML();
FileOutputStream fos = new FileOutputStream(configFolder + configFile);
xml.readClass("jftorrent", config);
xml.write(fos);
fos.close();
} catch (Exception e) {
JFLog.log(e);
}
}
private void startServer() {
server = new TorrentServer(config.port);
server.start();
}
private void startTorrents() {
for(int a=0;a<config.torrent.length;a++) {
startTorrent(config.torrent[a].file, config.torrent[a].dest, config.torrent[a].active, config.torrent[a].paused);
}
}
private boolean startTorrent(String file, String dest, boolean active, boolean paused) {
int size = clients.size();
for(int a=0;a<size;a++) {
if (clients.get(a).torrent.equals(file)) return false;
}
TorrentClient client = new TorrentClient(file, dest, active, paused);
client.start();
clients.add(client);
updateList();
updateTable();
return true;
}
public void updateList() {
int idx = list.getSelectedIndex();
listModel.removeAllElements();
int downloading = 0;
int seeding = 0;
// int active = 0;
// int inactive = 0;
int size = clients.size();
for(int a=0;a<size;a++) {
TorrentClient client = clients.get(a);
if (client.done) seeding++; else downloading++;
// active++;
}
listModel.addElement("All (" + size + ")");
listModel.addElement("Downloading (" + downloading + ")");
listModel.addElement("Seeding (" + seeding + ")");
// listModel.addElement("Active (" + active + ")");
// listModel.addElement("Inactive (" + inactive + ")");
list.setSelectedIndex(idx);
}
private String sizeToString(long size) {
if (size < 1024 * 1024) return "" + size/1024 + "KBs";
if (size < 1024 * 1024 * 1024) return "" + size/(1024 * 1024) + "MBs";
return "" + size/(1024 * 1024 * 1024) + "GBs";
}
private String calcETA(TorrentClient client) {
if (client.totalLength == client.downAmount) return "Done";
int downSpeed = client.downSpeed;
if (downSpeed == 0) return "inf";
int seconds = (int)((client.totalLength - client.downAmount) / downSpeed);
int minutes = seconds / 60;
seconds = seconds - (minutes * 60);
int hours = minutes / 60;
minutes = minutes - (hours * 60);
return String.format("%02d:%02d:%02d", hours,minutes,seconds);
}
private void addRow(TorrentClient client, int idx) {
//name, #, size, done, status, seeds, peers, downSpeed, upSpeed, ETA, uploaded, ratio, available
client.reset();
tableModel.addRow(new Object[] {
client.name, idx, sizeToString(client.totalLength), "" + client.downAmount * 100 / client.totalLength + "%",
client.status, client.seeders, client.getNumPeers(),
sizeToString(client.downSpeed), sizeToString(client.upSpeed), calcETA(client),
sizeToString(client.upAmount), "" + client.upAmount / client.downAmount,
"" + client.available
});
table.repaint();
}
private void updateRow(TorrentClient client, int row) {
//name, #, size, done, status, seeds, peers, downSpeed, upSpeed, ETA, uploaded, ratio, available
client.update();
table.setValueAt("" + client.downAmount * 100 / client.totalLength + "%", row, 3);
table.setValueAt(client.status, row, 4);
table.setValueAt("" + client.seeders, row, 5);
table.setValueAt(client.getNumPeers(), row, 6);
table.setValueAt(sizeToString(client.downSpeed), row, 7);
table.setValueAt(sizeToString(client.upSpeed), row, 8);
table.setValueAt(calcETA(client), row, 9);
table.setValueAt(sizeToString(client.upAmount), row, 10);
table.setValueAt("" + client.upAmount / client.downAmount, row, 11);
table.setValueAt("" + client.available, row, 12);
}
private void updateTable() {
tableModel.setRowCount(0);
int idx = list.getSelectedIndex();
if (idx == -1) return;
int size = clients.size();
for(int a=0;a<size;a++) {
TorrentClient client = clients.get(a);
switch (idx) {
case 0: addRow(client, a); break;
case 1: if (!client.done) addRow(client, a); break;
case 2: if (client.done) addRow(client, a); break;
}
}
}
private void addTorrent(String file, String dest) {
Torrent newTorrent = new Torrent();
newTorrent.file = file;
newTorrent.dest = dest;
newTorrent.active = true;
newTorrent.paused = false;
config.torrent = Arrays.copyOf(config.torrent, config.torrent.length + 1);
config.torrent[config.torrent.length-1] = newTorrent;
saveConfig();
}
private void removeTorrent(int idx) {
int len = config.torrent.length;
Torrent newList[] = new Torrent[len-1];
System.arraycopy(config.torrent, 0, newList, 0, idx);
System.arraycopy(config.torrent, idx+1, newList, idx, len - idx - 1);
config.torrent = newList;
saveConfig();
}
private void addFile() {
JFileChooser chooser = new JFileChooser();
chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
chooser.setMultiSelectionEnabled(false);
chooser.setCurrentDirectory(new File(JF.getUserPath() + "/Torrents"));
javax.swing.filechooser.FileFilter ffTorrent = new javax.swing.filechooser.FileFilter() {
public boolean accept(File file) {
if (file.isDirectory()) return true;
if (file.getName().endsWith(".torrent")) return true;
return false;
}
public String getDescription() {
return "Torrent (*.torrent)";
}
};
chooser.addChoosableFileFilter(ffTorrent);
chooser.setFileFilter(ffTorrent);
// chooser.setFileFilter(todo);
if (chooser.showOpenDialog(this) != JFileChooser.APPROVE_OPTION) return;
File torrent = chooser.getSelectedFile();
chooser = new JFileChooser();
chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
chooser.setMultiSelectionEnabled(false);
chooser.setCurrentDirectory(new File(JF.getUserPath() + "/Downloads"));
if (chooser.showSaveDialog(this) != JFileChooser.APPROVE_OPTION) return;
File dest = chooser.getSelectedFile();
if (!startTorrent(torrent.getAbsolutePath(), dest.getAbsolutePath(), true, false)) return;
addTorrent(torrent.getAbsolutePath(), dest.getAbsolutePath());
}
private String errmsg;
private File urltorrent;
private String getNameFromURL(String url) {
int idx1 = url.lastIndexOf('/');
int idx2 = url.lastIndexOf('.');
if (idx2 == -1) idx2 = url.length();
return url.substring(idx1+1, idx2);
}
private void addURL() {
String urlStr = JF.getString("Enter HTTP[S] URL:", "");
if (urlStr == null) return;
boolean http = false;
boolean https = false;
if (urlStr.startsWith("http://")) http = true;
if (urlStr.startsWith("https://")) https = true;
if (!http && !https) {
JF.showError("Error", "Unsupported URL");
return;
}
try {
JFTask task = new JFTask() {
public boolean work() {
try {
String urlString = (String)this.getProperty("url");
this.setLabel("Downloading : " + urlString);
this.setProgress(5);
// int idx = urlString.lastIndexOf(".");
// String ext = urlString.substring(idx).toLowerCase();
urltorrent = new File(JF.getUserPath() + "/Torrents/" + getNameFromURL(urlString) + ".torrent");
URL url = new URL(urlString);
HttpURLConnection uc = (HttpURLConnection)url.openConnection();
this.setProgress(25);
uc.connect();
InputStream fis = uc.getInputStream();
FileOutputStream fos = new FileOutputStream(urltorrent);
JFLog.log("size=" + fis.available());
if (uc.getResponseCode() != 200) throw new Exception("Error:" + uc.getResponseCode() + ":" + uc.getResponseMessage());
long length = uc.getContentLength();
if (length <= 0) throw new Exception("unknown length");
if (!JF.copyAll(fis, fos, length)) throw new Exception("download failed");
fis.close();
fos.close();
this.setProgress(50);
this.setLabel("Complete");
this.setProgress(100);
errmsg = null;
return true;
} catch (Exception e) {
errmsg = e.toString();
return false;
}
}
};
task.setProperty("url", urlStr);
ProgressDialog dialog = new ProgressDialog(null, true, task);
dialog.setVisible(true);
if (errmsg != null) {
JF.showError("Error", "Exception:" + errmsg);
}
} catch (Exception e) {
JF.showError("Error", "Exception:" + e);
}
JFileChooser chooser = new JFileChooser();
chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
chooser.setMultiSelectionEnabled(false);
chooser.setCurrentDirectory(new File(JF.getUserPath() + "/Downloads"));
if (chooser.showSaveDialog(this) != JFileChooser.APPROVE_OPTION) return;
File dest = chooser.getSelectedFile();
if (!startTorrent(urltorrent.getAbsolutePath(), dest.getAbsolutePath(), true, false)) return;
addTorrent(urltorrent.getAbsolutePath(), dest.getAbsolutePath());
}
/** This allows connections to untrusted hosts. */
private void initHttps() {
TrustManager[] trustAllCerts = new TrustManager[] {
new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType) {}
public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType) {}
}
};
// Let us create the factory where we can set some parameters for the connection
try {
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
SSLSocketFactory sslsocketfactory = (SSLSocketFactory) sc.getSocketFactory(); //this method will work with untrusted certs
} catch (Exception e) {
JFLog.log(e);
}
}
public void close() {
for(int a=0;a<clients.size();a++) {
clients.get(a).close();
}
}
private void updateGUI() {
int size = table.getRowCount();
for(int a=0;a<size;a++) {
int idx = (Integer)table.getValueAt(a, 1);
updateRow(clients.get(idx), a);
}
table.repaint();
}
public void setStatus(String txt) {
status.setText("Status : " + txt);
}
}