1 /*
  2 Script: Deluge.Details.Options.js
  3     The options 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 
 34 
 35 Ext.deluge.details.OptionsTab = Ext.extend(Ext.form.FormPanel, {
 36 
 37 	constructor: function(config) {
 38 		config = Ext.apply({
 39 			autoScroll: true,
 40 			bodyStyle: 'padding: 5px;',
 41 			border: false,
 42 			cls: 'x-deluge-options',
 43 			defaults: {
 44 				autoHeight: true,
 45 				labelWidth: 1,
 46 				defaultType: 'checkbox'
 47 			},
 48 			deferredRender: false,
 49 			layout: 'column',
 50 			title: _('Options')
 51 		}, config);
 52 		Ext.deluge.details.OptionsTab.superclass.constructor.call(this, config);
 53 	},
 54 	
 55 	initComponent: function() {
 56 		Ext.deluge.details.OptionsTab.superclass.initComponent.call(this);
 57 		
 58 		this.fieldsets = {}, this.fields = {};
 59 		this.optionsManager = new Deluge.OptionsManager({
 60 			defaults: {
 61 				'max_download_speed': -1,
 62 				'max_upload_speed': -1,
 63 				'max_connections': -1,
 64 				'max_upload_slots': -1,
 65 				'is_auto_managed': false,
 66 				'stop_at_ratio': false,
 67 				'stop_ratio': 2.0,
 68 				'remove_at_ratio': false,
 69 				'move_completed': null,
 70 				'private': false,
 71 				'prioritize_first_last': false
 72 			}
 73 		});
 74 		this.optionsManager.on('changed', this.onOptionChanged, this);
 75 		
 76 		/*
 77 		 * Bandwidth Options
 78 		 */
 79 		this.fieldsets.bandwidth = this.add({
 80 			xtype: 'fieldset',
 81 			defaultType: 'uxspinner',
 82 			bodyStyle: 'padding: 5px',
 83 			
 84 			layout: 'table',
 85 			layoutConfig: {columns: 3},
 86 			labelWidth: 150,
 87 			
 88 			style: 'margin-left: 10px; margin-right: 5px; padding: 5px',
 89 			title: _('Bandwidth'),
 90 			width: 250
 91 		});
 92 		
 93 		/*
 94 		 * Max Download Speed
 95 		 */
 96 		this.fieldsets.bandwidth.add({
 97 			xtype: 'label',
 98 			text: _('Max Download Speed'),
 99 			forId: 'max_download_speed',
100 			cls: 'x-deluge-options-label'
101 		});
102 		this.fields.max_download_speed = this.fieldsets.bandwidth.add({
103 			id: 'max_download_speed',
104 			name: 'max_download_speed',
105 			width: 70,
106 			strategy: {
107 				xtype: 'number',
108 				decimalPrecision: 1,
109 				minValue: -1,
110 				maxValue: 99999
111 			}
112 		});
113 		this.fieldsets.bandwidth.add({
114 			xtype: 'label',
115 			text: _('KiB/s'),
116 			style: 'margin-left: 10px'
117 		});
118 		
119 		/*
120 		 * Max Upload Speed
121 		 */
122 		this.fieldsets.bandwidth.add({
123 			xtype: 'label',
124 			text: _('Max Upload Speed'),
125 			forId: 'max_upload_speed',
126 			cls: 'x-deluge-options-label'
127 		});
128 		this.fields.max_upload_speed = this.fieldsets.bandwidth.add({
129 			id: 'max_upload_speed',
130 			name: 'max_upload_speed',
131 			width: 70,
132 			value: -1,
133 			strategy: {
134 				xtype: 'number',
135 				decimalPrecision: 1,
136 				minValue: -1,
137 				maxValue: 99999
138 			}
139 		});
140 		this.fieldsets.bandwidth.add({
141 			xtype: 'label',
142 			text: _('KiB/s'),
143 			style: 'margin-left: 10px'
144 		});
145 		
146 		/*
147 		 * Max Connections
148 		 */
149 		this.fieldsets.bandwidth.add({
150 			xtype: 'label',
151 			text: _('Max Connections'),
152 			forId: 'max_connections',
153 			cls: 'x-deluge-options-label'
154 		});
155 		this.fields.max_connections = this.fieldsets.bandwidth.add({
156 			id: 'max_connections',
157 			name: 'max_connections',
158 			width: 70,
159 			value: -1,
160 			strategy: {
161 				xtype: 'number',
162 				decimalPrecision: 0,
163 				minValue: -1,
164 				maxValue: 99999
165 			},
166 			colspan: 2
167 		});
168 		
169 		/*
170 		 * Max Upload Slots
171 		 */
172 		this.fieldsets.bandwidth.add({
173 			xtype: 'label',
174 			text: _('Max Upload Slots'),
175 			forId: 'max_upload_slots',
176 			cls: 'x-deluge-options-label'
177 		});
178 		this.fields.max_upload_slots = this.fieldsets.bandwidth.add({
179 			id: 'max_upload_slots',
180 			name: 'max_upload_slots',
181 			width: 70,
182 			value: -1,
183 			strategy: {
184 				xtype: 'number',
185 				decimalPrecision: 0,
186 				minValue: -1,
187 				maxValue: 99999
188 			},
189 			colspan: 2
190 		});
191 
192 		/*
193 		 * Queue Options
194 		 */
195 		this.fieldsets.queue = this.add({
196 			xtype: 'fieldset',
197 			title: _('Queue'),
198 			style: 'margin-left: 5px; margin-right: 5px; padding: 5px',
199 			width: 210,
200 			
201 			layout: 'table',
202 			layoutConfig: {columns: 2},
203 			labelWidth: 0,
204 			
205 			defaults: {
206 				fieldLabel: '',
207 				labelSeparator: ''
208 			}
209 		});
210 		
211 		this.fields.is_auto_managed = this.fieldsets.queue.add({
212 			fieldLabel: '',
213 			labelSeparator: '',
214 			id: 'is_auto_managed',
215 			boxLabel: _('Auto Managed'),
216 			width: 200,
217 			colspan: 2
218 		});
219 		
220 		this.fields.stop_at_ratio = this.fieldsets.queue.add({
221 			fieldLabel: '',
222 			labelSeparator: '',
223 			id: 'stop_at_ratio',
224 			width: 120,
225 			boxLabel: _('Stop seed at ratio')
226 		});
227 		
228 		this.fields.stop_ratio = this.fieldsets.queue.add({
229 			xtype: 'uxspinner',
230 			id: 'stop_ratio',
231 			name: 'stop_ratio',
232 			disabled: true,
233 			width: 50,
234 			value: 2.0,
235 			strategy: {
236 				xtype: 'number',
237 				minValue: -1,
238 				maxValue: 99999,
239 				incrementValue: 0.1,
240 				alternateIncrementValue: 1,
241 				decimalPrecision: 1
242 			}
243 		});
244 		
245 		this.fields.remove_at_ratio = this.fieldsets.queue.add({
246 			fieldLabel: '',
247 			labelSeparator: '',
248 			id: 'remove_at_ratio',
249 			bodyStyle: 'padding-left: 10px',
250 			boxLabel: _('Remove at ratio'),
251 			disabled: true,
252 			colspan: 2
253 		});
254 		
255 		this.fields.move_completed = this.fieldsets.queue.add({
256 			fieldLabel: '',
257 			labelSeparator: '',
258 			id: 'move_completed',
259 			boxLabel: _('Move Completed'),
260 			colspan: 2
261 		});
262 		
263 		
264 		/*
265 		 * General Options
266 		 */
267 		this.rightColumn =  this.add({
268 			border: false,
269 			autoHeight: true,
270 			style: 'margin-left: 5px',
271 			width: 200
272 		});
273 		
274 		this.fieldsets.general = this.rightColumn.add({
275 			xtype: 'fieldset',
276 			autoHeight: true,
277 			defaultType: 'checkbox',
278 			title: _('General'),
279 			layout: 'form'
280 		});
281 		
282 		this.fields['private'] = this.fieldsets.general.add({
283 			fieldLabel: '',
284 			labelSeparator: '',
285 			boxLabel: _('Private'),
286 			id: 'private'
287 		});
288 		
289 		this.fields.prioritize_first_last = this.fieldsets.general.add({
290 			fieldLabel: '',
291 			labelSeparator: '',
292 			boxLabel: _('Prioritize First/Last'),
293 			id: 'prioritize_first_last'
294 		});
295 		
296 		// Bind the fields so the options manager can manage them.
297 		for (var id in this.fields) {
298 			this.optionsManager.bind(id, this.fields[id]);
299 		}
300 		
301 		/*
302 		 * Buttons
303 		 */
304 		this.buttonPanel = this.rightColumn.add({
305 			layout: 'column',
306 			xtype: 'panel',
307 			border: false
308 		});
309 		
310 		// The buttons below are required to be added to a panel
311 		// first as simply adding them to the column layout throws an
312 		// error c.getSize() does not exist. This could be intentional
313 		// or it may possible be a bug in ext-js. Take care when upgrading
314 		// to ext-js 3.0.
315 		
316 		/*
317 		 * Edit Trackers button
318 		 */
319 		this.buttonPanel.add({
320 			xtype: 'panel',
321 			border: false
322 		}).add({
323 			id: 'edit_trackers',
324 			xtype: 'button',
325 			text: _('Edit Trackers'),
326 			cls: 'x-btn-text-icon',
327 			iconCls: 'x-deluge-edit-trackers',
328 			border: false,
329 			width: 100,
330 			handler: this.onEditTrackers,
331 			scope: this
332 		});
333 		
334 		/*
335 		 * Apply button
336 		 */
337 		this.buttonPanel.add({
338 			xtype: 'panel',
339 			border: false
340 		}).add({
341 			id: 'apply',
342 			xtype: 'button',
343 			text: _('Apply'),
344 			style: 'margin-left: 10px;',
345 			border: false,
346 			width: 100,
347 			handler: this.onApply,
348 			scope: this
349 		});
350 	},
351 	
352 	onRender: function(ct, position) {
353 		Ext.deluge.details.OptionsTab.superclass.onRender.call(this, ct, position);
354 		
355 		// This is another hack I think, so keep an eye out here when upgrading.
356 		this.layout = new Ext.layout.ColumnLayout();
357 		this.layout.setContainer(this);
358 		this.doLayout();
359 	},
360 	
361 	clear: function() {
362 		this.optionsManager.changeId(null);
363 	},
364 	
365 	reset: function() {
366 		if (this.torrentId) {
367 			this.optionsManager.reset(this.torrentId);
368 		}
369 	},
370 	
371 	update: function(torrentId) {
372 		this.torrentId = torrentId;
373 		Deluge.Client.core.get_torrent_status(torrentId, Deluge.Keys.Options, {
374 			success: this.onRequestComplete,
375 			scope: this
376 		});
377 	},
378 	
379 	onApply: function() {
380 		var changed = this.optionsManager.getChanged(this.torrentId);
381 		if (!Ext.isEmpty(changed['prioritize_first_last'])) {
382 			var value = changed['prioritize_first_last'];
383 			Deluge.Client.core.set_torrent_prioritize_first_last(this.torrentId, value, {
384 				success: function() {
385 					this.optionsManager.set(this.torrentId, 'prioritize_first_last', value);
386 				},
387 				scope: this
388 			});
389 		}
390 		Deluge.Client.core.set_torrent_options([this.torrentId], changed, {
391 			success: function() {
392 				this.optionsManager.set(this.torrentId, changed);
393 				this.optionsManager.reset(this.torrentId);
394 			},
395 			scope: this
396 		});
397 	},
398 	
399 	onEditTrackers: function() {
400 		Deluge.EditTrackers.show();
401 	},
402 	
403 	onOptionChanged: function(id, key, newValue, oldValue) {
404 		if (key == 'stop_at_ratio') {
405 			this.fields.remove_at_ratio.setDisabled(!newValue);
406 			this.fields.stop_ratio.setDisabled(!newValue);
407 		}
408 	},
409 	
410 	onRequestComplete: function(torrent, options) {
411 		this.fields['private'].setDisabled(!torrent['private']);
412 		delete torrent['private'];
413 		
414 		this.optionsManager.update(this.torrentId, torrent);
415 	}
416 });
417 Deluge.Details.add(new Ext.deluge.details.OptionsTab());
418