1 /*
  2 Script: Deluge.Details.Files.js
  3     The files tab displayed in the details panel.
  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 (function() {
 34 	/* Renderers for the column tree */
 35 	function fileProgressRenderer(value) {
 36 		var progress = value * 100;
 37 		return Deluge.progressBar(progress, this.width - 50, progress.toFixed(2) + '%', 0);
 38 	}
 39 	function priorityRenderer(value) {
 40 		return String.format('<div class="{0}">{1}</div>', FILE_PRIORITY_CSS[value], _(FILE_PRIORITY[value]));
 41 	}
 42 	
 43 	Ext.deluge.details.FilesTab = Ext.extend(Ext.tree.ColumnTree, {
 44 		
 45 		constructor: function(config) {
 46 			config = Ext.apply({
 47 				title: _('Files'),
 48 				rootVisible: false,
 49 				autoScroll: true,
 50 				selModel: new Ext.tree.MultiSelectionModel(),
 51 				
 52 				columns: [{
 53 					header: _('Filename'),
 54 					width: 330,
 55 					dataIndex: 'filename'
 56 				}, {
 57 					header: _('Size'),
 58 					width: 150,
 59 					dataIndex: 'size',
 60 					renderer: fsize
 61 				}, {
 62 					header: _('Progress'),
 63 					width: 150,
 64 					dataIndex: 'progress',
 65 					renderer: fileProgressRenderer
 66 				}, {
 67 					header: _('Priority'),
 68 					width: 150,
 69 					dataIndex: 'priority',
 70 					renderer: priorityRenderer
 71 				}],
 72 				
 73 				root: new Ext.tree.TreeNode({
 74 					text: 'Files'
 75 				})
 76 			}, config);
 77 			Ext.deluge.details.FilesTab.superclass.constructor.call(this, config);
 78 		},
 79 		
 80 		onRender: function(ct, position) {
 81 			Ext.deluge.details.FilesTab.superclass.onRender.call(this, ct, position);
 82 			Deluge.Menus.FilePriorities.on('itemclick', this.onItemClick, this);
 83 			this.on('contextmenu', this.onContextMenu, this);
 84 			this.sorter = new Ext.tree.TreeSorter(this, {
 85 				folderSort: true
 86 			});
 87 		},
 88 		
 89 		clear: function() {
 90 			var root = this.getRootNode();
 91 			if (!root.hasChildNodes()) return;
 92 			root.cascade(function(node) {
 93 				var parent = node.parentNode;
 94 				if (!parent) return;
 95 				if (!parent.ownerTree) return;
 96 				parent.removeChild(node);
 97 			});
 98 		},
 99 		
100 		update: function(torrentId) {
101 			if (this.torrentId != torrentId) {
102 				this.clear();
103 				this.torrentId = torrentId;
104 			}
105 			
106 			Deluge.Client.web.get_torrent_files(torrentId, {
107 				success: this.onRequestComplete,
108 				scope: this,
109 				torrentId: torrentId
110 			});
111 		},
112 		
113 		onContextMenu: function(node, e) {
114 			e.stopEvent();
115 			var selModel = this.getSelectionModel();
116 			if (selModel.getSelectedNodes().length < 2) {
117 				selModel.clearSelections();
118 				node.select();
119 			}
120 			Deluge.Menus.FilePriorities.showAt(e.getPoint());
121 		},
122 		
123 		onItemClick: function(baseItem, e) {
124 			switch (baseItem.id) {
125 				case 'expandAll':
126 					this.expandAll();
127 					break;
128 				default:
129 					var indexes = {};
130 					function walk(node) {
131 						if (Ext.isEmpty(node.attributes.fileIndex)) return;
132 						indexes[node.attributes.fileIndex] = node.attributes.priority;
133 					}
134 					this.getRootNode().cascade(walk);
135 					
136 					var nodes = this.getSelectionModel().getSelectedNodes();
137 					Ext.each(nodes, function(node) {
138 						if (Ext.isEmpty(node.attributes.fileIndex)) return;
139 						indexes[node.attributes.fileIndex] = baseItem.filePriority;
140 					});
141 					
142 					var priorities = new Array(Ext.keys(indexes).length);
143 					for (var index in indexes) {
144 						priorities[index] = indexes[index];
145 					}
146 
147 					Deluge.Client.core.set_torrent_file_priorities(this.torrentId, priorities, {
148 						success: function() {
149 							Ext.each(nodes, function(node) {
150 								node.setColumnValue(3, baseItem.filePriority);
151 							});
152 						},
153 						scope: this
154 					});
155 					break;
156 			}
157 		},
158 		
159 		onRequestComplete: function(files, options) {
160 			function walk(files, parent) {
161 				for (var file in files) {
162 					var item = files[file];
163 					var child = parent.findChild('id', file);
164 					if (Ext.type(item) == 'object') {
165 						if (!child) {
166 							child = new Ext.tree.TreeNode({
167 								id: file,
168 								text: file
169 							});
170 							parent.appendChild(child);
171 						}
172 						walk(item, child);
173 					} else {
174 						if (!child) {
175 							child = new Ext.tree.ColumnTreeNode({
176 								id: file,
177 								filename: file,
178 								text: file, // this needs to be here for sorting
179 								fileIndex: item[0],
180 								size: item[1],
181 								progress: item[2],
182 								priority: item[3],
183 								leaf: true,
184 								iconCls: 'x-deluge-file',
185 								uiProvider: Ext.tree.ColumnNodeUI
186 							});
187 							parent.appendChild(child);
188 						}
189 						child.setColumnValue(1, item[1]);
190 						child.setColumnValue(2, item[2]);
191 						child.setColumnValue(3, item[3]);
192 					}
193 				}
194 			}
195 			var root = this.getRootNode();
196 			walk(files, root);
197 			root.firstChild.expand();
198 		}
199 	});
200 	Deluge.Details.add(new Ext.deluge.details.FilesTab());
201 })();
202