]> git.proxmox.com Git - extjs.git/blame - extjs/packages/ux/classic/src/desktop/Desktop.js
add extjs 6.0.1 sources
[extjs.git] / extjs / packages / ux / classic / src / desktop / Desktop.js
CommitLineData
6527f429
DM
1/*!\r
2 * Ext JS Library\r
3 * Copyright(c) 2006-2014 Sencha Inc.\r
4 * licensing@sencha.com\r
5 * http://www.sencha.com/license\r
6 */\r
7\r
8/**\r
9 * @class Ext.ux.desktop.Desktop\r
10 * @extends Ext.panel.Panel\r
11 * <p>This class manages the wallpaper, shortcuts and taskbar.</p>\r
12 */\r
13Ext.define('Ext.ux.desktop.Desktop', {\r
14 extend: 'Ext.panel.Panel',\r
15\r
16 alias: 'widget.desktop',\r
17\r
18 uses: [\r
19 'Ext.util.MixedCollection',\r
20 'Ext.menu.Menu',\r
21 'Ext.view.View', // dataview\r
22 'Ext.window.Window',\r
23\r
24 'Ext.ux.desktop.TaskBar',\r
25 'Ext.ux.desktop.Wallpaper'\r
26 ],\r
27\r
28 activeWindowCls: 'ux-desktop-active-win',\r
29 inactiveWindowCls: 'ux-desktop-inactive-win',\r
30 lastActiveWindow: null,\r
31\r
32 border: false,\r
33 html: '&#160;',\r
34 layout: 'fit',\r
35\r
36 xTickSize: 1,\r
37 yTickSize: 1,\r
38\r
39 app: null,\r
40\r
41 /**\r
42 * @cfg {Array/Ext.data.Store} shortcuts\r
43 * The items to add to the DataView. This can be a {@link Ext.data.Store Store} or a\r
44 * simple array. Items should minimally provide the fields in the\r
45 * {@link Ext.ux.desktop.ShortcutModel Shortcut}.\r
46 */\r
47 shortcuts: null,\r
48\r
49 /**\r
50 * @cfg {String} shortcutItemSelector\r
51 * This property is passed to the DataView for the desktop to select shortcut items.\r
52 * If the {@link #shortcutTpl} is modified, this will probably need to be modified as\r
53 * well.\r
54 */\r
55 shortcutItemSelector: 'div.ux-desktop-shortcut',\r
56\r
57 /**\r
58 * @cfg {String} shortcutTpl\r
59 * This XTemplate is used to render items in the DataView. If this is changed, the\r
60 * {@link #shortcutItemSelector} will probably also need to changed.\r
61 */\r
62 shortcutTpl: [\r
63 '<tpl for=".">',\r
64 '<div class="ux-desktop-shortcut" id="{name}-shortcut">',\r
65 '<div class="ux-desktop-shortcut-icon {iconCls}">',\r
66 '<img src="',Ext.BLANK_IMAGE_URL,'" title="{name}">',\r
67 '</div>',\r
68 '<span class="ux-desktop-shortcut-text">{name}</span>',\r
69 '</div>',\r
70 '</tpl>',\r
71 '<div class="x-clear"></div>'\r
72 ],\r
73\r
74 /**\r
75 * @cfg {Object} taskbarConfig\r
76 * The config object for the TaskBar.\r
77 */\r
78 taskbarConfig: null,\r
79\r
80 windowMenu: null,\r
81\r
82 initComponent: function () {\r
83 var me = this;\r
84\r
85 me.windowMenu = new Ext.menu.Menu(me.createWindowMenu());\r
86\r
87 me.bbar = me.taskbar = new Ext.ux.desktop.TaskBar(me.taskbarConfig);\r
88 me.taskbar.windowMenu = me.windowMenu;\r
89\r
90 me.windows = new Ext.util.MixedCollection();\r
91\r
92 me.contextMenu = new Ext.menu.Menu(me.createDesktopMenu());\r
93\r
94 me.items = [\r
95 { xtype: 'wallpaper', id: me.id+'_wallpaper' },\r
96 me.createDataView()\r
97 ];\r
98\r
99 me.callParent();\r
100\r
101 me.shortcutsView = me.items.getAt(1);\r
102 me.shortcutsView.on('itemclick', me.onShortcutItemClick, me);\r
103\r
104 var wallpaper = me.wallpaper;\r
105 me.wallpaper = me.items.getAt(0);\r
106 if (wallpaper) {\r
107 me.setWallpaper(wallpaper, me.wallpaperStretch);\r
108 }\r
109 },\r
110\r
111 afterRender: function () {\r
112 var me = this;\r
113 me.callParent();\r
114 me.el.on('contextmenu', me.onDesktopMenu, me);\r
115 },\r
116\r
117 //------------------------------------------------------\r
118 // Overrideable configuration creation methods\r
119\r
120 createDataView: function () {\r
121 var me = this;\r
122 return {\r
123 xtype: 'dataview',\r
124 overItemCls: 'x-view-over',\r
125 trackOver: true,\r
126 itemSelector: me.shortcutItemSelector,\r
127 store: me.shortcuts,\r
128 style: {\r
129 position: 'absolute'\r
130 },\r
131 x: 0, y: 0,\r
132 tpl: new Ext.XTemplate(me.shortcutTpl)\r
133 };\r
134 },\r
135\r
136 createDesktopMenu: function () {\r
137 var me = this, ret = {\r
138 items: me.contextMenuItems || []\r
139 };\r
140\r
141 if (ret.items.length) {\r
142 ret.items.push('-');\r
143 }\r
144\r
145 ret.items.push(\r
146 { text: 'Tile', handler: me.tileWindows, scope: me, minWindows: 1 },\r
147 { text: 'Cascade', handler: me.cascadeWindows, scope: me, minWindows: 1 }\r
148 );\r
149\r
150 return ret;\r
151 },\r
152\r
153 createWindowMenu: function () {\r
154 var me = this;\r
155 return {\r
156 defaultAlign: 'br-tr',\r
157 items: [\r
158 { text: 'Restore', handler: me.onWindowMenuRestore, scope: me },\r
159 { text: 'Minimize', handler: me.onWindowMenuMinimize, scope: me },\r
160 { text: 'Maximize', handler: me.onWindowMenuMaximize, scope: me },\r
161 '-',\r
162 { text: 'Close', handler: me.onWindowMenuClose, scope: me }\r
163 ],\r
164 listeners: {\r
165 beforeshow: me.onWindowMenuBeforeShow,\r
166 hide: me.onWindowMenuHide,\r
167 scope: me\r
168 }\r
169 };\r
170 },\r
171\r
172 //------------------------------------------------------\r
173 // Event handler methods\r
174\r
175 onDesktopMenu: function (e) {\r
176 var me = this, menu = me.contextMenu;\r
177 e.stopEvent();\r
178 if (!menu.rendered) {\r
179 menu.on('beforeshow', me.onDesktopMenuBeforeShow, me);\r
180 }\r
181 menu.showAt(e.getXY());\r
182 menu.doConstrain();\r
183 },\r
184\r
185 onDesktopMenuBeforeShow: function (menu) {\r
186 var me = this, count = me.windows.getCount();\r
187\r
188 menu.items.each(function (item) {\r
189 var min = item.minWindows || 0;\r
190 item.setDisabled(count < min);\r
191 });\r
192 },\r
193\r
194 onShortcutItemClick: function (dataView, record) {\r
195 var me = this, module = me.app.getModule(record.data.module),\r
196 win = module && module.createWindow();\r
197\r
198 if (win) {\r
199 me.restoreWindow(win);\r
200 }\r
201 },\r
202\r
203 onWindowClose: function(win) {\r
204 var me = this;\r
205 me.windows.remove(win);\r
206 me.taskbar.removeTaskButton(win.taskButton);\r
207 me.updateActiveWindow();\r
208 },\r
209\r
210 //------------------------------------------------------\r
211 // Window context menu handlers\r
212\r
213 onWindowMenuBeforeShow: function (menu) {\r
214 var items = menu.items.items, win = menu.theWin;\r
215 items[0].setDisabled(win.maximized !== true && win.hidden !== true); // Restore\r
216 items[1].setDisabled(win.minimized === true); // Minimize\r
217 items[2].setDisabled(win.maximized === true || win.hidden === true); // Maximize\r
218 },\r
219\r
220 onWindowMenuClose: function () {\r
221 var me = this, win = me.windowMenu.theWin;\r
222\r
223 win.close();\r
224 },\r
225\r
226 onWindowMenuHide: function (menu) {\r
227 Ext.defer(function() {\r
228 menu.theWin = null;\r
229 }, 1);\r
230 },\r
231\r
232 onWindowMenuMaximize: function () {\r
233 var me = this, win = me.windowMenu.theWin;\r
234\r
235 win.maximize();\r
236 win.toFront();\r
237 },\r
238\r
239 onWindowMenuMinimize: function () {\r
240 var me = this, win = me.windowMenu.theWin;\r
241\r
242 win.minimize();\r
243 },\r
244\r
245 onWindowMenuRestore: function () {\r
246 var me = this, win = me.windowMenu.theWin;\r
247\r
248 me.restoreWindow(win);\r
249 },\r
250\r
251 //------------------------------------------------------\r
252 // Dynamic (re)configuration methods\r
253\r
254 getWallpaper: function () {\r
255 return this.wallpaper.wallpaper;\r
256 },\r
257\r
258 setTickSize: function(xTickSize, yTickSize) {\r
259 var me = this,\r
260 xt = me.xTickSize = xTickSize,\r
261 yt = me.yTickSize = (arguments.length > 1) ? yTickSize : xt;\r
262\r
263 me.windows.each(function(win) {\r
264 var dd = win.dd, resizer = win.resizer;\r
265 dd.xTickSize = xt;\r
266 dd.yTickSize = yt;\r
267 resizer.widthIncrement = xt;\r
268 resizer.heightIncrement = yt;\r
269 });\r
270 },\r
271\r
272 setWallpaper: function (wallpaper, stretch) {\r
273 this.wallpaper.setWallpaper(wallpaper, stretch);\r
274 return this;\r
275 },\r
276\r
277 //------------------------------------------------------\r
278 // Window management methods\r
279\r
280 cascadeWindows: function() {\r
281 var x = 0, y = 0,\r
282 zmgr = this.getDesktopZIndexManager();\r
283\r
284 zmgr.eachBottomUp(function(win) {\r
285 if (win.isWindow && win.isVisible() && !win.maximized) {\r
286 win.setPosition(x, y);\r
287 x += 20;\r
288 y += 20;\r
289 }\r
290 });\r
291 },\r
292\r
293 createWindow: function(config, cls) {\r
294 var me = this, win, cfg = Ext.applyIf(config || {}, {\r
295 stateful: false,\r
296 isWindow: true,\r
297 constrainHeader: true,\r
298 minimizable: true,\r
299 maximizable: true\r
300 });\r
301\r
302 cls = cls || Ext.window.Window;\r
303 win = me.add(new cls(cfg));\r
304\r
305 me.windows.add(win);\r
306\r
307 win.taskButton = me.taskbar.addTaskButton(win);\r
308 win.animateTarget = win.taskButton.el;\r
309\r
310 win.on({\r
311 activate: me.updateActiveWindow,\r
312 beforeshow: me.updateActiveWindow,\r
313 deactivate: me.updateActiveWindow,\r
314 minimize: me.minimizeWindow,\r
315 destroy: me.onWindowClose,\r
316 scope: me\r
317 });\r
318\r
319 win.on({\r
320 boxready: function () {\r
321 win.dd.xTickSize = me.xTickSize;\r
322 win.dd.yTickSize = me.yTickSize;\r
323\r
324 if (win.resizer) {\r
325 win.resizer.widthIncrement = me.xTickSize;\r
326 win.resizer.heightIncrement = me.yTickSize;\r
327 }\r
328 },\r
329 single: true\r
330 });\r
331\r
332 // replace normal window close w/fadeOut animation:\r
333 win.doClose = function () {\r
334 win.doClose = Ext.emptyFn; // dblclick can call again...\r
335 win.el.disableShadow();\r
336 win.el.fadeOut({\r
337 listeners: {\r
338 afteranimate: function () {\r
339 win.destroy();\r
340 }\r
341 }\r
342 });\r
343 };\r
344\r
345 return win;\r
346 },\r
347\r
348 getActiveWindow: function () {\r
349 var win = null,\r
350 zmgr = this.getDesktopZIndexManager();\r
351\r
352 if (zmgr) {\r
353 // We cannot rely on activate/deactive because that fires against non-Window\r
354 // components in the stack.\r
355\r
356 zmgr.eachTopDown(function (comp) {\r
357 if (comp.isWindow && !comp.hidden) {\r
358 win = comp;\r
359 return false;\r
360 }\r
361 return true;\r
362 });\r
363 }\r
364\r
365 return win;\r
366 },\r
367\r
368 getDesktopZIndexManager: function () {\r
369 var windows = this.windows;\r
370 // TODO - there has to be a better way to get this...\r
371 return (windows.getCount() && windows.getAt(0).zIndexManager) || null;\r
372 },\r
373\r
374 getWindow: function(id) {\r
375 return this.windows.get(id);\r
376 },\r
377\r
378 minimizeWindow: function(win) {\r
379 win.minimized = true;\r
380 win.hide();\r
381 },\r
382\r
383 restoreWindow: function (win) {\r
384 if (win.isVisible()) {\r
385 win.restore();\r
386 win.toFront();\r
387 } else {\r
388 win.show();\r
389 }\r
390 return win;\r
391 },\r
392\r
393 tileWindows: function() {\r
394 var me = this, availWidth = me.body.getWidth(true);\r
395 var x = me.xTickSize, y = me.yTickSize, nextY = y;\r
396\r
397 me.windows.each(function(win) {\r
398 if (win.isVisible() && !win.maximized) {\r
399 var w = win.el.getWidth();\r
400\r
401 // Wrap to next row if we are not at the line start and this Window will\r
402 // go off the end\r
403 if (x > me.xTickSize && x + w > availWidth) {\r
404 x = me.xTickSize;\r
405 y = nextY;\r
406 }\r
407\r
408 win.setPosition(x, y);\r
409 x += w + me.xTickSize;\r
410 nextY = Math.max(nextY, y + win.el.getHeight() + me.yTickSize);\r
411 }\r
412 });\r
413 },\r
414\r
415 updateActiveWindow: function () {\r
416 var me = this, activeWindow = me.getActiveWindow(), last = me.lastActiveWindow;\r
417 if (last && last.destroyed) {\r
418 me.lastActiveWindow = null;\r
419 return;\r
420 }\r
421 if (activeWindow === last) {\r
422 return;\r
423 }\r
424\r
425 if (last) {\r
426 if (last.el.dom) {\r
427 last.addCls(me.inactiveWindowCls);\r
428 last.removeCls(me.activeWindowCls);\r
429 }\r
430 last.active = false;\r
431 }\r
432\r
433 me.lastActiveWindow = activeWindow;\r
434\r
435 if (activeWindow) {\r
436 activeWindow.addCls(me.activeWindowCls);\r
437 activeWindow.removeCls(me.inactiveWindowCls);\r
438 activeWindow.minimized = false;\r
439 activeWindow.active = true;\r
440 }\r
441\r
442 me.taskbar.setActiveButton(activeWindow && activeWindow.taskButton);\r
443 }\r
444});\r