1 /* 2 Script: deluge-torrents.js 3 Contains all objects and functions related to the torrent grid. 4 5 Copyright: 6 (C) Damien Churchill 2009 <damoxc@gmail.com> 7 This program is free software; you can redistribute it and/or modify 8 it under the terms of the GNU General Public License as published by 9 the Free Software Foundation; either version 3, or (at your option) 10 any later version. 11 12 This program is distributed in the hope that it will be useful, 13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with this program. If not, write to: 19 The Free Software Foundation, Inc., 20 51 Franklin Street, Fifth Floor 21 Boston, MA 02110-1301, USA. 22 23 In addition, as a special exception, the copyright holders give 24 permission to link the code of portions of this program with the OpenSSL 25 library. 26 You must obey the GNU General Public License in all respects for all of 27 the code used other than OpenSSL. If you modify file(s) with this 28 exception, you may extend this exception to your version of the file(s), 29 but you are not obligated to do so. If you do not wish to do so, delete 30 this exception statement from your version. If you delete this exception 31 statement from all source files in the program, then also delete it here. 32 33 */ 34 35 (function() { 36 /* Renderers for the Torrent Grid */ 37 function queueRenderer(value) { 38 return (value == -1) ? '' : value + 1; 39 } 40 function torrentNameRenderer(value, p, r) { 41 return String.format('<div class="torrent-name x-deluge-{0}">{1}</div>', r.data['state'].toLowerCase(), value); 42 } 43 function torrentSpeedRenderer(value) { 44 if (!value) return; 45 return fspeed(value); 46 } 47 function torrentProgressRenderer(value, p, r) { 48 value = new Number(value); 49 var progress = value; 50 var text = r.data['state'] + ' ' + value.toFixed(2) + '%' 51 var width = new Number(this.style.match(/\w+:\s*(\d+)\w+/)[1]) - 8; 52 return Deluge.progressBar(value, width, text); 53 } 54 function seedsRenderer(value, p, r) { 55 if (r.data['total_seeds'] > -1) { 56 return String.format('{0} ({1})', value, r.data['total_seeds']); 57 } else { 58 return value; 59 } 60 } 61 function peersRenderer(value, p, r) { 62 if (r.data['total_peers'] > -1) { 63 return String.format('{0} ({1})', value, r.data['total_peers']); 64 } else { 65 return value; 66 } 67 } 68 function availRenderer(value, p, r) { 69 return new Number(value).toFixed(3); 70 } 71 function trackerRenderer(value, p, r) { 72 return String.format('<div style="background: url(/tracker/{0}) no-repeat; padding-left: 20px;">{0}</div>', value); 73 } 74 75 /** 76 * Ext.deluge.TorrentGrid Class 77 * 78 * @author Damien Churchill <damoxc@gmail.com> 79 * @version 1.2 80 * 81 * @class Ext.deluge.TorrentGrid 82 * @extends Ext.grid.GridPanel 83 * @constructor 84 * @param {Object} config Configuration options 85 */ 86 Ext.deluge.TorrentGrid = Ext.extend(Ext.grid.GridPanel, { 87 constructor: function(config) { 88 config = Ext.apply({ 89 id: 'torrentGrid', 90 store: new Ext.data.SimpleStore({ 91 fields: [ 92 {name: 'queue'}, 93 {name: 'name'}, 94 {name: 'size', type: 'int'}, 95 {name: 'state'}, 96 {name: 'progress', type: 'float'}, 97 {name: 'seeds', type: 'int'}, 98 {name: 'total_seeds', type: 'int'}, 99 {name: 'peers', type: 'int'}, 100 {name: 'total_peers', type: 'int'}, 101 {name: 'downspeed', type: 'int'}, 102 {name: 'upspeed', type: 'int'}, 103 {name: 'eta', type: 'int'}, 104 {name: 'ratio', type: 'float'}, 105 {name: 'avail', type: 'float'}, 106 {name: 'added', type: 'int'}, 107 {name: 'tracker'} 108 ], 109 id: 16 110 }), 111 columns: [{ 112 id:'queue', 113 header: _('#'), 114 width: 30, 115 sortable: true, 116 renderer: queueRenderer, 117 dataIndex: 'queue' 118 }, { 119 id:'name', 120 header: _('Name'), 121 width: 150, 122 sortable: true, 123 renderer: torrentNameRenderer, 124 dataIndex: 'name' 125 }, { 126 header: _('Size'), 127 width: 75, 128 sortable: true, 129 renderer: fsize, 130 dataIndex: 'size' 131 }, { 132 header: _('Progress'), 133 width: 150, 134 sortable: true, 135 renderer: torrentProgressRenderer, 136 dataIndex: 'progress' 137 }, { 138 header: _('Seeders'), 139 width: 60, 140 sortable: true, 141 renderer: seedsRenderer, 142 dataIndex: 'seeds' 143 }, { 144 header: _('Peers'), 145 width: 60, 146 sortable: true, 147 renderer: peersRenderer, 148 dataIndex: 'peers' 149 }, { 150 header: _('Down Speed'), 151 width: 80, 152 sortable: true, 153 renderer: torrentSpeedRenderer, 154 dataIndex: 'downspeed' 155 }, { 156 header: _('Up Speed'), 157 width: 80, 158 sortable: true, 159 renderer: torrentSpeedRenderer, 160 dataIndex: 'upspeed' 161 }, { 162 header: _('ETA'), 163 width: 60, 164 sortable: true, 165 renderer: ftime, 166 dataIndex: 'eta' 167 }, { 168 header: _('Ratio'), 169 width: 60, 170 sortable: true, 171 renderer: availRenderer, 172 dataIndex: 'ratio' 173 }, { 174 header: _('Avail'), 175 width: 60, 176 sortable: true, 177 renderer: availRenderer, 178 dataIndex: 'avail' 179 }, { 180 header: _('Added'), 181 width: 80, 182 sortable: true, 183 renderer: fdate, 184 dataIndex: 'added' 185 }, { 186 header: _('Tracker'), 187 width: 120, 188 sortable: true, 189 renderer: trackerRenderer, 190 dataIndex: 'tracker' 191 }], 192 region: 'center', 193 cls: 'deluge-torrents', 194 stripeRows: true, 195 autoExpandColumn: 'name', 196 deferredRender:false, 197 autoScroll:true, 198 margins: '5 5 0 0' 199 }, config); 200 Ext.deluge.TorrentGrid.superclass.constructor.call(this, config); 201 }, 202 203 initComponent: function() { 204 Ext.deluge.TorrentGrid.superclass.initComponent.call(this); 205 Deluge.Events.on('torrentRemoved', this.onTorrentRemoved, this); 206 this.on('rowcontextmenu', function(grid, rowIndex, e) { 207 e.stopEvent(); 208 var selection = grid.getSelectionModel(); 209 if (!selection.hasSelection()) { 210 selection.selectRow(rowIndex); 211 } 212 Deluge.Menus.Torrent.showAt(e.getPoint()); 213 }); 214 }, 215 216 /** 217 * Returns the record representing the torrent at the specified index. 218 * 219 * @param {int} The row index of the torrent you wish to retrieve. 220 * @return {Ext.data.Record} The record representing the torrent. 221 */ 222 getTorrent: function(rowIndex) { 223 return this.getStore().getAt(rowIndex); 224 }, 225 226 getSelected: function() { 227 return this.getSelectionModel().getSelected(); 228 }, 229 230 getSelections: function() { 231 return this.getSelectionModel().getSelections(); 232 }, 233 234 update: function(torrents) { 235 //var torrents = []; 236 var store = this.getStore(); 237 for (var torrentId in torrents) { 238 var record = store.getById(torrentId); 239 var torrent = torrents[torrentId]; 240 if (!record) { 241 // We need to create a new record 242 var data = [ 243 torrent.queue, 244 torrent.name, 245 torrent.total_size, 246 torrent.state, 247 torrent.progress, 248 torrent.num_seeds, 249 torrent.total_seeds, 250 torrent.num_peers, 251 torrent.total_peers, 252 torrent.download_payload_rate, 253 torrent.upload_payload_rate, 254 torrent.eta, 255 torrent.ratio, 256 torrent.distributed_copies, 257 torrent.time_added, 258 torrent.tracker_host, 259 torrentId 260 ]; 261 store.loadData([data], true); 262 } else { 263 // We just need to do an update 264 record.set('queue', torrent.queue); 265 record.set('name', torrent.name); 266 record.set('size', torrent.total_size); 267 record.set('state', torrent.state); 268 record.set('progress', torrent.progress); 269 record.set('seeds', torrent.num_seeds); 270 record.set('total_seeds', torrent.total_seeds); 271 record.set('peers', torrent.num_peers); 272 record.set('total_peers', torrent.total_peers); 273 record.set('downspeed', torrent.download_payload_rate); 274 record.set('upspeed', torrent.upload_payload_rate); 275 record.set('eta', torrent.eta); 276 record.set('ratio', torrent.ratio); 277 record.set('avail', torrent.distributed_copies); 278 record.set('added', torrent.time_added); 279 record.set('tracker', torrent.tracker_host); 280 record.commit(); 281 } 282 } 283 284 var torrentIds = Ext.keys(torrents); 285 store.each(function(record) { 286 if (torrentIds.indexOf(record.id) == -1) { 287 // Torrent is no longer in the grid so we must remove it. 288 store.remove(record); 289 } 290 }, this); 291 }, 292 293 // private 294 onTorrentRemoved: function(torrentIds) { 295 var selModel = this.getSelectionModel(); 296 Ext.each(torrentIds, function(torrentId) { 297 var record = this.getStore().getById(torrentId); 298 if (selModel.isSelected(record)) { 299 selModel.deselectRow(this.getStore().indexOf(record)); 300 } 301 this.getStore().remove(record); 302 }, this); 303 } 304 }); 305 Deluge.Torrents = new Ext.deluge.TorrentGrid(); 306 })();