Initial
[qwikioffice:qwikioffice.git] / public / client / Desktop.js
1 /*\r
2  * qWikiOffice Desktop 1.0\r
3  * Copyright(c) 2007-2010, Murdock Technologies, Inc.\r
4  * licensing@qwikioffice.com\r
5  * \r
6  * http://www.qwikioffice.com/license\r
7  */\r
8 \r
9 Ext.Desktop = Ext.extend(Ext.util.Observable, {\r
10    /**\r
11     * @cfg. {Ext.app.App}\r
12     */\r
13    app: null,\r
14    /**\r
15     * @cfg {Object}\r
16     * Example:\r
17     * {\r
18     *    "fontColor": "FFFFFF",\r
19     *    "theme": {"id": 1,"name": "Blue","file": "resources/css/xtheme-blue.css"},\r
20     *    "taskbarTransparency": "100"\r
21     * }\r
22     */\r
23    appearance: null,\r
24    /**\r
25     * @cfg {Object}\r
26     * Example:\r
27     * {\r
28     *    "color": "f9f9f9",\r
29     *    "wallpaper": {"id": 3,"name": "Blue Swirl","file": "resources/wallpapers/blue-swirl.jpg"},\r
30     *    "wallpaperPosition": "tile"\r
31     * }\r
32     */\r
33    background: null,\r
34    /**\r
35     * @cfg {Object} The launchers object.\r
36     * Contains the moduleId's of the modules to add to each launcher.\r
37     */\r
38    launchers: {\r
39       autorun: [],\r
40       quickstart: [],\r
41       shortcut: []\r
42    },\r
43    /**\r
44     * @cfg {Object} The logout button config.\r
45     */\r
46    logoutConfig: {\r
47       handler: function(){window.location = "logout.php";},\r
48       iconCls: 'icon-logout',\r
49       text: 'Logout'\r
50    },\r
51    /**\r
52     * @cfg {Function} Function that handles sorting of the Start Menu.  Return true to swap a and b.\r
53     * Examples:\r
54     * function(a, b){ // Sort in ASC alphabetical order\r
55     *    if( b.text < a.text ){\r
56             return true;\r
57     *    }\r
58     *    return false;\r
59     * }\r
60     * function(a, b){ // Sort in ASC alphabetical order with menus at the bottom\r
61     *    if( (b.text < a.text) && !b.menu ){\r
62     *       return true;\r
63     *    }\r
64     *    return false;\r
65     * }\r
66     */\r
67    startMenuSortFn: function(a, b){ // Sort in ASC alphabetical order with menus at the top\r
68       if( ( ( b.menu && a.menu ) && ( b.text < a.text ) ) || ( b.menu && !a.menu ) || ( (b.text < a.text) && !a.menu ) ){\r
69          return true;\r
70       }\r
71       return false;\r
72    },\r
73    /**\r
74     * Read only.\r
75     * @type {Ext.Window}\r
76     */\r
77    activeWindow: null,\r
78    /**\r
79     * Read only.\r
80     * @type {Ext.menu.Menu}\r
81     */\r
82    contextMenu: null,\r
83    /**\r
84     * Read only.\r
85     * @type {Ext.ux.Shortcuts}\r
86     */\r
87    shortcuts: null,\r
88    /**\r
89     * Read only.\r
90     * @type {Ext.ux.Taskbar}\r
91     */\r
92    taskbar: null,\r
93    /**\r
94     * Read only.\r
95     * @type {Ext.WindowGroup}\r
96     */\r
97    windows: new Ext.WindowGroup(),\r
98    /**\r
99     * Read only.\r
100     * @type {Number}\r
101     */\r
102    xTickSize: 1,\r
103    /**\r
104     * Read only.\r
105     * @type {Number}\r
106     */\r
107    yTickSize: 1,\r
108 \r
109    /**\r
110     * @param {Object} config.\r
111     */\r
112    constructor : function(config){\r
113       this.app = config.app;\r
114 \r
115       this.addEvents({\r
116          winactivate: true,\r
117          winbeforeclose: true,\r
118          windeactivate: true\r
119       });\r
120 \r
121       if(config.appearance){\r
122          this.appearance = config.appearance;\r
123       }\r
124       if(config.background){\r
125          this.background = config.background;\r
126       }\r
127       if(config.launchers){\r
128          Ext.apply(this.launchers, config.launchers);\r
129       }\r
130       if(config.logoutConfig){\r
131          this.logoutConfig = config.logoutConfig;\r
132       }\r
133       if(config.startMenuSortFn){\r
134          this.startMenuSortFn = config.startMenuSortFn;\r
135       }\r
136 \r
137       var taskbarConfig = config.taskbarConfig || {};\r
138       if(taskbarConfig.position === 'top'){\r
139          this.taskbar = new Ext.ux.TaskBar(taskbarConfig);\r
140          this.el = Ext.getBody().createChild({tag: 'div', cls: 'x-desktop'});\r
141       }else{\r
142          this.el = Ext.getBody().createChild({tag: 'div', cls: 'x-desktop'});\r
143          this.taskbar = new Ext.ux.TaskBar(taskbarConfig);\r
144       }\r
145       this.taskbar.desktop = this;\r
146 \r
147       this.contextMenu = new Ext.menu.Menu({\r
148          items: [\r
149             {\r
150                text: 'Close All',\r
151                handler: this.closeWindows,\r
152                scope: this\r
153             },\r
154             '-',\r
155             {\r
156                text: 'Minimize All',\r
157                handler: this.minimizeWindows,\r
158                scope: this\r
159             },\r
160             '-',\r
161             {\r
162                text: 'Tile',\r
163                handler: this.tileWindows,\r
164                scope: this\r
165             },\r
166             {\r
167                text: 'Cascade',\r
168                handler: this.cascadeWindows,\r
169                scope: this\r
170             },\r
171             {\r
172                text: 'Checkerboard',\r
173                handler: this.checkerboardWindows,\r
174                scope: this\r
175             },\r
176             {\r
177                text: 'Snap Fit',\r
178                handler: this.snapFitWindows,\r
179                scope: this\r
180             },\r
181             {\r
182                text: 'Snap Fit Vertical',\r
183                handler: this.snapFitVWindows,\r
184                scope: this\r
185             },\r
186             '-'\r
187          ]\r
188       });\r
189 \r
190       this.shortcuts = new Ext.ux.Shortcuts(this);\r
191 \r
192       // todo: fix bug where Ext.Msg are not displayed properly\r
193       this.windows.zseed = 7000; //10000;\r
194 \r
195       Ext.Desktop.superclass.constructor.call(this);\r
196 \r
197       this.initEvents();\r
198       this.initAppearance();\r
199       this.initBackground();\r
200       this.initModules();\r
201       this.initLaunchers();\r
202       this.initLogout();\r
203       this.layout();\r
204    },\r
205 \r
206    initEvents : function(){\r
207       Ext.EventManager.onWindowResize(this.layout, this);\r
208 \r
209       this.el.on('contextmenu', function(e){\r
210          if(e.target.id === this.el.id){\r
211             e.stopEvent();\r
212             if(!this.contextMenu.el){\r
213                this.contextMenu.render();\r
214             }\r
215             this.contextMenu.showAt(e.getXY());\r
216          }\r
217       }, this);\r
218    },\r
219 \r
220    initModules : function(){\r
221       var ms = this.app.modules;\r
222       if(!ms){\r
223          return false;\r
224       }\r
225 \r
226       for(var i = 0, len = ms.length; i < len; i++){\r
227          if(ms[i].launcher){\r
228             ms[i].launcher.handler = this.launchWindow.createDelegate(this, [ms[i].id]);\r
229          }\r
230          ms[i].loaded = false;\r
231       }\r
232 \r
233       return true;\r
234    },\r
235 \r
236    initLaunchers : function(){\r
237       this.initStartMenu();\r
238       this.initContextMenu();\r
239       this.initQuickStart();\r
240       this.initShortcut();\r
241       this.initAutoRun();\r
242    },\r
243 \r
244    initStartMenu : function(){\r
245       var menu = this.taskbar.startButton.menu;\r
246       var config = this.buildStartItemConfig() || {};\r
247       if(config.items){\r
248          menu.add(config.items);\r
249       }\r
250       if(config.toolItems){\r
251          // todo: update startmenu to accept array of tool items\r
252          menu.addTool.apply(menu, config.toolItems);\r
253       }\r
254    },\r
255 \r
256    initAutoRun : function(){\r
257       var mIds = this.launchers.autorun;\r
258       if(mIds && mIds.length > 0){\r
259          this.app.onReady(function(){\r
260             for(var i = 0, len = mIds.length; i < len; i++){\r
261                var m = this.app.getModule(mIds[i]);\r
262                if(m){\r
263                   m.autorun = true;\r
264                   this.launchWindow(mIds[i]);\r
265                }\r
266             }\r
267          }, this);\r
268       }\r
269    },\r
270 \r
271    initShortcut : function(){\r
272       var mIds = this.launchers.shortcut;\r
273       if(mIds){\r
274          for(var i = 0, len = mIds.length; i < len; i++){\r
275             this.addShortcut(mIds[i], false);\r
276          }\r
277       }\r
278    },\r
279 \r
280    initQuickStart : function(){\r
281       var mIds = this.launchers.quickstart;\r
282       if(mIds){\r
283          for(var i = 0, len = mIds.length; i < len; i++){\r
284             this.addQuickStartButton(mIds[i], false);\r
285          }\r
286       }\r
287    },\r
288 \r
289    initContextMenu : function(){\r
290       var ms = this.app.modules;\r
291       if(ms){\r
292          for(var i = 0, len = ms.length; i < len; i++){\r
293             if(ms[i].launcherPaths && ms[i].launcherPaths.contextmenu){\r
294                this.addContextMenuItem(ms[i].id);\r
295             }\r
296          }\r
297       }\r
298    },\r
299 \r
300    initLogout : function(){\r
301       if(this.logoutConfig){\r
302          this.taskbar.startButton.menu.addTool(this.logoutConfig);\r
303       }\r
304    },\r
305 \r
306    /**\r
307     * Provides the handler to the module launcher.\r
308     * Requests the module, which will load the module if needed.\r
309     * Passes in the callback and scope as params.\r
310     * @param {string} id\r
311     */\r
312    launchWindow : function(id){\r
313       var m = this.app.requestModule(id, function(m){\r
314          if(m){m.createWindow();}\r
315       }, this);\r
316    },\r
317 \r
318    /**\r
319     * @param {object} config The window config object.\r
320     * @param {string} cls The class to use instead of Ext.Window.\r
321     */\r
322    createWindow : function(config, cls){\r
323       var win = new (cls||Ext.Window)(\r
324          Ext.applyIf(config||{}, {\r
325             manager: this.windows,\r
326             minimizable: true,\r
327             maximizable: true,\r
328             shadow: 'frame'\r
329          })\r
330       );\r
331 \r
332       win.render(this.el);\r
333       win.taskButton = this.taskbar.addTaskButton(win);\r
334       /*win.cmenu = new Ext.menu.Menu({\r
335          items: [\r
336 \r
337          ]\r
338       });*/\r
339       win.animateTarget = win.taskButton.el;\r
340 \r
341       win.on({\r
342                 'activate': {\r
343                         fn: function(win){\r
344                                 this.markActive(win);\r
345                                 this.fireEvent('winactivate', this, win);\r
346                         }\r
347                         , scope: this\r
348                 },\r
349                 'beforeclose': {\r
350                         fn: function(win){\r
351                                 this.fireEvent('winbeforeclose', this, win);\r
352                         },\r
353                         scope: this\r
354                 },\r
355                 'beforeshow': {\r
356                         fn: this.markActive\r
357                         , scope: this\r
358                 },\r
359                 'deactivate': {\r
360                         fn: function(win){\r
361                                 this.markInactive(win);\r
362                                 this.fireEvent('windeactivate', this, win);\r
363                         }\r
364                         , scope: this\r
365                 },\r
366                 'minimize': {\r
367                         fn: this.minimizeWin\r
368                         , scope: this\r
369                 },\r
370                 'close': {\r
371                         fn: this.removeWin\r
372                         , scope: this\r
373          }\r
374       });\r
375 \r
376       this.layout();\r
377       return win;\r
378    },\r
379 \r
380    /**\r
381     * @param {Ext.Window} win The window to minimize.\r
382     */\r
383    minimizeWin : function(win){\r
384       win.minimized = true;\r
385       win.hide();\r
386    },\r
387 \r
388    /**\r
389     * @param {Ext.Window} win The window to mark active.\r
390     */\r
391    markActive : function(win){\r
392       if(this.activeWindow && this.activeWindow != win){\r
393          this.markInactive(this.activeWindow);\r
394       }\r
395       this.taskbar.setActiveButton(win.taskButton);\r
396       this.activeWindow = win;\r
397       Ext.fly(win.taskButton.el).addClass('active-win');\r
398       win.minimized = false;\r
399    },\r
400 \r
401    /**\r
402     * @param {Ext.Window} win The window to mark inactive.\r
403     */\r
404    markInactive : function(win){\r
405       if(win == this.activeWindow){\r
406          this.activeWindow = null;\r
407          Ext.fly(win.taskButton.el).removeClass('active-win');\r
408       }\r
409    },\r
410 \r
411    /**\r
412     * @param {Ext.Window} win The window to remove.\r
413     */\r
414    removeWin : function(win){\r
415       this.taskbar.removeTaskButton(win.taskButton);\r
416       this.layout();\r
417    },\r
418 \r
419    layout : function(){\r
420       this.el.setHeight(Ext.lib.Dom.getViewHeight() - this.getTaskbarHeight());\r
421    },\r
422 \r
423    getManager : function(){\r
424       return this.windows;\r
425    },\r
426 \r
427    /**\r
428     * @param {string} id The window id.\r
429     */\r
430    getWindow : function(id){\r
431       return this.windows.get(id);\r
432    },\r
433 \r
434    /**\r
435     * @param {String} key The launcher key.  Options are: 'autorun', 'quickstart' and 'shortcut'.\r
436     */\r
437    getLauncher : function(key){\r
438       return this.launchers[key];\r
439    },\r
440 \r
441    /**\r
442     * @param {String} key The launcher key.  Options are: 'autorun', 'quickstart' and 'shortcut'.\r
443     * @param {String} id The module id to add.\r
444     */\r
445    addToLauncher : function(key, id){\r
446       var c = this.getLauncher(key);\r
447       if(c){\r
448          c.push(id);\r
449       }\r
450    },\r
451 \r
452    /**\r
453     * @param {String} key The launcher key.  Options are: 'autorun', 'quickstart' and 'shortcut'.\r
454     * @param {String} id The module id to remove.\r
455     */\r
456    removeFromLauncher : function(key, id){\r
457       var c = this.getLauncher(key);\r
458       if(c){\r
459          var i = 0;\r
460          while(i < c.length){\r
461             if(c[i] == id){\r
462                c.splice(i, 1);\r
463             }else{\r
464                i++;\r
465             }\r
466          }\r
467       }\r
468    },\r
469 \r
470    getTaskbarPosition : function(){\r
471       return this.taskbar.position;\r
472    },\r
473 \r
474    getTaskbarHeight : function(){\r
475       return this.taskbar.isVisible() ? this.taskbar.getHeight() : 0;\r
476    },\r
477 \r
478    getViewHeight : function(){\r
479       return (Ext.lib.Dom.getViewHeight() - this.getTaskbarHeight());\r
480    },\r
481 \r
482    getViewWidth : function(){\r
483       return Ext.lib.Dom.getViewWidth();\r
484    },\r
485 \r
486    getWinWidth : function(){\r
487       var width = this.getViewWidth();\r
488       return width < 200 ? 200 : width;\r
489    },\r
490 \r
491    getWinHeight : function(){\r
492       var height = this.getViewHeight();\r
493       return height < 100 ? 100 : height;\r
494    },\r
495 \r
496    /**\r
497     * @param {integer} width The width.\r
498     */\r
499    getWinX : function(width){\r
500       return (Ext.lib.Dom.getViewWidth() - width) / 2\r
501    },\r
502 \r
503    /**\r
504     * @param {integer} height The height.\r
505     */\r
506    getWinY : function(height){\r
507       return (Ext.lib.Dom.getViewHeight() - this.getTaskbarHeight() - height) / 2;\r
508    },\r
509 \r
510    setTickSize : function(xTickSize, yTickSize){\r
511       this.xTickSize = xTickSize;\r
512       if (arguments.length == 1){\r
513          this.yTickSize = xTickSize;\r
514       }else{\r
515          this.yTickSize = yTickSize;\r
516       }\r
517       this.windows.each(function(win) {\r
518          win.dd.xTickSize = this.xTickSize;\r
519          win.dd.yTickSize = this.yTickSize;\r
520          win.resizer.widthIncrement = this.xTickSize;\r
521          win.resizer.heightIncrement = this.yTickSize;\r
522       }, this);\r
523    },\r
524 \r
525    cascadeWindows : function(){\r
526       var x = 0, y = 0;\r
527       this.windows.each(function(win) {\r
528          if(win.isVisible() && !win.maximized){\r
529             win.setPosition(x, y);\r
530             win.toFront();\r
531             x += 20;\r
532             y += 20;\r
533          }\r
534       }, this);\r
535    },\r
536 \r
537    tileWindows : function(){\r
538       var availWidth = this.el.getWidth(true);\r
539       var x = this.xTickSize;\r
540       var y = this.yTickSize;\r
541       var nextY = y;\r
542       this.windows.each(function(win) {\r
543          if(win.isVisible() && !win.maximized){\r
544             var w = win.el.getWidth();\r
545             // Wrap to next row if we are not at the line start and this Window will go off the end\r
546             if((x > this.xTickSize) && (x + w > availWidth)){\r
547                x = this.xTickSize;\r
548                y = nextY;\r
549             }\r
550 \r
551             win.setPosition(x, y);\r
552             x += w + this.xTickSize;\r
553             nextY = Math.max(nextY, y + win.el.getHeight() + this.yTickSize);\r
554          }\r
555       }, this);\r
556    },\r
557 \r
558    closeWindows : function() {\r
559       this.windows.each(function(win) {\r
560          win.close();\r
561       }, this);\r
562    },\r
563 \r
564    minimizeWindows : function() {\r
565       this.windows.each(function(win) {\r
566          this.minimizeWin(win);\r
567       }, this);\r
568    },\r
569 \r
570    checkerboardWindows : function() {\r
571       var availWidth = this.el.getWidth(true);\r
572       var availHeight = this.el.getHeight(true);\r
573 \r
574       var x = 0, y = 0;\r
575       var lastx = 0, lasty = 0;\r
576 \r
577       // square size should be a value set user?\r
578       var square = 400;\r
579 \r
580       this.windows.each(function(win) {\r
581          // if (win.isVisible() && !win.maximized) {\r
582          if (win.isVisible()) {\r
583             // Subtract padding, should be a value set user?\r
584             win.setWidth(square - 10);\r
585             win.setHeight(square - 10);\r
586 \r
587             win.setPosition(x, y);\r
588             x += square;\r
589 \r
590             if (x + square > availWidth) {\r
591                x = lastx;\r
592                y += square;\r
593 \r
594                if (y > availHeight) {\r
595                   lastx += 20;\r
596                   lasty += 20;\r
597                   x = lastx;\r
598                   y = lasty;\r
599                }\r
600             }\r
601          }\r
602       }, this);\r
603    },\r
604 \r
605    snapFitWindows : function() {\r
606       var availWidth = this.el.getWidth(true);\r
607       var availHeight = this.el.getHeight(true);\r
608 \r
609       var x = 0, y = 0;\r
610 \r
611       // How to get number of windows?\r
612       // var snapCount = windows.length;\r
613       var snapCount = 0;\r
614 \r
615       this.windows.each(function(win) {\r
616          if (win.isVisible()) {\r
617             snapCount++;\r
618          }\r
619       }, this);\r
620       // above loop seems unnecessary?\r
621 \r
622       var snapSize = parseInt(availWidth / snapCount);\r
623 \r
624       if (snapSize > 0) {\r
625          this.windows.each(function(win) {\r
626             if (win.isVisible()) {\r
627                // Subtract 10 for padding?\r
628                win.setWidth(snapSize);\r
629                win.setHeight(availHeight);\r
630 \r
631                win.setPosition(x, y);\r
632                x += snapSize;\r
633             }\r
634          }, this);\r
635       }\r
636    },\r
637 \r
638    snapFitVWindows : function(){\r
639       var availWidth = this.el.getWidth(true);\r
640       var availHeight = this.el.getHeight(true);\r
641 \r
642       var x = 0, y = 0;\r
643 \r
644       // How to get number of windows?\r
645       // var snapCount = windows.length;\r
646       var snapCount = 0;\r
647 \r
648       this.windows.each(function(win) {\r
649          if (win.isVisible()) {\r
650             snapCount++;\r
651          }\r
652       }, this);\r
653       // above loop seems unnecessary?\r
654 \r
655       var snapSize = parseInt(availHeight / snapCount);\r
656 \r
657       if (snapSize > 0) {\r
658          this.windows.each(function(win) {\r
659             if (win.isVisible()) {\r
660                // Subtract 10 for padding?\r
661                win.setWidth(availWidth);\r
662                win.setHeight(snapSize);\r
663 \r
664                win.setPosition(x, y);\r
665                y += snapSize;\r
666             }\r
667          }, this);\r
668       }\r
669    },\r
670 \r
671    initAppearance : function(){\r
672         var a = this.appearance;\r
673         if(a){\r
674          this.setFontColor(a.fontColor);\r
675          this.setTheme(a.theme);\r
676          this.setTaskbarTransparency(a.taskbarTransparency);\r
677       }\r
678    },\r
679 \r
680    getAppearance : function(){\r
681       return this.appearance;\r
682    },\r
683 \r
684    initBackground : function(){\r
685       var b = this.background;\r
686       if(b){\r
687          this.setBackgroundColor(b.color);\r
688          this.setWallpaperPosition(b.wallpaperPosition);\r
689          this.setWallpaper(b.wallpaper);\r
690       }\r
691    },\r
692 \r
693    getBackground : function(){\r
694       return this.background;\r
695    },\r
696 \r
697    /**\r
698     * @param {string} hex The hexidecimal number for the color.\r
699     */\r
700    setBackgroundColor : function(hex){\r
701       if(hex){\r
702          Ext.getBody().setStyle('background-color', '#'+hex);\r
703          this.background.backgroundcolor = hex;\r
704       }\r
705    },\r
706 \r
707    /**\r
708     * @param {string} hex The hexidecimal number for the color.\r
709     */\r
710    setFontColor : function(hex){\r
711       if(hex){\r
712          //Ext.util.CSS.updateRule('.ux-shortcut-btn-text', 'color', '#'+hex);\r
713          this.shortcuts.setFontColor(hex);\r
714          this.appearance.fontColor = hex;\r
715       }\r
716    },\r
717 \r
718    /**\r
719     * @param {object} o The data for the theme.\r
720     * Example:\r
721     * {\r
722     *    id: 1,\r
723     *    name: 'Vista Black',\r
724     *    file: 'path/to/file'\r
725     * }\r
726     */\r
727    setTheme : function(o){\r
728       if(o && o.id && o.name && o.file){\r
729          Ext.util.CSS.swapStyleSheet('theme', o.file);\r
730          this.appearance.theme = o;\r
731       }\r
732    },\r
733 \r
734    /**\r
735     * @param {integer} v The value.  An integer from 0 to 100.\r
736     */\r
737    setTaskbarTransparency : function(v){\r
738       if(v >= 0 && v <= 100){\r
739          this.taskbar.el.addClass("transparent");\r
740          Ext.util.CSS.updateRule('.transparent','opacity', v/100);\r
741          Ext.util.CSS.updateRule('.transparent','-moz-opacity', v/100);\r
742          Ext.util.CSS.updateRule('.transparent','filter', 'alpha(opacity='+v+')');\r
743 \r
744          this.appearance.taskbarTransparency = v;\r
745       }\r
746    },\r
747 \r
748    getWallpaper : function(){\r
749       return this.background.wallpaper;\r
750    },\r
751 \r
752    /**\r
753     * @param {object} o The data for the wallpaper.\r
754     * Example:\r
755     * {\r
756     *    id: 1,\r
757     *    name: 'Blank',\r
758     *    file: 'path/to/file'\r
759     * }\r
760     */\r
761    setWallpaper : function(o){\r
762       if(o && o.id && o.name && o.file){\r
763 \r
764          var notifyWin = this.showNotification({\r
765             html: 'Loading wallpaper...',\r
766             title: 'Please wait'\r
767          });\r
768 \r
769          var wp = new Image();\r
770          wp.src = o.file;\r
771 \r
772          var task = new Ext.util.DelayedTask(verify, this);\r
773          task.delay(200);\r
774 \r
775          this.background.wallpaper = o;\r
776       }\r
777 \r
778       function verify(){\r
779          if(wp.complete){\r
780             task.cancel();\r
781 \r
782             notifyWin.setIconClass('icon-done');\r
783             notifyWin.setTitle('Finished');\r
784             notifyWin.setMessage('Wallpaper loaded.');\r
785             this.hideNotification(notifyWin);\r
786 \r
787             document.body.background = wp.src;\r
788          }else{\r
789             task.delay(200);\r
790          }\r
791       }\r
792    },\r
793 \r
794    /**\r
795     * @param {string} pos Options are 'tile' or 'center'.\r
796     */\r
797    setWallpaperPosition : function(pos){\r
798       if(pos){\r
799          var b = Ext.getBody();\r
800          if(pos === "center"){\r
801             b.removeClass('wallpaper-tile');\r
802             b.addClass('wallpaper-center');\r
803          }else if(pos === "tile"){\r
804             b.removeClass('wallpaper-center');\r
805             b.addClass('wallpaper-tile');\r
806          }\r
807          this.background.wallpaperPosition = pos;\r
808       }\r
809    },\r
810 \r
811    /**\r
812     * @param {object} config The config object.\r
813     */\r
814    showNotification : function(config){\r
815       var win = new Ext.ux.Notification(Ext.apply({\r
816          animateTarget: this.taskbar.el,\r
817          animateFrom: this.getTaskbarPosition(),\r
818          autoDestroy: true,\r
819          hideDelay: 5000,\r
820          html: '',\r
821          iconCls: 'icon-waiting',\r
822          title: ''\r
823       }, config));\r
824       win.show();\r
825 \r
826       return win;\r
827    },\r
828 \r
829    /**\r
830     * @param {Ext.ux.Notification} win The notification window.\r
831     * @param {integer} delay The delay time in milliseconds.\r
832     */\r
833    hideNotification : function(win, delay){\r
834       if(win){\r
835          (function(){win.animHide();}).defer(delay || 3000);\r
836       }\r
837    },\r
838 \r
839    /**\r
840     * @param {string} id The id of the module to add.\r
841     */\r
842    addAutoRun : function(id){\r
843       var m = this.app.getModule(id);\r
844       var c = this.getLauncher('autorun');\r
845                         \r
846       if(c && m && !m.autorun){\r
847          m.autorun = true;\r
848          c.push(id);\r
849       }\r
850    },\r
851 \r
852    /**\r
853     * @param {string} id The id of the module to remove.\r
854     */\r
855    removeAutoRun : function(id){\r
856       var m = this.app.getModule(id);\r
857       var c = this.getLauncher('autorun');\r
858 \r
859       if(c && m && m.autorun){\r
860          var i = 0;\r
861 \r
862          while(i < c.length){\r
863             if(c[i] == id){\r
864                c.splice(i, 1);\r
865             }else{\r
866                i++;\r
867             }\r
868          }\r
869 \r
870          m.autorun = null;\r
871       }\r
872    },\r
873 \r
874    /**\r
875     * @param {string} id The id of the module to add.\r
876     */\r
877    addContextMenuItem : function(id){\r
878       var m = this.app.getModule(id);\r
879 \r
880       if(m && !m.contextMenuItem && m.launcher){\r
881          var c = m.launcher;\r
882 \r
883          this.contextMenu.add({\r
884             handler: this.launchWindow.createDelegate(this, [id]),\r
885             iconCls: c.iconCls,\r
886             text: c.text,\r
887             tooltip: c.tooltip || ''\r
888          });\r
889       }\r
890    },\r
891 \r
892    /**\r
893     * @param {string} id The module id\r
894     * @param {boolean} updateConfig \r
895     */\r
896    addShortcut : function(id, updateConfig){\r
897       var m = this.app.getModule(id);\r
898 \r
899       if(m && !m.shortcut){\r
900          var c = m.launcher;\r
901 \r
902          m.shortcut = this.shortcuts.addShortcut({\r
903             handler: this.launchWindow.createDelegate(this, [id]),\r
904             iconCls: c.shortcutIconCls,\r
905             text: c.text,\r
906             tooltip: c.tooltip || ''\r
907          });\r
908 \r
909          if(updateConfig){\r
910             this.addToLauncher('shortcut', id);\r
911          }\r
912       }\r
913    },\r
914 \r
915    /**\r
916     * @param {string} id The module id\r
917     * @param {boolean} updateConfig\r
918     */\r
919    removeShortcut : function(id, updateConfig){\r
920       var m = this.app.getModule(id);\r
921 \r
922       if(m && m.shortcut){\r
923          this.shortcuts.removeShortcut(m.shortcut);\r
924          m.shortcut = null;\r
925 \r
926          if(updateConfig){\r
927             this.removeFromLauncher('shortcut', id);\r
928          }\r
929       }\r
930    },\r
931 \r
932    /**\r
933     * @param {string} id The module id\r
934     * @param {boolean} updateConfig\r
935     */\r
936    addQuickStartButton : function(id, updateConfig){\r
937         var m = this.app.getModule(id);\r
938 \r
939       if(m && !m.quickStartButton){\r
940          var c = m.launcher;\r
941 \r
942          m.quickStartButton = this.taskbar.addQuickStartButton({\r
943             handler: this.launchWindow.createDelegate(this, [id]),\r
944             iconCls: c.iconCls,\r
945             scope: c.scope,\r
946             text: c.text,\r
947             tooltip: c.tooltip || c.text\r
948          });\r
949 \r
950          if(updateConfig){\r
951             this.addToLauncher('quickstart', id);\r
952          }\r
953       }\r
954    },\r
955 \r
956    /**\r
957     * @param {string} id The module id\r
958     * @param {boolean} updateConfig\r
959     */\r
960    removeQuickStartButton : function(id, updateConfig){\r
961       var m = this.app.getModule(id);\r
962 \r
963       if(m && m.quickStartButton){\r
964          this.taskbar.removeQuickStartButton(m.quickStartButton);\r
965          m.quickStartButton = null;\r
966 \r
967          if(updateConfig){\r
968             this.removeFromLauncher('quickstart', id);\r
969          }\r
970       }\r
971    },\r
972 \r
973    /**\r
974          * Returns the Start Menu items and toolItems configs\r
975          */\r
976         buildStartItemConfig : function(){\r
977                 var ms = this.app.modules;\r
978                 var sortFn = this.startMenuSortFn;\r
979 \r
980         if(ms){\r
981          var launcherPaths;\r
982                 var paths;\r
983                 var sm = {menu: {items: []}}; // Start Menu\r
984                 var smi = sm.menu.items;\r
985 \r
986                 smi.push({text: 'startmenu', menu: {items: []}});\r
987                 smi.push({text: 'startmenutool', menu: {items: []}});\r
988 \r
989                         for(var i = 0, iLen = ms.length; i < iLen; i++){ // loop through the modules\r
990             if(ms[i].launcherPaths){\r
991                launcherPaths = ms[i].launcherPaths;\r
992 \r
993                for(var id in launcherPaths){ // loop through the module's launcher paths\r
994                   paths = launcherPaths[id].split('/');\r
995 \r
996                   if(paths.length > 0){\r
997                      if(id === 'startmenu'){\r
998                         simplify(smi[0].menu, paths, ms[i].launcher);\r
999                         sort(smi[0].menu);\r
1000                      }else if(id === 'startmenutool'){\r
1001                         simplify(smi[1].menu, paths, ms[i].launcher);\r
1002                         sort(smi[1].menu);\r
1003                      }\r
1004                   }\r
1005                }\r
1006                                 }\r
1007                         }\r
1008 \r
1009                         return {\r
1010                                 items: smi[0].menu.items,\r
1011                                 toolItems: smi[1].menu.items\r
1012                         };\r
1013         }\r
1014 \r
1015         return null;\r
1016 \r
1017                 /**\r
1018                  * Creates nested arrays that represent the Start Menu.\r
1019                  *\r
1020                  * @param {array} pMenu The Start Menu\r
1021                  * @param {array} paths The menu texts\r
1022                  * @param {object} launcher The launcher config\r
1023                  */\r
1024                 function simplify(pMenu, paths, launcher){\r
1025                         var newMenu;\r
1026                         var foundMenu;\r
1027 \r
1028                         for(var i = 0, len = paths.length; i < len; i++){\r
1029             if(paths[i] === ''){\r
1030                continue;\r
1031             }\r
1032 \r
1033                                 foundMenu = findMenu(pMenu.items, paths[i]); // text exists?\r
1034 \r
1035                                 if(!foundMenu){\r
1036                                         newMenu = {\r
1037                                                 iconCls: 'ux-start-menu-submenu',\r
1038                                                 handler: function(){return false;},\r
1039                                                 menu: {items: []},\r
1040                                                 text: paths[i]\r
1041                                         };\r
1042                                         pMenu.items.push(newMenu);\r
1043                                         pMenu = newMenu.menu;\r
1044                                 }else{\r
1045                                         pMenu = foundMenu;\r
1046                                 }\r
1047                         }\r
1048 \r
1049                         pMenu.items.push(launcher);\r
1050                 }\r
1051 \r
1052                 /**\r
1053                  * Returns the menu if found.\r
1054                  * @param {array} pMenu The parent menu to search\r
1055                  * @param {string} text\r
1056                  */\r
1057                 function findMenu(pMenu, text){\r
1058                         for(var j = 0, jlen = pMenu.length; j < jlen; j++){\r
1059                                 if(pMenu[j].text === text){\r
1060                                         return pMenu[j].menu; // found the menu, return it\r
1061                                 }\r
1062                         }\r
1063                         return null;\r
1064                 }\r
1065 \r
1066                 /**\r
1067                  * @param {array} menu The nested array to sort\r
1068                  */\r
1069                 function sort(menu){\r
1070                         var items = menu.items;\r
1071                         for(var i = 0, ilen = items.length; i < ilen; i++){\r
1072                                 if(items[i].menu){\r
1073                                         sort(items[i].menu); // use recursion to iterate nested arrays\r
1074                                 }\r
1075                                 bubbleSort(items, 0, items.length); // sort the menu items\r
1076                         }\r
1077                 }\r
1078 \r
1079                 /**\r
1080                  * @param {array} items Menu items to sort\r
1081                  * @param {integer} start The start index\r
1082                  * @param {integer} stop The stop index\r
1083                  */\r
1084                 function bubbleSort(items, start, stop){\r
1085                         for(var i = stop - 1; i >= start;  i--){\r
1086                                 for(var j = start; j <= i; j++){\r
1087                                         if(items[j+1] && items[j]){\r
1088                                                 if(sortFn(items[j], items[j+1])){\r
1089                                                         var tempValue = items[j];\r
1090                                                         items[j] = items[j+1];\r
1091                                                         items[j+1] = tempValue;\r
1092                                                 }\r
1093 \r
1094                                         }\r
1095                                 }\r
1096                         }\r
1097                         return items;\r
1098                 }\r
1099         }\r
1100 });