Ticket #1380: scheduler.diff
File scheduler.diff, 18.8 KB (added by , 14 years ago) |
---|
-
deluge/plugins/scheduler/scheduler/data/scheduler.js
diff --git a/deluge/plugins/scheduler/scheduler/data/scheduler.js b/deluge/plugins/scheduler/scheduler/data/scheduler.js index 7963903..8275cf4 100644
a b 1 ScheduleSelectPanel = Ext.extend(Ext.form.FieldSet, { 2 constructor: function(config) { 3 config = Ext.apply({ 4 title: _('Schedule'), 5 autoHeight: true 6 }, config); 7 ScheduleSelectPanel.superclass.constructor.call(this, config); 1 Ext.ns('Deluge.ux'); 2 3 Deluge.ux.ScheduleSelector = Ext.extend(Ext.form.FieldSet, { 4 5 title: _('Schedule'), 6 autoHeight: true, 7 style: 'margin-bottom: 0px; padding-bottom: 0px;', 8 border: false, 9 10 states: [ 11 { 12 name: 'Normal', 13 backgroundColor: 'LightGreen', 14 borderColor: 'DarkGreen', 15 value: 0 16 }, 17 { 18 name: 'Throttled', 19 backgroundColor: 'Yellow', 20 borderColor: 'Gold', 21 value: 1 22 }, 23 { 24 name: 'Paused', 25 backgroundColor: 'OrangeRed', 26 borderColor: 'FireBrick', 27 value: 2 28 } 29 ], 30 daysOfWeek: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'], 31 32 initComponent: function() { 33 Deluge.ux.ScheduleSelector.superclass.initComponent.call(this); 34 35 // ExtJS' radiogroup implementation is very broken for styling. 36 /*this.stateBrush = this.add({ 37 xtype: 'radiogroup', 38 fieldLabel: _('State Brush'), 39 name: 'current_state_brush', 40 submitValue: false, 41 items: [ 42 { boxLabel: 'Normal', name: 'current_state_brush', inputValue: 0 }, 43 { boxLabel: 'Throttled', name: 'current_state_brush', inputValue: 1, checked: true }, 44 { boxLabel: 'Paused', name: 'current_state_brush', inputValue: 2 }, 45 ] 46 });*/ 8 47 }, 9 48 10 49 onRender: function(ct, position) { 11 ScheduleSelectPanel.superclass.onRender.call(this, ct, position);50 Deluge.ux.ScheduleSelector.superclass.onRender.call(this, ct, position); 12 51 13 52 var dom = this.body.dom; 14 var table = createEl(dom, 'table');15 53 16 54 function createEl(parent, type) { 17 55 var el = document.createElement(type); … … ScheduleSelectPanel = Ext.extend(Ext.form.FieldSet, { 19 57 return el; 20 58 } 21 59 22 Ext.each(['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'], function(day) { 60 // create state brushes 61 // tack a random number to the end to avoid clashes 62 this.stateBrushName = 'schedule-state-brush-' + Math.round(Math.random() * 10000); 63 64 var el1 = createEl(dom, 'div'); 65 66 var el2 = createEl(el1, 'div'); 67 this.stateBrush = el2; 68 el2.id = this.stateBrushName; 69 70 // for webkit 71 var floatAttr = 'float'; 72 if (el2.style.float == undefined) { 73 // for firefox 74 if (el2.style.cssFloat != undefined) floatAttr = 'cssFloat'; 75 // for IE 76 if (el2.style.styleFloat != undefined) floatAttr = 'styleFloat'; 77 } 78 el2.style[floatAttr] = 'right'; 79 80 for (var i=0; i < this.states.length; i++) { 81 var el3 = createEl(el2, 'input'); 82 el3.type = 'radio'; 83 el3.value = this.states[i].value; 84 el3.name = this.stateBrushName; 85 el3.id = this.stateBrushName + '-' + this.states[i].name; 86 87 // isn't the first one 88 if (i > 0) el3.style.marginLeft = '7px'; 89 90 // assume the first is the default state, so make the 2nd one the default brush 91 if (i == 1) el3.checked = true; 92 93 var el4 = createEl(el2, 'label'); 94 el4.appendChild(document.createTextNode(this.states[i].name)); 95 el4.htmlFor = el3.id; 96 el4.style.backgroundColor = this.states[i].backgroundColor; 97 el4.style.borderBottom = '2px solid ' + this.states[i].borderColor; 98 el4.style.padding = '2px 3px'; 99 el4.style.marginLeft = '3px'; 100 } 101 102 el1.appendChild(document.createTextNode('Select a state brush:')); 103 104 el1.style.marginBottom = '10px'; 105 106 // keep the radio buttons separate from the time bars 107 createEl(dom, 'div').style.clear = 'both'; 108 109 var table = createEl(dom, 'table'); 110 table.cellSpacing = 0; 111 112 // cache access to cells for easier access later 113 this.scheduleCells = { }; 114 115 Ext.each(this.daysOfWeek, function(day) { 116 var cells = [ ]; 23 117 var row = createEl(table, 'tr'); 24 118 var label = createEl(row, 'th'); 25 119 label.setAttribute('style', 'font-weight: bold; padding-right: 5px;'); 26 label. innerHTML = day;120 label.appendChild(document.createTextNode(day)); 27 121 for (var hour = 0; hour < 24; hour++) { 28 122 var cell = createEl(row, 'td'); 29 cell.setAttribute('style', 'border: 1px solid Green; width: 16px; height: 20px; background: LightGreen;'); 123 124 // assume the first state is the default state 125 cell.currentValue = cell.oldValue = this.states[0].value; 126 cell.day = day; 127 cell.hour = hour; 128 129 cell.width = '16px'; 130 cell.height = '20px'; 131 132 cell.style.border = '1px solid #999999'; 133 // don't repeat borders in between cells 134 if (hour != 23) // not the last cell 135 cell.style.borderRight = 'none'; 136 137 this.updateCell(cell); 138 139 cells.push(cell); 140 141 cell = Ext.get(cell); 142 cell.on('click', this.onCellClick, this); 143 cell.on('mouseover', this.onCellMouseOver, this); 144 cell.on('mouseout', this.onCellMouseOut, this); 145 cell.on('mousedown', this.onCellMouseDown, this); 146 cell.on('mouseup', this.onCellMouseUp, this); 147 } 148 149 // insert gap row to provide visual separation 150 row = createEl(table, 'tr'); 151 // blank cell to create gap 152 createEl(row, 'td').height = '3px'; 153 154 this.scheduleCells[day] = cells; 155 }, this); 156 }, 157 158 updateCell: function(cell) { 159 // sanity check 160 if (cell.currentValue == undefined) return; 161 162 for (var i in this.states) { 163 var curState = this.states[i]; 164 if (curState.value == cell.currentValue) { 165 cell.style.background = curState.backgroundColor; 166 break; 30 167 } 168 } 169 }, 170 171 getCurrentBrushValue: function() { 172 var v = null; 173 var brushes = Ext.get(this.body.dom).findParent('form').elements[this.stateBrushName]; 174 Ext.each(brushes, function(b) { 175 if (b.checked) 176 v = b.value; 31 177 }); 178 179 return v; 180 }, 181 182 onCellClick: function(event, cell) { 183 cell.oldValue = cell.currentValue; 184 185 this.dragAnchor = null; 186 }, 187 188 onCellMouseDown: function(event, cell) { 189 this.dragAnchor = cell; 190 }, 191 192 onCellMouseUp: function(event, cell) { 193 // if we're dragging... 194 if (this.dragAnchor) { 195 // set all those between here and the anchor to the new values 196 if (cell.hour > this.dragAnchor.hour) 197 this.confirmCells(cell.day, this.dragAnchor.hour, cell.hour); 198 else if (cell.hour < this.dragAnchor.hour) 199 this.confirmCells(cell.day, cell.hour, this.dragAnchor.hour); 200 else 201 this.confirmCells(cell.day, cell.hour, cell.hour); 202 203 this.hideCellLeftTooltip(); 204 this.hideCellRightTooltip(); 205 this.dragAnchor = null; 206 } 207 }, 208 209 onCellMouseOver: function(event, cell) { 210 // LEFT TOOL TIP 211 // if it isn't showing and we're dragging, show it. 212 // otherwise if dragging, leave it alone unless we're dragging to the left. 213 // if we're not dragging, show it. 214 var leftTooltipCell = null; 215 if (!this.dragAnchor) 216 leftTooltipCell = cell; 217 else if ((this.dragAnchor && this.isCellLeftTooltipHidden()) || 218 (this.dragAnchor && this.dragAnchor.hour > cell.hour)) 219 leftTooltipCell = this.dragAnchor; 220 221 if (leftTooltipCell) { 222 var hour = leftTooltipCell.hour; 223 var pm = false; 224 225 // convert to 12-hour time 226 if (hour >= 12) { 227 pm = true; 228 if (hour > 12) hour -= 12; 229 } 230 // change 0 hour to 12am 231 else if (hour == 0) { 232 hour = 12; 233 } 234 this.showCellLeftTooltip(hour + ' ' + (pm ? 'pm' : 'am'), leftTooltipCell); 235 } 236 237 // RIGHT TOOL TIP 238 var rightTooltipCell = null; 239 if (this.dragAnchor) { 240 if (this.dragAnchor.hour == cell.hour) 241 this.hideCellRightTooltip(); 242 else if (this.dragAnchor.hour > cell.hour && this.isCellRightTooltipHidden()) 243 rightTooltipCell = this.dragAnchor; 244 else // cell.hour > this.dragAnchor.hour 245 rightTooltipCell = cell; 246 } 247 248 if (rightTooltipCell) { 249 var hour = rightTooltipCell.hour; 250 var pm = false; 251 252 // convert to 12-hour time 253 if (hour >= 12) { 254 pm = true; 255 if (hour > 12) hour -= 12; 256 } 257 // change 0 hour to 12am 258 else if (hour == 0) { 259 hour = 12; 260 } 261 this.showCellRightTooltip(hour + ' ' + (pm ? 'pm' : 'am'), rightTooltipCell); 262 } 263 264 // preview colour change and 265 // revert state for all those on the outer side of the drag if dragging 266 if (this.dragAnchor) { 267 if (cell.day != this.dragAnchor.day) { 268 // dragged into another day. Abort! Abort! 269 Ext.each(this.daysOfWeek, function(day) { 270 this.revertCells(day, 0, 23); 271 }, this); 272 this.dragAnchor = null; 273 this.hideCellLeftTooltip(); 274 this.hideCellRightTooltip(); 275 } 276 else if (cell.hour > this.dragAnchor.hour) { 277 // dragging right 278 this.revertCells(cell.day, cell.hour+1, 23); 279 this.previewCells(cell.day, this.dragAnchor.hour, cell.hour); 280 } 281 else if (cell.hour < this.dragAnchor.hour) { 282 // dragging left 283 this.revertCells(cell.day, 0, cell.hour-1); 284 this.previewCells(cell.day, cell.hour, this.dragAnchor.hour); 285 } 286 else { 287 // back to anchor cell 288 // don't know if it is from right or left, so revert all except this 289 this.revertCells(cell.day, cell.hour+1, 23); 290 this.revertCells(cell.day, 0, cell.hour-1); 291 } 292 } 293 else { 294 // not dragging, just preview this cell 295 this.previewCells(cell.day, cell.hour, cell.hour); 296 } 297 }, 298 299 onCellMouseOut: function(event, cell) { 300 if (!this.dragAnchor) 301 this.hideCellLeftTooltip(); 302 303 // revert state. If new state has been set, old and new will be equal. 304 // if dragging, this will be handled by the next mouse over 305 if (this.dragAnchor == null && cell.oldValue != cell.currentValue) { 306 this.revertCells(cell.day, cell.hour, cell.hour); 307 } 308 }, 309 310 previewCells: function(day, fromHour, toHour) { 311 var cells = this.scheduleCells[day]; 312 var curBrushValue = this.getCurrentBrushValue(); 313 314 if (toHour > cells.length) toHour = cells.length; 315 316 for (var i=fromHour; i <= toHour; i++) { 317 if (cells[i].currentValue != curBrushValue) { 318 cells[i].oldValue = cells[i].currentValue; 319 cells[i].currentValue = curBrushValue; 320 this.updateCell(cells[i]); 321 } 322 } 323 }, 324 325 revertCells: function(day, fromHour, toHour) { 326 var cells = this.scheduleCells[day]; 327 328 if (toHour > cells.length) toHour = cells.length; 329 330 for (var i=fromHour; i <= toHour; i++) { 331 cells[i].currentValue = cells[i].oldValue; 332 this.updateCell(cells[i]); 333 } 334 }, 335 336 confirmCells: function(day, fromHour, toHour) { 337 var cells = this.scheduleCells[day]; 338 339 if (toHour > cells.length) toHour = cells.length; 340 341 for (var i=fromHour; i <= toHour; i++) { 342 if (cells[i].currentValue != cells[i].oldValue) { 343 cells[i].oldValue = cells[i].currentValue; 344 } 345 } 346 }, 347 348 showCellLeftTooltip: function(text, cell) { 349 var tooltip = this.cellLeftTooltip; 350 351 if (!tooltip) { 352 // no cached left tooltip exists, create one 353 tooltip = document.createElement('div'); 354 this.cellLeftTooltip = tooltip; 355 this.body.dom.appendChild(tooltip); 356 tooltip.style.position = 'absolute'; 357 tooltip.style.backgroundColor = '#F2F2F2'; 358 tooltip.style.border = '1px solid #333333'; 359 tooltip.style.padding = '1px 3px'; 360 tooltip.style.opacity = 0.8; 361 } 362 363 // remove all existing children 364 while (tooltip.childNodes.length > 0) { 365 tooltip.removeChild(tooltip.firstChild); 366 } 367 // add the requested text 368 tooltip.appendChild(document.createTextNode(text)); 369 370 // place the tooltip 371 Ext.get(tooltip).alignTo(cell, 'br-tr'); 372 373 // make it visible 374 tooltip.style.visibility = 'visible'; 375 }, 376 377 hideCellLeftTooltip: function() { 378 if (this.cellLeftTooltip) { 379 this.cellLeftTooltip.style.visibility = 'hidden'; 380 } 381 }, 382 383 isCellLeftTooltipHidden: function() { 384 if (this.cellLeftTooltip) 385 return this.cellLeftTooltip.style.visibility == 'hidden'; 386 else 387 return true; 388 }, 389 390 showCellRightTooltip: function(text, cell) { 391 var tooltip = this.cellRightTooltip; 392 393 if (!tooltip) { 394 // no cached left tooltip exists, create one 395 tooltip = document.createElement('div'); 396 this.cellRightTooltip = tooltip; 397 this.body.dom.appendChild(tooltip); 398 tooltip.style.position = 'absolute'; 399 tooltip.style.backgroundColor = '#F2F2F2'; 400 tooltip.style.border = '1px solid #333333'; 401 tooltip.style.padding = '1px 3px'; 402 tooltip.style.opacity = 0.8; 403 } 404 405 // remove all existing children 406 while (tooltip.childNodes.length > 0) { 407 tooltip.removeChild(tooltip.firstChild); 408 } 409 // add the requested text 410 tooltip.appendChild(document.createTextNode(text)); 411 412 // place the tooltip 413 Ext.get(tooltip).alignTo(cell, 'bl-tl'); 414 415 // make it visible 416 tooltip.style.visibility = 'visible'; 417 }, 418 419 hideCellRightTooltip: function() { 420 if (this.cellRightTooltip) { 421 this.cellRightTooltip.style.visibility = 'hidden'; 422 } 423 }, 424 425 isCellRightTooltipHidden: function() { 426 if (this.cellRightTooltip) 427 return this.cellRightTooltip.style.visibility == 'hidden'; 428 else 429 return true; 430 }, 431 432 getConfig: function() { 433 var config = [ ]; 434 435 for (var i=0; i < 24; i++) { 436 var hourConfig = [ 0, 0, 0, 0, 0, 0, 0 ]; 437 438 for (var j=0; j < this.daysOfWeek.length; j++) { 439 hourConfig[j] = parseInt(this.scheduleCells[this.daysOfWeek[j]][i].currentValue); 440 } 441 442 config.push(hourConfig); 443 } 444 445 return config; 446 }, 447 448 setConfig: function(config) { 449 for (var i=0; i < 24; i++) { 450 var hourConfig = config[i]; 451 452 for (var j=0; j < this.daysOfWeek.length; j++) { 453 var cell = this.scheduleCells[this.daysOfWeek[j]][i]; 454 cell.currentValue = cell.oldValue = hourConfig[j]; 455 this.updateCell(cell); 456 } 457 } 32 458 } 33 459 }); 34 460 35 SchedulerPreferences = Ext.extend(Ext.Panel, { 36 constructor: function(config) { 37 config = Ext.apply({ 38 border: false, 39 title: _('Scheduler') 40 }, config); 41 SchedulerPreferences.superclass.constructor.call(this, config); 42 }, 461 Ext.ns('Deluge.ux.preferences'); 462 463 Deluge.ux.preferences.SchedulerPage = Ext.extend(Ext.Panel, { 464 465 border: false, 466 title: _('Scheduler'), 467 layout: 'fit', 43 468 44 469 initComponent: function() { 45 SchedulerPreferences.superclass.initComponent.call(this);470 Deluge.ux.preferences.SchedulerPage.superclass.initComponent.call(this); 46 471 47 472 this.form = this.add({ 48 473 xtype: 'form', … … SchedulerPreferences = Ext.extend(Ext.Panel, { 51 476 autoHeight: true 52 477 }); 53 478 54 this.schedule = this.form.add(new ScheduleSelectPanel());479 this.schedule = this.form.add(new Deluge.ux.ScheduleSelector()); 55 480 56 481 this.slowSettings = this.form.add({ 57 482 xtype: 'fieldset', 58 title: _('Slow Settings'), 483 border: false, 484 title: _('Throttled Settings'), 59 485 autoHeight: true, 60 defaultType: 'uxspinner' 486 defaultType: 'spinnerfield', 487 defaults: { 488 minValue: -1, 489 maxValue: 99999 490 }, 491 style: 'margin-top: 5px; margin-bottom: 0px; padding-bottom: 0px;', 492 labelWidth: 200 61 493 }); 62 494 63 495 this.downloadLimit = this.slowSettings.add({ 64 fieldLabel: _('Download Limit'), 65 name: 'download_limit' 496 fieldLabel: _('Maximum Download Speed (KiB/s)'), 497 name: 'download_limit', 498 width: 80, 499 value: -1, 500 decimalPrecision: 0 66 501 }); 67 502 this.uploadLimit = this.slowSettings.add({ 68 fieldLabel: _('Upload Limit'), 69 name: 'upload_limit' 503 fieldLabel: _('Maximum Upload Speed (KiB/s)'), 504 name: 'upload_limit', 505 width: 80, 506 value: -1, 507 decimalPrecision: 0 70 508 }); 71 509 this.activeTorrents = this.slowSettings.add({ 72 510 fieldLabel: _('Active Torrents'), 73 name: 'active_torrents' 511 name: 'active_torrents', 512 width: 80, 513 value: -1, 514 decimalPrecision: 0 515 }); 516 this.activeDownloading = this.slowSettings.add({ 517 fieldLabel: _('Active Downloading'), 518 name: 'active_downloading', 519 width: 80, 520 value: -1, 521 decimalPrecision: 0 522 }); 523 this.activeSeeding = this.slowSettings.add({ 524 fieldLabel: _('Active Seeding'), 525 name: 'active_seeding', 526 width: 80, 527 value: -1, 528 decimalPrecision: 0 74 529 }); 75 530 }, 76 531 77 532 onRender: function(ct, position) { 78 SchedulerPreferences.superclass.onRender.call(this, ct, position);533 Deluge.ux.preferences.SchedulerPage.superclass.onRender.call(this, ct, position); 79 534 this.form.layout = new Ext.layout.FormLayout(); 80 535 this.form.layout.setContainer(this); 81 536 this.form.doLayout(); 82 537 }, 83 538 84 onShow: function() { 85 SchedulerPreferences.superclass.onShow.call(this); 539 onApply: function() { 540 // build settings object 541 var config = { } 542 543 config['button_state'] = this.schedule.getConfig(); 544 config['low_down'] = this.downloadLimit.getValue(); 545 config['low_up'] = this.uploadLimit.getValue(); 546 config['low_active'] = this.activeTorrents.getValue(); 547 config['low_active_down'] = this.activeDownloading.getValue(); 548 config['low_active_up'] = this.activeSeeding.getValue(); 549 550 deluge.client.scheduler.set_config(config); 551 }, 552 553 afterRender: function() { 554 Deluge.ux.preferences.SchedulerPage.superclass.afterRender.call(this); 555 this.updateConfig(); 556 }, 557 558 updateConfig: function() { 559 deluge.client.scheduler.get_config({ 560 success: function(config) { 561 this.schedule.setConfig(config['button_state']); 562 this.downloadLimit.setValue(config['low_down']); 563 this.uploadLimit.setValue(config['low_up']); 564 this.activeTorrents.setValue(config['low_active']); 565 this.activeDownloading.setValue(config['low_active_down']); 566 this.activeSeeding.setValue(config['low_active_up']); 567 }, 568 scope: this 569 }); 86 570 } 87 571 }); 88 572 89 SchedulerPlugin = Ext.extend(Deluge.Plugin, { 90 constructor: function(config) { 91 config = Ext.apply({ 92 name: "Scheduler" 93 }, config); 94 SchedulerPlugin.superclass.constructor.call(this, config); 95 }, 573 Deluge.plugins.SchedulerPlugin = Ext.extend(Deluge.Plugin, { 574 575 name: 'Scheduler', 96 576 97 577 onDisable: function() { 98 Deluge.Preferences.removePage(this.prefsPage); 578 // use LOWERCASE for deluge.preferences to get the instance 579 // of PreferencesWindow, instead of the class. 580 deluge.preferences.removePage(this.prefsPage); 99 581 }, 100 582 101 583 onEnable: function() { 102 this.prefsPage = new SchedulerPreferences(); 103 this.prefsPage = Deluge.Preferences.addPage(this.prefsPage); 584 this.prefsPage = deluge.preferences.addPage(new Deluge.ux.preferences.SchedulerPage()); 104 585 } 105 586 }); 106 new SchedulerPlugin(); 107 No newline at end of file 587 588 Deluge.registerPlugin('Scheduler', Deluge.plugins.SchedulerPlugin); 589 No newline at end of file -
deluge/ui/web/js/deluge-all/preferences/PreferencesWindow.js
diff --git a/deluge/ui/web/js/deluge-all/preferences/PreferencesWindow.js b/deluge/ui/web/js/deluge-all/preferences/PreferencesWindow.js index f71c463..2e1fbc6 100644
a b Deluge.preferences.PreferencesWindow = Ext.extend(Ext.Window, { 240 240 // private 241 241 onOk: function() { 242 242 deluge.client.core.set_config(this.optionsManager.getDirty()); 243 244 for (var page in this.pages) { 245 if (this.pages[page].onApply) this.pages[page].onApply(); 246 } 247 243 248 this.hide(); 244 249 } 245 250 });