package thaw.plugins.queueWatcher; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.Collections; import java.util.Comparator; import java.util.Iterator; import java.util.Observable; import java.util.Observer; import java.util.Vector; import javax.swing.JTable; import javax.swing.event.TableModelEvent; import javax.swing.table.TableColumn; import javax.swing.table.TableColumnModel; import thaw.core.I18n; import thaw.core.Logger; import thaw.fcp.FCPQueueManager; import thaw.fcp.FCPTransferQuery; import thaw.fcp.FCPClientGet; import thaw.fcp.FCPClientPut; import thaw.gui.IconBox; import thaw.gui.GUIHelper; import thaw.core.PluginManager; import thaw.plugins.TrayIcon; public class QueueTableModel extends javax.swing.table.AbstractTableModel implements Observer { private static final long serialVersionUID = 20060709; private final static String totalTimeStr = I18n.getMessage("thaw.plugin.queueWatcher.totalTime"); private final static String downloadSuccessfulStr = I18n.getMessage("thaw.plugin.queueWatcher.downloadSuccessful"); private final static String downloadFailedStr = I18n.getMessage("thaw.plugin.queueWatcher.downloadFailed"); private final static String insertionSuccessfulStr = I18n.getMessage("thaw.plugin.queueWatcher.insertionSuccessful"); private final static String insertionFailedStr = I18n.getMessage("thaw.plugin.queueWatcher.insertionFailed"); private final static String unspecifiedStr = I18n.getMessage("thaw.common.unspecified"); private final Vector columnNames; private Vector queries = null; private boolean isForInsertions = false; private boolean isSortedAsc = false; private int sortedColumn = -1; private FCPQueueManager queueManager; private PluginManager pluginManager; public QueueTableModel(boolean isForInsertions, PluginManager pluginManager, final FCPQueueManager queueManager) { super(); this.pluginManager = pluginManager; this.queueManager = queueManager; this.isForInsertions = isForInsertions; columnNames = new Vector(); columnNames.add(" "); columnNames.add(I18n.getMessage("thaw.common.file")); columnNames.add(I18n.getMessage("thaw.common.size")); if(!isForInsertions) columnNames.add(I18n.getMessage("thaw.common.localPath")); columnNames.add(I18n.getMessage("thaw.common.status")); columnNames.add(I18n.getMessage("thaw.common.progress")); columnNames.add(I18n.getMessage("thaw.common.priority")); columnNames.add(I18n.getMessage("thaw.common.speed")); columnNames.add(I18n.getMessage("thaw.common.eta")); resetTable(); if(queueManager != null) { reloadQueue(); queueManager.addObserver(this); } else { Logger.warning(this, "Unable to connect to QueueManager. Is the connection established ?"); } } public int getRowCount() { if(queries != null) { return queries.size(); } else return 0; } public int getColumnCount() { return columnNames.size(); } public String getColumnName(final int col) { String result = (String)columnNames.get(col); if(col == sortedColumn) { if(isSortedAsc) result = result + " >>"; else result = result + " <<"; } return result; } public Object getValueAt(final int row, int column) { if(row >= queries.size()) return null; final FCPTransferQuery query = (FCPTransferQuery)queries.get(row); if (column == 0) { if(query == null) return null; if(!query.isRunning() && !query.isFinished()) return " "; if(query.isFinished() && query.isSuccessful() && ( (!(query instanceof FCPClientGet)) || ((FCPClientGet)query).isWritingSuccessful())) return IconBox.minGreen; if(query.isFinished() && (!query.isSuccessful() || ((query instanceof FCPClientGet) && !((FCPClientGet)query).isWritingSuccessful()) ) ) return IconBox.minRed; if(query.isRunning() && !query.isFinished()) return IconBox.minOrange; return " "; } else if(column == 1) { String filename = query.getFilename(); if (filename == null) return "(null)"; return filename; } else if(column == 2) { return thaw.gui.GUIHelper.getPrintableSize(query.getFileSize()); } else if(!isForInsertions && (column == 3)) { if(query.getPath() != null) return query.getPath(); else return unspecifiedStr; } else if( (isForInsertions && (column == 3)) || (!isForInsertions && (column == 4)) ) { return query.getStatus(); } else if( ((isForInsertions && (column == 4)) || (!isForInsertions && (column == 5)) ) ) { return query; } else if( ((isForInsertions && (column == 5)) || (!isForInsertions && (column == 6)) ) ) { return DetailPanel.prioritiesStr[query.getThawPriority()]; } else if( ((isForInsertions && (column == 6)) || (!isForInsertions && (column == 7)) ) ) { if (query.isFinished()) return ""; long averageSpeed = query.getAverageSpeed(); if (averageSpeed <= 0) return ""; return GUIHelper.getPrintableSize(averageSpeed) + "/s"; } else if( ((isForInsertions && (column == 7)) || (!isForInsertions && (column == 8)) ) ) { if (!query.isProgressionReliable()) return ""; long remaining = query.getETA(); if (remaining <= 0) return ""; if (!query.isFinished()) return GUIHelper.getPrintableTime(remaining); else return totalTimeStr + " "+GUIHelper.getPrintableTime(remaining); } return null; } public boolean isCellEditable(final int row, final int column) { return false; } /** * Don't call notifyObservers ! */ public void resetTable() { if(queries != null) { synchronized(queries) { for(final Iterator it = queries.iterator(); it.hasNext();) { final Observable query = (Observable)it.next(); query.deleteObserver(this); } } } queries = new Vector(); } public void reloadQueue() { resetTable(); addQueries(queueManager.getRunningQueue()); final Vector[] pendings = queueManager.getPendingQueues(); for(int i = 0;i < pendings.length ; i++) addQueries(pendings[i]); } public void addQueries(final Vector queries) { synchronized(queries) { for(final Iterator it = queries.iterator(); it.hasNext();) { final FCPTransferQuery query = (FCPTransferQuery)it.next(); if((query.getQueryType() == 1) && !isForInsertions) addQuery(query); if((query.getQueryType() == 2) && isForInsertions) addQuery(query); } } } public void addQuery(final FCPTransferQuery query) { if (!query.isPersistent()) return; if(queries.contains(query)) { Logger.debug(this, "addQuery() : Already known"); return; } ((Observable)query).addObserver(this); synchronized(queries) { queries.add(query); } sortTable(); final int changedRow = queries.indexOf(query); this.notifyObservers(new TableModelEvent(this, changedRow, changedRow, TableModelEvent.ALL_COLUMNS, TableModelEvent.INSERT)); } public void removeQuery(final FCPTransferQuery query) { ((Observable)query).deleteObserver(this); sortTable(); final int changedRow = queries.indexOf(query); synchronized(queries) { queries.remove(query); } if(changedRow >= 0) { this.notifyObservers(new TableModelEvent(this, changedRow, changedRow, TableModelEvent.ALL_COLUMNS, TableModelEvent.DELETE)); }else this.notifyObservers(); } public FCPTransferQuery getQuery(final int row) { try { return (FCPTransferQuery)queries.get(row); } catch(final java.lang.ArrayIndexOutOfBoundsException e) { Logger.notice(this, "Query not found, row: "+row); return null; } } /** * returns a *copy* */ public Vector getQueries() { final Vector newVect = new Vector(); synchronized(queries) { for(final Iterator queryIt = queries.iterator() ; queryIt.hasNext();) { newVect.add(queryIt.next()); } } return newVect; } public void notifyObservers() { final TableModelEvent event = new TableModelEvent(this); this.notifyObservers(event); } public void notifyObservers(final int changedRow) { final TableModelEvent event = new TableModelEvent(this, changedRow); this.notifyObservers(event); } public void notifyObservers(final TableModelEvent event) { fireTableChanged(event); /* TableModelListener[] listeners = getTableModelListeners(); for(int i = 0 ; i < listeners.length ; i++) { listeners[i].tableChanged(event); } */ } public void update(final Observable o, final Object arg) { if (o == queueManager && arg == null) { /* unclear change */ reloadQueue(); return; } if (o == queueManager) { final FCPTransferQuery query = (FCPTransferQuery)arg; /* we only display persistent queries */ if (!query.isPersistent()) return; if((query.getQueryType() == 1) && isForInsertions) return; if((query.getQueryType() == 2) && !isForInsertions) return; if(queueManager.isInTheQueues(query)) { // then it's an adding addQuery(query); return; } if(queries.contains(query)) { // then it's a removing removeQuery(query); return; } /* else we don't know */ reloadQueue(); return; } else if (o instanceof FCPTransferQuery && queries.indexOf(o) >= 0 && ((FCPTransferQuery)o).isFinished() && (arg == null || !(arg instanceof Long /* update of the total time/ETA */)) ) { String str = null; boolean success = ((FCPTransferQuery)o).isSuccessful(); if (o instanceof FCPClientGet) { str = (success ? downloadSuccessfulStr : downloadFailedStr); } else if (o instanceof FCPClientPut) { str = (success ? insertionSuccessfulStr : insertionFailedStr); } if (str != null) { str = str.replaceAll("X", ((FCPTransferQuery)o).getFilename()); TrayIcon.popMessage(pluginManager, "Thaw", str, thaw.gui.SysTrayIcon.MSG_INFO); } } if (o instanceof FCPTransferQuery) { int oldPos = -1; int i = 0; if (queries != null) { oldPos = queries.indexOf(o); } sortTable(); if (queries != null && (i = queries.indexOf(o)) >= 0) { if (oldPos != i && oldPos >= 0) this.notifyObservers(oldPos); this.notifyObservers(i); return; } Logger.warning(this, "update(): unknow change"); try { throw new Exception("meh"); } catch(Exception e) { e.printStackTrace(); } reloadQueue(); } } /** * @return false if nothing sorted */ public boolean sortTable() { if((sortedColumn < 0) || (queries.size() <= 0)) return false; synchronized(queries) { Collections.sort(queries, new QueryComparator(isSortedAsc, sortedColumn, isForInsertions)); } return true; } public class ColumnListener extends MouseAdapter { private JTable table; public ColumnListener(final JTable t) { table = t; } public void mouseClicked(final MouseEvent e) { final TableColumnModel colModel = table.getColumnModel(); final int columnModelIndex = colModel.getColumnIndexAtX(e.getX()); final int modelIndex = colModel.getColumn(columnModelIndex).getModelIndex(); final int columnsCount = table.getColumnCount(); if (modelIndex < 0 || columnModelIndex < 1) return; if (sortedColumn == modelIndex) isSortedAsc = !isSortedAsc; else sortedColumn = modelIndex; for (int i = 0; i < columnsCount; i++) { final TableColumn column = colModel.getColumn(i); column.setHeaderValue(getColumnName(column.getModelIndex())); } table.getTableHeader().repaint(); sortTable(); } } public class QueryComparator implements Comparator { private boolean isSortedAsc; private int column; private boolean isForInsertionTable; public QueryComparator(final boolean sortedAsc, final int column, final boolean isForInsertionTable) { isSortedAsc = sortedAsc; this.column = column - 1; /* can't sort on the first column */ this.isForInsertionTable = isForInsertionTable; } public int compare(final Object o1, final Object o2) { int result = 0; if(!(o1 instanceof FCPTransferQuery) || !(o2 instanceof FCPTransferQuery)) return 0; final FCPTransferQuery q1 = (FCPTransferQuery)o1; final FCPTransferQuery q2 = (FCPTransferQuery)o2; if(column == 0) { /* File name */ if(q1.getFilename() == null) result = -1; else if(q2.getFilename() == null) result = 1; else result = q1.getFilename().compareTo(q2.getFilename()); } else if(column == 1) { /* Size */ result = (new Long(q1.getFileSize())).compareTo(new Long(q2.getFileSize())); } else if( ((column == 2) && !isForInsertionTable) ) { /* localPath */ if(q1.getPath() == null) result = -1; else if(q2.getPath() == null) result = 1; else result = q1.getPath().compareTo(q2.getPath()); } else if( ((column == 2) && isForInsertionTable) || ((column == 3) && !isForInsertionTable) ) { /* status */ if(q1.getStatus() == null) result = -1; else if(q2.getStatus() == null) result = 1; else result = q1.getStatus().compareTo(q2.getStatus()); } else if( ((column == 3) && isForInsertionTable) || ((column == 4) && !isForInsertionTable) ) { /* progress */ boolean b = false; if((q1.getProgression() <= 0) && (q2.getProgression() <= 0)) { if(q1.isRunning() && !q2.isRunning()) { result = 1; b = true; } else if(q2.isRunning() && !q1.isRunning()) { result = -1; b = true; } } if (!b) result = (new Integer(q1.getProgression())).compareTo(new Integer(q2.getProgression())); } else if( ((column == 4) && isForInsertionTable) || ((column == 5) && !isForInsertionTable) ) { /* priority */ result = -(new Integer(q1.getFCPPriority())).compareTo(new Integer(q2.getFCPPriority())); /* negative result because lower priority value is higher priority */ } else if( ((column == 5) && isForInsertionTable) || ((column == 6) && !isForInsertionTable) ) { /* progress */ result = (new Long(q1.getAverageSpeed())).compareTo(new Long(q2.getAverageSpeed())); } else if( ((column == 6) && isForInsertionTable) || ((column == 7) && !isForInsertionTable) ) { /* progress */ if (q1.isFinished() && !q2.isFinished()) result = 1; else if (!q1.isFinished() && q2.isFinished()) result = -1; else if (q1.getETA() > 0 && q2.getETA() <= 0) result = 1; else if (q1.getETA() <= 0 && q2.getETA() > 0) result = -1; else { result = (new Long(q1.getETA())).compareTo(new Long(q2.getETA())); result = -result; } } if (!isSortedAsc) result = -result; return result; } public boolean isSortedAsc() { return isSortedAsc; } public boolean equals(final Object obj) { if (obj instanceof QueryComparator) { final QueryComparator compObj = (QueryComparator) obj; return compObj.isSortedAsc() == isSortedAsc(); } return false; } public int hashCode(){ return super.hashCode(); } } }