/*
* XNap
*
* A pure java file sharing client.
*
* See AUTHORS for copyright information.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package xnap.gui.table;
import xnap.*;
import xnap.gui.util.SwingSynchronizedCache;
import xnap.net.*;
import xnap.net.event.*;
import xnap.util.*;
import xnap.util.event.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;
import java.util.*;
import javax.swing.SwingUtilities;
// don't change the next line
import javax.swing.Timer;
import javax.swing.event.*;
import javax.swing.table.*;
public class TransferTableModel extends AbstractDynamicTableModel
implements ListListener, StatusChangeListener {
//--- Constant(s) ---
public static final int UPDATE_INTERVAL = 1000;
public static final int FILENAME = 0;
public static final int FILESIZE = 1;
public static final int USER = 2;
public static final int CLIENT_INFO = 3;
public static final int STATUS = 4;
public static final int PROGRESS = 5;
public static final int TIMELEFT = 6;
public static final int PARTIAL_FILESIZE = 7;
public static final int QUEUEPOS = 8;
protected Column columns[] = new Column[] {
new Column(XNap.tr("Filename"), String.class,
new StringCellRenderer()),
new Column(XNap.tr("Size"), Long.class,
new FilesizeCellRenderer()),
new Column(XNap.tr("User"), String.class),
new Column(XNap.tr("Client"), String.class),
new Column(XNap.tr("Status"), String.class,
new StringCellRenderer()),
new Column(XNap.tr("Progress"), Progress.class,
new ProgressCellRenderer()),
new Column(XNap.tr("Time Left"), Integer.class,
new TimeCellRenderer()),
new Column(XNap.tr("Transfered"), Long.class,
new FilesizeCellRenderer()),
new Column(XNap.tr("Position in Queue"), Integer.class)
};
//--- Data field(s) ---
private static Timer updateTimer = null;
/**
* Stores the data.
*/
protected ArrayList rows = new ArrayList();
private TransferQueue queue;
private boolean updateQueue = false;
private String tableName;
//--- Constructor(s) ---
public TransferTableModel(TransferQueue queue, String table, String tableName,
EventVector data)
{
super(table, Preferences.getInstance());
this.queue = queue;
this.tableName = tableName;
SwingSynchronizedCache cache = new SwingSynchronizedCache(this);
data.addListListener(cache);
setColumns(columns);
if (updateTimer == null) {
updateTimer = new Timer(UPDATE_INTERVAL, new Updater());
updateTimer.start();
}
else {
updateTimer.addActionListener(new Updater());
}
}
public TransferTableModel(TransferQueue queue, String table, String tableName)
{
this(queue, table, tableName, queue);
setUpdateQueue(true);
}
//--- Method(s) ---
public void elementAdded(ListEvent e)
{
ITransferContainer t = (ITransferContainer)e.getElement();
t.addStatusChangeListener(this);
rows.add(t);
fireTableRowsInserted(rows.size() - 1, rows.size() - 1);
}
public void elementRemoved(ListEvent e)
{
ITransferContainer t = (ITransferContainer)e.getElement();
t.removeStatusChangeListener(this);
int i = rows.indexOf(t);
if (i != -1) {
rows.remove(i);
fireTableRowsDeleted(i, i);
}
}
public TransferQueue getQueue()
{
return queue;
}
public int getRowCount()
{
return rows.size();
}
public ITransferContainer get(int i)
{
return (ITransferContainer)rows.get(mapToIndex(i));
}
public Object get(int i, int j)
{
if (rows.get(i) instanceof ITransferContainer) {
ITransferContainer t = (ITransferContainer)rows.get(i);
if (t == null)
return null;
IUser u = t.getUser();
switch (j) {
case FILENAME:
return t.getFilename();
case FILESIZE:
return new Long(t.getFilesize());
case USER:
return (u != null) ? u.getName() : "";
case CLIENT_INFO:
return (u != null) ? u.getClientInfo() : "";
case STATUS:
return t.getStatusText();
case PROGRESS:
return new Progress(t.getTotalBytesTransferred(),
t.getFilesize(),
t.getCurrentRate());
case TIMELEFT:
long rate = t.getAverageRate();
if (rate <= 0)
return new Integer(-1);
else
return new Integer((int)((t.getFilesize()
- t.getTotalBytesTransferred())
/ rate));
case PARTIAL_FILESIZE:
return new Long(t.getTotalBytesTransferred());
case QUEUEPOS:
int pos = this.getQueue().getLocalQueuePos(t);
return (pos >= 0) ? new Integer(pos + 1) : null;
}
}
return null;
}
public String getTableName()
{
return tableName;
}
public boolean isCellEditable(int i, int j)
{
return false;
}
/**
* If set to true, the transfer rate of the queue will be set every
* time the update thread runs.
*/
public void setUpdateQueue(boolean newValue)
{
updateQueue = newValue;
}
/**
* Observes the transfer threads.
*/
public void statusChange(StatusChangeEvent e)
{
ITransferContainer t = (ITransferContainer)e.getSource();
if (e.getNewStatus() != ITransferContainer.STATUS_DOWNLOADING
&& e.getNewStatus() != ITransferContainer.STATUS_UPLOADING) {
// once a transfer is not active anymore it is not updated
// by the updater thread, so we need to do it manually
SwingUtilities.invokeLater(new StatusChangeEventHandler(t));
}
}
public void updateTable()
{
long rate = 0;
for (int i = 0; i < rows.size(); i++) {
ITransferContainer t = (ITransferContainer)rows.get(i);
if (t.getStatus() == ITransferContainer.STATUS_DOWNLOADING
|| t.getStatus() == ITransferContainer.STATUS_UPLOADING
|| t.getStatus() == ITransferContainer.STATUS_WAITING) {
fireTableRowsUpdated(i, i);
if (t.getStatus() != ITransferContainer.STATUS_WAITING) {
rate += t.getCurrentRate();
}
}
}
if (updateQueue) {
getQueue().setCurrentRate(rate);
}
}
private class Updater implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
updateTable();
}
}
private class StatusChangeEventHandler implements Runnable
{
ITransferContainer item;
public StatusChangeEventHandler(ITransferContainer item)
{
this.item = item;
}
public void run()
{
for (int i = 0; i < rows.size(); i++) {
if (rows.get(i).equals(item)) {
fireTableRowsUpdated(i, i);
}
}
}
}
}