Ticket #1380: scheduler.diff

File scheduler.diff, 18.8 KB (added by samuel337, 14 years ago)

Fixed a minor bug when reusing the schedule component.

  • 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);
     1Ext.ns('Deluge.ux');
     2
     3Deluge.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                });*/
    847        },
    948       
    1049        onRender: function(ct, position) {
    11                 ScheduleSelectPanel.superclass.onRender.call(this, ct, position);
     50                Deluge.ux.ScheduleSelector.superclass.onRender.call(this, ct, position);
    1251               
    1352                var dom = this.body.dom;
    14                 var table = createEl(dom, 'table');
    1553               
    1654                function createEl(parent, type) {
    1755                        var el = document.createElement(type);
    ScheduleSelectPanel = Ext.extend(Ext.form.FieldSet, {  
    1957                        return el;
    2058                }
    2159               
    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 = [ ];
    23117                        var row = createEl(table, 'tr');
    24118                        var label = createEl(row, 'th');
    25119                        label.setAttribute('style', 'font-weight: bold; padding-right: 5px;');
    26                         label.innerHTML = day;
     120                        label.appendChild(document.createTextNode(day));
    27121                        for (var hour = 0; hour < 24; hour++) {
    28122                                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;
    30167                        }
     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;
    31177                });
     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                }
    32458        }
    33459});
    34460
    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         },
     461Ext.ns('Deluge.ux.preferences');
     462
     463Deluge.ux.preferences.SchedulerPage = Ext.extend(Ext.Panel, {
     464       
     465        border: false,
     466        title: _('Scheduler'),
     467        layout: 'fit',
    43468       
    44469        initComponent: function() {
    45                 SchedulerPreferences.superclass.initComponent.call(this);
     470                Deluge.ux.preferences.SchedulerPage.superclass.initComponent.call(this);
    46471
    47472                this.form = this.add({
    48473                        xtype: 'form',
    SchedulerPreferences = Ext.extend(Ext.Panel, {  
    51476                        autoHeight: true
    52477                });
    53478               
    54                 this.schedule = this.form.add(new ScheduleSelectPanel());
     479                this.schedule = this.form.add(new Deluge.ux.ScheduleSelector());
    55480               
    56481                this.slowSettings = this.form.add({
    57482                        xtype: 'fieldset',
    58                         title: _('Slow Settings'),
     483                        border: false,
     484                        title: _('Throttled Settings'),
    59485                        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
    61493                });
    62494               
    63495                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
    66501                });
    67502                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
    70508                });
    71509                this.activeTorrents = this.slowSettings.add({
    72510                        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
    74529                });
    75530        },
    76531       
    77532        onRender: function(ct, position) {
    78                 SchedulerPreferences.superclass.onRender.call(this, ct, position);
     533                Deluge.ux.preferences.SchedulerPage.superclass.onRender.call(this, ct, position);
    79534                this.form.layout = new Ext.layout.FormLayout();
    80535                this.form.layout.setContainer(this);
    81536                this.form.doLayout();
    82537        },
    83538       
    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                });
    86570        }
    87571});
    88572
    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         },
     573Deluge.plugins.SchedulerPlugin = Ext.extend(Deluge.Plugin, {
     574       
     575        name: 'Scheduler',
    96576       
    97577        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);
    99581        },
    100582       
    101583        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());
    104585        }
    105586});
    106 new SchedulerPlugin();
    107  No newline at end of file
     587
     588Deluge.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, {  
    240240        // private
    241241        onOk: function() {
    242242                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               
    243248                this.hide();
    244249        }
    245250});