3 This file is part of Ext JS 4
5 Copyright (c) 2011 Sencha Inc
7 Contact: http://www.sencha.com/contact
9 GNU General Public License Usage
10 This file may be used under the terms of the GNU General Public License version 3.0 as published by the Free Software Foundation and appearing in the file LICENSE included in the packaging of this file. Please review the following information to ensure the GNU General Public License version 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.
12 If you are unsure which license is appropriate for your use, please contact the sales department at http://www.sencha.com/contact.
17 * Copyright(c) 2006-2011 Sencha Inc.
18 * licensing@sencha.com
19 * http://www.sencha.com/license
23 * @class Ext.ux.desktop.Desktop
24 * @extends Ext.panel.Panel
25 * <p>This class manages the wallpaper, shortcuts and taskbar.</p>
27 Ext.define('Ext.ux.desktop.Desktop', {
28 extend: 'Ext.panel.Panel',
30 alias: 'widget.desktop',
33 'Ext.util.MixedCollection',
35 'Ext.view.View', // dataview
38 'Ext.ux.desktop.TaskBar',
39 'Ext.ux.desktop.Wallpaper',
40 'Ext.ux.desktop.FitAllLayout'
43 activeWindowCls: 'ux-desktop-active-win',
44 inactiveWindowCls: 'ux-desktop-inactive-win',
45 lastActiveWindow: null,
57 * @cfg {Array|Store} shortcuts
58 * The items to add to the DataView. This can be a {@link Ext.data.Store Store} or a
59 * simple array. Items should minimally provide the fields in the
60 * {@link Ext.ux.desktop.ShorcutModel ShortcutModel}.
65 * @cfg {String} shortcutItemSelector
66 * This property is passed to the DataView for the desktop to select shortcut items.
67 * If the {@link #shortcutTpl} is modified, this will probably need to be modified as
70 shortcutItemSelector: 'div.ux-desktop-shortcut',
73 * @cfg {String} shortcutTpl
74 * This XTemplate is used to render items in the DataView. If this is changed, the
75 * {@link shortcutItemSelect} will probably also need to changed.
79 '<div class="ux-desktop-shortcut" id="{name}-shortcut">',
80 '<div class="ux-desktop-shortcut-icon {iconCls}">',
81 '<img src="',Ext.BLANK_IMAGE_URL,'" title="{name}">',
83 '<span class="ux-desktop-shortcut-text">{name}</span>',
86 '<div class="x-clear"></div>'
90 * @cfg {Object} taskbarConfig
91 * The config object for the TaskBar.
97 initComponent: function () {
100 me.windowMenu = new Ext.menu.Menu(me.createWindowMenu());
102 me.bbar = me.taskbar = new Ext.ux.desktop.TaskBar(me.taskbarConfig);
103 me.taskbar.windowMenu = me.windowMenu;
105 me.windows = new Ext.util.MixedCollection();
107 me.contextMenu = new Ext.menu.Menu(me.createDesktopMenu());
110 { xtype: 'wallpaper', id: me.id+'_wallpaper' },
116 me.shortcutsView = me.items.getAt(1);
117 me.shortcutsView.on('itemclick', me.onShortcutItemClick, me);
119 var wallpaper = me.wallpaper;
120 me.wallpaper = me.items.getAt(0);
122 me.setWallpaper(wallpaper, me.wallpaperStretch);
126 afterRender: function () {
129 me.el.on('contextmenu', me.onDesktopMenu, me);
132 //------------------------------------------------------
133 // Overrideable configuration creation methods
135 createDataView: function () {
139 overItemCls: 'x-view-over',
141 itemSelector: me.shortcutItemSelector,
143 tpl: new Ext.XTemplate(me.shortcutTpl)
147 createDesktopMenu: function () {
148 var me = this, ret = {
149 items: me.contextMenuItems || []
152 if (ret.items.length) {
157 { text: 'Tile', handler: me.tileWindows, scope: me, minWindows: 1 },
158 { text: 'Cascade', handler: me.cascadeWindows, scope: me, minWindows: 1 })
163 createWindowMenu: function () {
166 defaultAlign: 'br-tr',
168 { text: 'Restore', handler: me.onWindowMenuRestore, scope: me },
169 { text: 'Minimize', handler: me.onWindowMenuMinimize, scope: me },
170 { text: 'Maximize', handler: me.onWindowMenuMaximize, scope: me },
172 { text: 'Close', handler: me.onWindowMenuClose, scope: me }
175 beforeshow: me.onWindowMenuBeforeShow,
176 hide: me.onWindowMenuHide,
182 //------------------------------------------------------
183 // Event handler methods
185 onDesktopMenu: function (e) {
186 var me = this, menu = me.contextMenu;
188 if (!menu.rendered) {
189 menu.on('beforeshow', me.onDesktopMenuBeforeShow, me);
191 menu.showAt(e.getXY());
195 onDesktopMenuBeforeShow: function (menu) {
196 var me = this, count = me.windows.getCount();
198 menu.items.each(function (item) {
199 var min = item.minWindows || 0;
200 item.setDisabled(count < min);
204 onShortcutItemClick: function (dataView, record) {
205 var me = this, module = me.app.getModule(record.data.module),
206 win = module && module.createWindow();
209 me.restoreWindow(win);
213 onWindowClose: function(win) {
215 me.windows.remove(win);
216 me.taskbar.removeTaskButton(win.taskButton);
217 me.updateActiveWindow();
220 //------------------------------------------------------
221 // Window context menu handlers
223 onWindowMenuBeforeShow: function (menu) {
224 var items = menu.items.items, win = menu.theWin;
225 items[0].setDisabled(win.maximized !== true && win.hidden !== true); // Restore
226 items[1].setDisabled(win.minimized === true); // Minimize
227 items[2].setDisabled(win.maximized === true || win.hidden === true); // Maximize
230 onWindowMenuClose: function () {
231 var me = this, win = me.windowMenu.theWin;
236 onWindowMenuHide: function (menu) {
240 onWindowMenuMaximize: function () {
241 var me = this, win = me.windowMenu.theWin;
246 onWindowMenuMinimize: function () {
247 var me = this, win = me.windowMenu.theWin;
252 onWindowMenuRestore: function () {
253 var me = this, win = me.windowMenu.theWin;
255 me.restoreWindow(win);
258 //------------------------------------------------------
259 // Dynamic (re)configuration methods
261 getWallpaper: function () {
262 return this.wallpaper.wallpaper;
265 setTickSize: function(xTickSize, yTickSize) {
267 xt = me.xTickSize = xTickSize,
268 yt = me.yTickSize = (arguments.length > 1) ? yTickSize : xt;
270 me.windows.each(function(win) {
271 var dd = win.dd, resizer = win.resizer;
274 resizer.widthIncrement = xt;
275 resizer.heightIncrement = yt;
279 setWallpaper: function (wallpaper, stretch) {
280 this.wallpaper.setWallpaper(wallpaper, stretch);
284 //------------------------------------------------------
285 // Window management methods
287 cascadeWindows: function() {
289 zmgr = this.getDesktopZIndexManager();
291 zmgr.eachBottomUp(function(win) {
292 if (win.isWindow && win.isVisible() && !win.maximized) {
293 win.setPosition(x, y);
300 createWindow: function(config, cls) {
301 var me = this, win, cfg = Ext.applyIf(config || {}, {
304 constrainHeader: true,
309 cls = cls || Ext.window.Window;
310 win = me.add(new cls(cfg));
314 win.taskButton = me.taskbar.addTaskButton(win);
315 win.animateTarget = win.taskButton.el;
318 activate: me.updateActiveWindow,
319 beforeshow: me.updateActiveWindow,
320 deactivate: me.updateActiveWindow,
321 minimize: me.minimizeWindow,
322 destroy: me.onWindowClose,
327 afterrender: function () {
328 win.dd.xTickSize = me.xTickSize;
329 win.dd.yTickSize = me.yTickSize;
332 win.resizer.widthIncrement = me.xTickSize;
333 win.resizer.heightIncrement = me.yTickSize;
339 // replace normal window close w/fadeOut animation:
340 win.doClose = function () {
341 win.doClose = Ext.emptyFn; // dblclick can call again...
342 win.el.disableShadow();
345 afteranimate: function () {
355 getActiveWindow: function () {
357 zmgr = this.getDesktopZIndexManager();
360 // We cannot rely on activate/deactive because that fires against non-Window
361 // components in the stack.
363 zmgr.eachTopDown(function (comp) {
364 if (comp.isWindow && !comp.hidden) {
375 getDesktopZIndexManager: function () {
376 var windows = this.windows;
377 // TODO - there has to be a better way to get this...
378 return (windows.getCount() && windows.getAt(0).zIndexManager) || null;
381 getWindow: function(id) {
382 return this.windows.get(id);
385 minimizeWindow: function(win) {
386 win.minimized = true;
390 restoreWindow: function (win) {
391 if (win.isVisible()) {
400 tileWindows: function() {
401 var me = this, availWidth = me.body.getWidth(true);
402 var x = me.xTickSize, y = me.yTickSize, nextY = y;
404 me.windows.each(function(win) {
405 if (win.isVisible() && !win.maximized) {
406 var w = win.el.getWidth();
408 // Wrap to next row if we are not at the line start and this Window will
410 if (x > me.xTickSize && x + w > availWidth) {
415 win.setPosition(x, y);
416 x += w + me.xTickSize;
417 nextY = Math.max(nextY, y + win.el.getHeight() + me.yTickSize);
422 updateActiveWindow: function () {
423 var me = this, activeWindow = me.getActiveWindow(), last = me.lastActiveWindow;
424 if (activeWindow === last) {
430 last.addCls(me.inactiveWindowCls);
431 last.removeCls(me.activeWindowCls);
436 me.lastActiveWindow = activeWindow;
439 activeWindow.addCls(me.activeWindowCls);
440 activeWindow.removeCls(me.inactiveWindowCls);
441 activeWindow.minimized = false;
442 activeWindow.active = true;
445 me.taskbar.setActiveButton(activeWindow && activeWindow.taskButton);