]> git.proxmox.com Git - pve-manager.git/blame - www/manager6/qemu/HardwareView.js
gui: qemu/HardwareView: remove Keyboard setting
[pve-manager.git] / www / manager6 / qemu / HardwareView.js
CommitLineData
f97670f5 1Ext.define('PVE.qemu.HardwareView', {
bc0eaf58 2 extend: 'Proxmox.grid.PendingObjectGrid',
f97670f5
DM
3 alias: ['widget.PVE.qemu.HardwareView'],
4
ba93a9c6
DC
5 onlineHelp: 'qm_virtual_machines_settings',
6
f97670f5
DM
7 renderKey: function(key, metaData, rec, rowIndex, colIndex, store) {
8 var me = this;
9 var rows = me.rows;
10 var rowdef = rows[key] || {};
6a040799
DC
11 var iconCls = rowdef.iconCls;
12 var icon = '';
13 var txt = (rowdef.header || key);
f97670f5
DM
14
15 metaData.tdAttr = "valign=middle";
16
17 if (rowdef.tdCls) {
18 metaData.tdCls = rowdef.tdCls;
19 if (rowdef.tdCls == 'pve-itype-icon-storage') {
cdf5bec2
DL
20 var value = me.getObjectValue(key, '', false);
21 if (value === '') {
22 value = me.getObjectValue(key, '', true);
23 }
b38d0810
DC
24 if (value.match(/vm-.*-cloudinit/)) {
25 metaData.tdCls = 'pve-itype-icon-cloud';
26 return rowdef.cloudheader;
27 } else if (value.match(/media=cdrom/)) {
f97670f5
DM
28 metaData.tdCls = 'pve-itype-icon-cdrom';
29 return rowdef.cdheader;
30 }
31 }
6a040799
DC
32 } else if (iconCls) {
33 icon = "<i class='pve-grid-fa fa fa-fw fa-" + iconCls + "'></i>";
34 metaData.tdCls += " pve-itype-fa";
f97670f5 35 }
6a040799 36 return icon + txt;
f97670f5
DM
37 },
38
39 initComponent : function() {
40 var me = this;
41 var i, confid;
42
43 var nodename = me.pveSelNode.data.node;
44 if (!nodename) {
45 throw "no node name specified";
46 }
47
48 var vmid = me.pveSelNode.data.vmid;
49 if (!vmid) {
50 throw "no VM ID specified";
51 }
52
53 var caps = Ext.state.Manager.get('GuiCap');
54
55 var rows = {
56 memory: {
57 header: gettext('Memory'),
58 editor: caps.vms['VM.Config.Memory'] ? 'PVE.qemu.MemoryEdit' : undefined,
59 never_delete: true,
72408db9 60 defaultValue: '512',
f97670f5 61 tdCls: 'pve-itype-icon-memory',
cbe0b4b8 62 group: 2,
1d902252
DC
63 multiKey: ['memory', 'balloon', 'shares'],
64 renderer: function(value, metaData, record, ri, ci, store, pending) {
65 var res = '';
66
67 var max = me.getObjectValue('memory', 512, pending);
68 var balloon = me.getObjectValue('balloon', undefined, pending);
69 var shares = me.getObjectValue('shares', undefined, pending);
70
71 res = Proxmox.Utils.format_size(max*1024*1024);
72
73 if (balloon !== undefined && balloon > 0) {
74 res = Proxmox.Utils.format_size(balloon*1024*1024) + "/" + res;
75
76 if (shares) {
77 res += ' [shares=' + shares +']';
78 }
79 } else if (balloon === 0) {
80 res += ' [balloon=0]';
81 }
82 return res;
f97670f5
DM
83 }
84 },
85 sockets: {
86 header: gettext('Processors'),
87 never_delete: true,
88 editor: (caps.vms['VM.Config.CPU'] || caps.vms['VM.Config.HWType']) ?
89 'PVE.qemu.ProcessorEdit' : undefined,
90 tdCls: 'pve-itype-icon-processor',
cbe0b4b8 91 group: 3,
72408db9 92 defaultValue: '1',
f97670f5
DM
93 multiKey: ['sockets', 'cpu', 'cores', 'numa', 'vcpus', 'cpulimit', 'cpuunits'],
94 renderer: function(value, metaData, record, rowIndex, colIndex, store, pending) {
95
96 var sockets = me.getObjectValue('sockets', 1, pending);
97 var model = me.getObjectValue('cpu', undefined, pending);
98 var cores = me.getObjectValue('cores', 1, pending);
99 var numa = me.getObjectValue('numa', undefined, pending);
100 var vcpus = me.getObjectValue('vcpus', undefined, pending);
101 var cpulimit = me.getObjectValue('cpulimit', undefined, pending);
102 var cpuunits = me.getObjectValue('cpuunits', undefined, pending);
103
72408db9
EK
104 var res = Ext.String.format('{0} ({1} sockets, {2} cores)',
105 sockets*cores, sockets, cores);
106
f97670f5
DM
107 if (model) {
108 res += ' [' + model + ']';
109 }
110
111 if (numa) {
112 res += ' [numa=' + numa +']';
113 }
114
115 if (vcpus) {
116 res += ' [vcpus=' + vcpus +']';
117 }
118
119 if (cpulimit) {
120 res += ' [cpulimit=' + cpulimit +']';
121 }
122
123 if (cpuunits) {
124 res += ' [cpuunits=' + cpuunits +']';
125 }
126
127 return res;
128 }
129 },
f97670f5
DM
130 vga: {
131 header: gettext('Display'),
132 editor: caps.vms['VM.Config.HWType'] ? 'PVE.qemu.DisplayEdit' : undefined,
133 never_delete: true,
134 tdCls: 'pve-itype-icon-display',
cbe0b4b8 135 group:4,
f97670f5
DM
136 defaultValue: '',
137 renderer: PVE.Utils.render_kvm_vga_driver
138 },
139 cores: {
140 visible: false
141 },
142 cpu: {
143 visible: false
144 },
145 numa: {
146 visible: false
147 },
148 balloon: {
149 visible: false
150 },
151 hotplug: {
152 visible: false
153 },
154 vcpus: {
155 visible: false
156 },
157 cpuunits: {
158 visible: false
159 },
160 cpulimit: {
161 visible: false
3b37ab6d
DC
162 },
163 bios: {
164 visible: false
1d902252
DC
165 },
166 shares: {
167 visible: false
f97670f5 168 }
f97670f5
DM
169 };
170
abe824aa
DC
171 PVE.Utils.forEachBus(undefined, function(type, id) {
172 var confid = type + id;
f97670f5 173 rows[confid] = {
8d554444 174 group: 10,
f97670f5
DM
175 tdCls: 'pve-itype-icon-storage',
176 editor: 'PVE.qemu.HDEdit',
177 never_delete: caps.vms['VM.Config.Disk'] ? false : true,
178 header: gettext('Hard Disk') + ' (' + confid +')',
b38d0810
DC
179 cdheader: gettext('CD/DVD Drive') + ' (' + confid +')',
180 cloudheader: gettext('CloudInit Drive') + ' (' + confid + ')'
f97670f5 181 };
abe824aa 182 });
f97670f5 183 for (i = 0; i < 32; i++) {
72408db9 184 confid = "net" + i.toString();
f97670f5 185 rows[confid] = {
8d554444 186 group: 15,
cbe0b4b8 187 order: i,
f97670f5
DM
188 tdCls: 'pve-itype-icon-network',
189 editor: caps.vms['VM.Config.Network'] ? 'PVE.qemu.NetworkEdit' : undefined,
190 never_delete: caps.vms['VM.Config.Network'] ? false : true,
191 header: gettext('Network Device') + ' (' + confid +')'
192 };
193 }
194c9b09 194 rows.efidisk0 = {
8d554444 195 group: 20,
194c9b09
DC
196 tdCls: 'pve-itype-icon-storage',
197 editor: null,
198 never_delete: caps.vms['VM.Config.Disk'] ? false : true,
199 header: gettext('EFI Disk')
200 };
fa522e48 201 for (i = 0; i < 5; i++) {
72408db9 202 confid = "usb" + i.toString();
fa522e48 203 rows[confid] = {
8d554444 204 group: 25,
cbe0b4b8 205 order: i,
fa522e48 206 tdCls: 'pve-itype-icon-usb',
2668ba64
DC
207 editor: caps.nodes['Sys.Console'] ? 'PVE.qemu.USBEdit' : undefined,
208 never_delete: caps.nodes['Sys.Console'] ? false : true,
fa522e48
DC
209 header: gettext('USB Device') + ' (' + confid + ')'
210 };
211 }
ec3d8372 212 for (i = 0; i < 4; i++) {
72408db9 213 confid = "hostpci" + i.toString();
ec3d8372 214 rows[confid] = {
8d554444 215 group: 30,
cbe0b4b8 216 order: i,
ec3d8372
DC
217 tdCls: 'pve-itype-icon-pci',
218 never_delete: caps.nodes['Sys.Console'] ? false : true,
25a1063a 219 editor: caps.nodes['Sys.Console'] ? 'PVE.qemu.PCIEdit' : undefined,
ec3d8372
DC
220 header: gettext('PCI Device') + ' (' + confid + ')'
221 };
222 }
a488da8c
DC
223 for (i = 0; i < 4; i++) {
224 confid = "serial" + i.toString();
225 rows[confid] = {
8d554444 226 group: 35,
cbe0b4b8 227 order: i,
a488da8c
DC
228 tdCls: 'pve-itype-icon-serial',
229 never_delete: caps.nodes['Sys.Console'] ? false : true,
230 header: gettext('Serial Port') + ' (' + confid + ')'
231 };
232 }
afa19975 233 for (i = 0; i < 256; i++) {
72408db9 234 rows["unused" + i.toString()] = {
cd86ab24 235 group: 99,
cbe0b4b8 236 order: i,
f97670f5
DM
237 tdCls: 'pve-itype-icon-storage',
238 editor: caps.vms['VM.Config.Disk'] ? 'PVE.qemu.HDEdit' : undefined,
72408db9 239 header: gettext('Unused Disk') + ' ' + i.toString()
f97670f5
DM
240 };
241 }
242
243 var sorterFn = function(rec1, rec2) {
244 var v1 = rec1.data.key;
245 var v2 = rec2.data.key;
246 var g1 = rows[v1].group || 0;
247 var g2 = rows[v2].group || 0;
cbe0b4b8
DL
248 var order1 = rows[v1].order || 0;
249 var order2 = rows[v2].order || 0;
250
251 if ((g1 - g2) !== 0) {
252 return g1 - g2;
253 }
f97670f5 254
cbe0b4b8
DL
255 if ((order1 - order2) !== 0) {
256 return order1 - order2;
257 }
258
259 if (v1 > v2) {
260 return 1;
261 } else if (v1 < v2) {
262 return -1;
263 } else {
264 return 0;
265 }
f97670f5
DM
266 };
267
268 var reload = function() {
269 me.rstore.load();
270 };
271
272 var baseurl = 'nodes/' + nodename + '/qemu/' + vmid + '/config';
273
274 var sm = Ext.create('Ext.selection.RowModel', {});
275
276 var run_editor = function() {
277 var rec = sm.getSelection()[0];
278 if (!rec) {
279 return;
280 }
281
282 var rowdef = rows[rec.data.key];
283 if (!rowdef.editor) {
284 return;
285 }
286
287 var editor = rowdef.editor;
288 if (rowdef.tdCls == 'pve-itype-icon-storage') {
289 var value = me.getObjectValue(rec.data.key, '', true);
ab1ee352
DC
290 if (value.match(/vm-.*-cloudinit/)) {
291 return;
292 } else if (value.match(/media=cdrom/)) {
f97670f5
DM
293 editor = 'PVE.qemu.CDEdit';
294 }
295 }
296
297 var win;
298
299 if (Ext.isString(editor)) {
300 win = Ext.create(editor, {
301 pveSelNode: me.pveSelNode,
302 confid: rec.data.key,
303 url: '/api2/extjs/' + baseurl
304 });
305 } else {
306 var config = Ext.apply({
307 pveSelNode: me.pveSelNode,
308 confid: rec.data.key,
309 url: '/api2/extjs/' + baseurl
310 }, rowdef.editor);
311 win = Ext.createWidget(rowdef.editor.xtype, config);
312 win.load();
313 }
314
315 win.show();
316 win.on('destroy', reload);
317 };
318
f97670f5
DM
319 var run_resize = function() {
320 var rec = sm.getSelection()[0];
321 if (!rec) {
322 return;
323 }
324
325 var win = Ext.create('PVE.window.HDResize', {
326 disk: rec.data.key,
327 nodename: nodename,
328 vmid: vmid
329 });
330
331 win.show();
332
333 win.on('destroy', reload);
334 };
335
f97670f5
DM
336 var run_move = function() {
337 var rec = sm.getSelection()[0];
338 if (!rec) {
339 return;
340 }
341
342 var win = Ext.create('PVE.window.HDMove', {
343 disk: rec.data.key,
344 nodename: nodename,
345 vmid: vmid
346 });
347
348 win.show();
349
350 win.on('destroy', reload);
351 };
352
5720fafa 353 var edit_btn = new Proxmox.button.Button({
f97670f5
DM
354 text: gettext('Edit'),
355 selModel: sm,
356 disabled: true,
357 handler: run_editor
358 });
359
5720fafa 360 var resize_btn = new Proxmox.button.Button({
f97670f5
DM
361 text: gettext('Resize disk'),
362 selModel: sm,
363 disabled: true,
364 handler: run_resize
365 });
366
5720fafa 367 var move_btn = new Proxmox.button.Button({
f97670f5
DM
368 text: gettext('Move disk'),
369 selModel: sm,
370 disabled: true,
371 handler: run_move
372 });
373
5720fafa 374 var remove_btn = new Proxmox.button.Button({
f97670f5 375 text: gettext('Remove'),
877fce54
EK
376 defaultText: gettext('Remove'),
377 altText: gettext('Detach'),
f97670f5
DM
378 selModel: sm,
379 disabled: true,
380 dangerous: true,
3b2e557f 381 RESTMethod: 'PUT',
f97670f5 382 confirmMsg: function(rec) {
ff5a8a9b
EK
383 var warn = gettext('Are you sure you want to remove entry {0}');
384 if (this.text === this.altText) {
385 warn = gettext('Are you sure you want to detach entry {0}');
386 }
387
388 var entry = rec.data.key;
389 var msg = Ext.String.format(warn, "'"
390 + me.renderKey(entry, {}, rec) + "'");
391
392 if (entry.match(/^unused\d+$/)) {
16152937 393 msg += " " + gettext('This will permanently erase all data.');
f97670f5
DM
394 }
395
396 return msg;
397 },
398 handler: function(b, e, rec) {
e7ade592 399 Proxmox.Utils.API2Request({
f97670f5
DM
400 url: '/api2/extjs/' + baseurl,
401 waitMsgTarget: me,
3b2e557f 402 method: b.RESTMethod,
f97670f5
DM
403 params: {
404 'delete': rec.data.key
405 },
406 callback: function() {
407 reload();
408 },
409 failure: function (response, opts) {
410 Ext.Msg.alert('Error', response.htmlStatus);
3b2e557f
TM
411 },
412 success: function(response, options) {
413 if (b.RESTMethod === 'POST') {
414 var upid = response.result.data;
415 var win = Ext.create('Proxmox.window.TaskProgress', {
416 upid: upid,
417 listeners: {
418 destroy: function () {
419 me.reload();
420 }
421 }
422 });
423 win.show();
424 }
f97670f5
DM
425 }
426 });
877fce54
EK
427 },
428 listeners: {
429 render: function(btn) {
430 // hack: calculate an optimal button width on first display
431 // to prevent the whole toolbar to move when we switch
432 // between the "Remove" and "Detach" labels
433 var def = btn.getSize().width;
434
435 btn.setText(btn.altText);
436 var alt = btn.getSize().width;
437
438 btn.setText(btn.defaultText);
439
440 var optimal = alt > def ? alt : def;
441 btn.setSize({ width: optimal });
442 }
f97670f5
DM
443 }
444 });
445
5720fafa 446 var revert_btn = new Proxmox.button.Button({
f97670f5
DM
447 text: gettext('Revert'),
448 selModel: sm,
449 disabled: true,
450 handler: function(b, e, rec) {
451 var rowdef = me.rows[rec.data.key] || {};
452 var keys = rowdef.multiKey || [ rec.data.key ];
453 var revert = keys.join(',');
e7ade592 454 Proxmox.Utils.API2Request({
f97670f5
DM
455 url: '/api2/extjs/' + baseurl,
456 waitMsgTarget: me,
457 method: 'PUT',
458 params: {
459 'revert': revert
460 },
461 callback: function() {
462 reload();
463 },
464 failure: function (response, opts) {
465 Ext.Msg.alert('Error',response.htmlStatus);
466 }
467 });
468 }
469 });
470
3b37ab6d
DC
471 var efidisk_menuitem = Ext.create('Ext.menu.Item',{
472 text: gettext('EFI Disk'),
473 iconCls: 'pve-itype-icon-storage',
474 disabled: !caps.vms['VM.Config.Disk'],
475 handler: function() {
1535df62
DC
476
477 var rstoredata = me.rstore.getData().map;
478 // check if ovmf is configured
479 if (rstoredata.bios && rstoredata.bios.data.value === 'ovmf') {
480 var win = Ext.create('PVE.qemu.EFIDiskEdit', {
481 url: '/api2/extjs/' + baseurl,
482 pveSelNode: me.pveSelNode
483 });
484 win.on('destroy', reload);
485 win.show();
486 } else {
487 Ext.Msg.alert('Error',gettext('Please select OVMF(UEFI) as BIOS first.'));
488 }
489
3b37ab6d
DC
490 }
491 });
492
f97670f5
DM
493 var set_button_status = function() {
494 var sm = me.getSelectionModel();
495 var rec = sm.getSelection()[0];
496
1535df62
DC
497 // disable button when we have an efidisk already
498 // disable is ok in this case, because you can instantly
499 // see that there is already one
500 efidisk_menuitem.setDisabled(me.rstore.getData().map.efidisk0 !== undefined);
2668ba64 501 // en/disable usb add button
25a1063a
DC
502 var usbcount = 0;
503 var pcicount = 0;
b38d0810 504 var hasCloudInit = false;
2668ba64
DC
505 me.rstore.getData().items.forEach(function(item){
506 if (/^usb\d+/.test(item.id)) {
25a1063a
DC
507 usbcount++;
508 } else if (/^hostpci\d+/.test(item.id)) {
509 pcicount++;
2668ba64 510 }
b38d0810
DC
511 if (!hasCloudInit && /vm-.*-cloudinit/.test(item.data.value)) {
512 hasCloudInit = true;
513 }
2668ba64 514 });
3097170d
TL
515
516 // heuristic only for disabling some stuff, the backend has the final word.
517 var noSysConsolePerm = !caps.nodes['Sys.Console'];
518
25a1063a
DC
519 me.down('#addusb').setDisabled(noSysConsolePerm || (usbcount >= 5));
520 me.down('#addpci').setDisabled(noSysConsolePerm || (pcicount >= 4));
3097170d 521 me.down('#addci').setDisabled(noSysConsolePerm || hasCloudInit);
3b37ab6d 522
f97670f5
DM
523 if (!rec) {
524 remove_btn.disable();
525 edit_btn.disable();
526 resize_btn.disable();
527 move_btn.disable();
f97670f5
DM
528 revert_btn.disable();
529 return;
530 }
531 var key = rec.data.key;
532 var value = rec.data.value;
533 var rowdef = rows[key];
534
535 var pending = rec.data['delete'] || me.hasPendingChanges(key);
3b2e557f
TM
536 var isUnusedDisk = key.match(/^unused\d+/);
537 var isUsedDisk = !isUnusedDisk &&
25e0bc2d
DC
538 rowdef.tdCls == 'pve-itype-icon-storage' &&
539 (value && !value.match(/media=cdrom/));
f97670f5 540
ab1ee352 541 var isCloudInit = (value && value.toString().match(/vm-.*-cloudinit/));
b38d0810 542
3b37ab6d
DC
543 var isEfi = (key === 'efidisk0');
544
f97670f5 545 remove_btn.setDisabled(rec.data['delete'] || (rowdef.never_delete === true));
ab1ee352 546 remove_btn.setText((isUsedDisk && !isCloudInit) ? remove_btn.altText : remove_btn.defaultText);
3b2e557f 547 remove_btn.RESTMethod = isUnusedDisk ? 'POST':'PUT';
f97670f5 548
b38d0810 549 edit_btn.setDisabled(rec.data['delete'] || !rowdef.editor || isCloudInit);
f97670f5 550
877fce54 551 resize_btn.setDisabled(pending || !isUsedDisk);
f97670f5 552
877fce54 553 move_btn.setDisabled(pending || !isUsedDisk);
f97670f5 554
f97670f5
DM
555 revert_btn.setDisabled(!pending);
556
557 };
558
f09dd6c1 559 Ext.apply(me, {
f97670f5
DM
560 url: '/api2/json/' + 'nodes/' + nodename + '/qemu/' + vmid + '/pending',
561 interval: 5000,
562 selModel: sm,
b08ae044 563 run_editor: run_editor,
f97670f5
DM
564 tbar: [
565 {
566 text: gettext('Add'),
567 menu: new Ext.menu.Menu({
568 items: [
569 {
570 text: gettext('Hard Disk'),
571 iconCls: 'pve-itype-icon-storage',
572 disabled: !caps.vms['VM.Config.Disk'],
573 handler: function() {
574 var win = Ext.create('PVE.qemu.HDEdit', {
575 url: '/api2/extjs/' + baseurl,
576 pveSelNode: me.pveSelNode
577 });
578 win.on('destroy', reload);
579 win.show();
580 }
581 },
582 {
583 text: gettext('CD/DVD Drive'),
584 iconCls: 'pve-itype-icon-cdrom',
585 disabled: !caps.vms['VM.Config.Disk'],
586 handler: function() {
587 var win = Ext.create('PVE.qemu.CDEdit', {
588 url: '/api2/extjs/' + baseurl,
589 pveSelNode: me.pveSelNode
590 });
591 win.on('destroy', reload);
592 win.show();
593 }
594 },
595 {
596 text: gettext('Network Device'),
597 iconCls: 'pve-itype-icon-network',
598 disabled: !caps.vms['VM.Config.Network'],
599 handler: function() {
600 var win = Ext.create('PVE.qemu.NetworkEdit', {
601 url: '/api2/extjs/' + baseurl,
602 pveSelNode: me.pveSelNode
603 });
604 win.on('destroy', reload);
605 win.show();
606 }
3b37ab6d 607 },
2668ba64
DC
608 efidisk_menuitem,
609 {
610 text: gettext('USB Device'),
611 itemId: 'addusb',
612 iconCls: 'pve-itype-icon-usb',
613 disabled: !caps.nodes['Sys.Console'],
614 handler: function() {
615 var win = Ext.create('PVE.qemu.USBEdit', {
616 url: '/api2/extjs/' + baseurl,
617 pveSelNode: me.pveSelNode
618 });
619 win.on('destroy', reload);
620 win.show();
621 }
b38d0810 622 },
25a1063a
DC
623 {
624 text: gettext('PCI Device'),
625 itemId: 'addpci',
626 iconCls: 'pve-itype-icon-pci',
627 disabled: !caps.nodes['Sys.Console'],
628 handler: function() {
629 var win = Ext.create('PVE.qemu.PCIEdit', {
630 url: '/api2/extjs/' + baseurl,
631 pveSelNode: me.pveSelNode
632 });
633 win.on('destroy', reload);
634 win.show();
635 }
636 },
37977fa5
TL
637 {
638 text: gettext('Serial Port'),
639 itemId: 'addserial',
640 iconCls: 'pve-itype-icon-serial',
641 disabled: !caps.vms['VM.Config.Options'],
642 handler: function() {
643 var win = Ext.create('PVE.qemu.SerialEdit', {
644 url: '/api2/extjs/' + baseurl
645 });
646 win.on('destroy', reload);
647 win.show();
648 }
649 },
b38d0810
DC
650 {
651 text: gettext('CloudInit Drive'),
652 itemId: 'addci',
653 iconCls: 'pve-itype-icon-cloud',
654 disabled: !caps.nodes['Sys.Console'],
655 handler: function() {
656 var win = Ext.create('PVE.qemu.CIDriveEdit', {
657 url: '/api2/extjs/' + baseurl,
658 pveSelNode: me.pveSelNode
659 });
660 win.on('destroy', reload);
661 win.show();
662 }
2668ba64 663 }
f97670f5
DM
664 ]
665 })
fa522e48 666 },
f97670f5
DM
667 remove_btn,
668 edit_btn,
669 resize_btn,
670 move_btn,
f97670f5
DM
671 revert_btn
672 ],
673 rows: rows,
674 sorterFn: sorterFn,
675 listeners: {
676 itemdblclick: run_editor,
677 selectionchange: set_button_status
678 }
679 });
680
681 me.callParent();
682
f09dd6c1 683 me.on('activate', me.rstore.startUpdate);
f97670f5
DM
684 me.on('destroy', me.rstore.stopUpdate);
685
f09dd6c1 686 me.mon(me.rstore, 'refresh', function() {
f97670f5
DM
687 set_button_status();
688 });
689 }
690});