Upgrade to ExtJS 4.0.0 - Released 04/26/2011
[extjs.git] / examples / desktop / js / Desktop.js
old mode 100644 (file)
new mode 100755 (executable)
index 7b6e6ae..614c68f
 /*!
- * Ext JS Library 3.3.1
- * Copyright(c) 2006-2010 Sencha Inc.
+ * Ext JS Library 4.0
+ * Copyright(c) 2006-2011 Sencha Inc.
  * licensing@sencha.com
  * http://www.sencha.com/license
  */
-Ext.Desktop = function(app) {
-    this.taskbar = new Ext.ux.TaskBar(app);
-    this.xTickSize = this.yTickSize = 1;
-    var taskbar = this.taskbar;
 
-    var desktopEl = Ext.get('x-desktop');
-    var taskbarEl = Ext.get('ux-taskbar');
-    var shortcuts = Ext.get('x-shortcuts');
+/**
+ * @class Ext.ux.desktop.Desktop
+ * @extends Ext.panel.Panel
+ * <p>This class manages the wallpaper, shortcuts and taskbar.</p>
+ */
+Ext.define('Ext.ux.desktop.Desktop', {
+    extend: 'Ext.panel.Panel',
 
-    var windows = new Ext.WindowGroup();
-    var activeWindow;
+    alias: 'widget.desktop',
 
-    function minimizeWin(win) {
-        win.minimized = true;
-        win.hide();
-    }
+    uses: [
+        'Ext.util.MixedCollection',
+        'Ext.menu.Menu',
+        'Ext.view.View', // dataview
+        'Ext.window.Window',
 
-    function markActive(win) {
-        if (activeWindow && activeWindow != win) {
-            markInactive(activeWindow);
-        }
-        taskbar.setActiveButton(win.taskButton);
-        activeWindow = win;
-        Ext.fly(win.taskButton.el).addClass('active-win');
-        win.minimized = false;
-    }
+        'Ext.ux.desktop.TaskBar',
+        'Ext.ux.desktop.Wallpaper',
+        'Ext.ux.desktop.FitAllLayout'
+    ],
+
+    activeWindowCls: 'ux-desktop-active-win',
+    inactiveWindowCls: 'ux-desktop-inactive-win',
+    lastActiveWindow: null,
+
+    border: false,
+    html: '&#160;',
+    layout: 'fitall',
+
+    xTickSize: 1,
+    yTickSize: 1,
+
+    app: null,
+
+    /**
+     * @cfg {Array|Store} shortcuts
+     * The items to add to the DataView. This can be a {@link Ext.data.Store Store} or a
+     * simple array. Items should minimally provide the fields in the
+     * {@link Ext.ux.desktop.ShorcutModel ShortcutModel}.
+     */
+    shortcuts: null,
+
+    /**
+     * @cfg {String} shortcutItemSelector
+     * This property is passed to the DataView for the desktop to select shortcut items.
+     * If the {@link #shortcutTpl} is modified, this will probably need to be modified as
+     * well.
+     */
+    shortcutItemSelector: 'div.ux-desktop-shortcut',
+
+    /**
+     * @cfg {String} shortcutTpl
+     * This XTemplate is used to render items in the DataView. If this is changed, the
+     * {@link shortcutItemSelect} will probably also need to changed.
+     */
+    shortcutTpl: [
+        '<tpl for=".">',
+            '<div class="ux-desktop-shortcut" id="{name}-shortcut">',
+                '<div class="ux-desktop-shortcut-icon {iconCls}">',
+                    '<img src="',Ext.BLANK_IMAGE_URL,'" title="{name}">',
+                '</div>',
+                '<span class="ux-desktop-shortcut-text">{name}</span>',
+            '</div>',
+        '</tpl>',
+        '<div class="x-clear"></div>'
+    ],
+
+    /**
+     * @cfg {Object} taskbarConfig
+     * The config object for the TaskBar.
+     */
+    taskbarConfig: null,
 
-    function markInactive(win) {
-        if (win == activeWindow) {
-            activeWindow = null;
-            Ext.fly(win.taskButton.el).removeClass('active-win');
+    windowMenu: null,
+
+    initComponent: function () {
+        var me = this;
+
+        me.windowMenu = new Ext.menu.Menu(me.createWindowMenu());
+
+        me.bbar = me.taskbar = new Ext.ux.desktop.TaskBar(me.taskbarConfig);
+        me.taskbar.windowMenu = me.windowMenu;
+
+        me.windows = new Ext.util.MixedCollection();
+
+        me.contextMenu = new Ext.menu.Menu(me.createDesktopMenu());
+
+        me.items = [
+            { xtype: 'wallpaper', id: me.id+'_wallpaper' },
+            me.createDataView()
+        ];
+
+        me.callParent();
+
+        me.shortcutsView = me.items.getAt(1);
+        me.shortcutsView.on('itemclick', me.onShortcutItemClick, me);
+
+        var wallpaper = me.wallpaper;
+        me.wallpaper = me.items.getAt(0);
+        if (wallpaper) {
+            me.setWallpaper(wallpaper, me.wallpaperStretch);
         }
-    }
+    },
 
-    function removeWin(win) {
-        taskbar.removeTaskButton(win.taskButton);
-        layout();
-    }
+    afterRender: function () {
+        var me = this;
+        me.callParent();
+        me.el.on('contextmenu', me.onDesktopMenu, me);
+    },
 
-    function layout() {
-        desktopEl.setHeight(Ext.lib.Dom.getViewHeight() - taskbarEl.getHeight());
-    }
-    Ext.EventManager.onWindowResize(layout);
-
-    this.layout = layout;
-
-    this.createWindow = function(config, cls) {
-        var win = new(cls || Ext.Window)(
-        Ext.applyIf(config || {},
-        {
-            renderTo: desktopEl,
-            manager: windows,
-            minimizable: true,
-            maximizable: true
-        })
-        );
-        win.dd.xTickSize = this.xTickSize;
-        win.dd.yTickSize = this.yTickSize;
-        if (win.resizer) {
-            win.resizer.widthIncrement = this.xTickSize;
-            win.resizer.heightIncrement = this.yTickSize;
+    //------------------------------------------------------
+    // Overrideable configuration creation methods
+
+    createDataView: function () {
+        var me = this;
+        return {
+            xtype: 'dataview',
+            overItemCls: 'x-view-over',
+            trackOver: true,
+            itemSelector: me.shortcutItemSelector,
+            store: me.shortcuts,
+            tpl: new Ext.XTemplate(me.shortcutTpl)
+        };
+    },
+
+    createDesktopMenu: function () {
+        var me = this, ret = {
+            items: me.contextMenuItems || []
+        };
+
+        if (ret.items.length) {
+            ret.items.push('-');
         }
-        win.render(desktopEl);
-        win.taskButton = taskbar.addTaskButton(win);
 
-        win.cmenu = new Ext.menu.Menu({
+        ret.items.push(
+                { text: 'Tile', handler: me.tileWindows, scope: me, minWindows: 1 },
+                { text: 'Cascade', handler: me.cascadeWindows, scope: me, minWindows: 1 })
+
+        return ret;
+    },
+
+    createWindowMenu: function () {
+        var me = this;
+        return {
+            defaultAlign: 'br-tr',
             items: [
+                { text: 'Restore', handler: me.onWindowMenuRestore, scope: me },
+                { text: 'Minimize', handler: me.onWindowMenuMinimize, scope: me },
+                { text: 'Maximize', handler: me.onWindowMenuMaximize, scope: me },
+                '-',
+                { text: 'Close', handler: me.onWindowMenuClose, scope: me }
+            ],
+            listeners: {
+                beforeshow: me.onWindowMenuBeforeShow,
+                hide: me.onWindowMenuHide,
+                scope: me
+            }
+        };
+    },
+
+    //------------------------------------------------------
+    // Event handler methods
+
+    onDesktopMenu: function (e) {
+        var me = this, menu = me.contextMenu;
+        e.stopEvent();
+        if (!menu.rendered) {
+            menu.on('beforeshow', me.onDesktopMenuBeforeShow, me);
+        }
+        menu.showAt(e.getXY());
+        menu.doConstrain();
+    },
+
+    onDesktopMenuBeforeShow: function (menu) {
+        var me = this, count = me.windows.getCount();
+
+        menu.items.each(function (item) {
+            var min = item.minWindows || 0;
+            item.setDisabled(count < min);
+        });
+    },
+
+    onShortcutItemClick: function (dataView, record) {
+        var me = this, module = me.app.getModule(record.data.module),
+            win = module && module.createWindow();
+
+        if (win) {
+            me.restoreWindow(win);
+        }
+    },
+
+    onWindowClose: function(win) {
+        var me = this;
+        me.windows.remove(win);
+        me.taskbar.removeTaskButton(win.taskButton);
+        me.updateActiveWindow();
+    },
+
+    //------------------------------------------------------
+    // Window context menu handlers
+
+    onWindowMenuBeforeShow: function (menu) {
+        var items = menu.items.items, win = menu.theWin;
+        items[0].setDisabled(win.maximized !== true && win.hidden !== true); // Restore
+        items[1].setDisabled(win.minimized === true); // Minimize
+        items[2].setDisabled(win.maximized === true || win.hidden === true); // Maximize
+    },
+
+    onWindowMenuClose: function () {
+        var me = this, win = me.windowMenu.theWin;
+
+        win.close();
+    },
+
+    onWindowMenuHide: function (menu) {
+        menu.theWin = null;
+    },
+
+    onWindowMenuMaximize: function () {
+        var me = this, win = me.windowMenu.theWin;
+
+        win.maximize();
+    },
+
+    onWindowMenuMinimize: function () {
+        var me = this, win = me.windowMenu.theWin;
+
+        win.minimize();
+    },
+
+    onWindowMenuRestore: function () {
+        var me = this, win = me.windowMenu.theWin;
+
+        me.restoreWindow(win);
+    },
+
+    //------------------------------------------------------
+    // Dynamic (re)configuration methods
+
+    getWallpaper: function () {
+        return this.wallpaper.wallpaper;
+    },
+
+    setTickSize: function(xTickSize, yTickSize) {
+        var me = this,
+            xt = me.xTickSize = xTickSize,
+            yt = me.yTickSize = (arguments.length > 1) ? yTickSize : xt;
 
-            ]
+        me.windows.each(function(win) {
+            var dd = win.dd, resizer = win.resizer;
+            dd.xTickSize = xt;
+            dd.yTickSize = yt;
+            resizer.widthIncrement = xt;
+            resizer.heightIncrement = yt;
         });
+    },
 
+    setWallpaper: function (wallpaper, stretch) {
+        this.wallpaper.setWallpaper(wallpaper, stretch);
+        return this;
+    },
+
+    //------------------------------------------------------
+    // Window management methods
+
+    cascadeWindows: function() {
+        var x = 0, y = 0,
+            zmgr = this.getDesktopZIndexManager();
+
+        zmgr.eachBottomUp(function(win) {
+            if (win.isWindow && win.isVisible() && !win.maximized) {
+                win.setPosition(x, y);
+                x += 20;
+                y += 20;
+            }
+        });
+    },
+
+    createWindow: function(config, cls) {
+        var me = this, win, cfg = Ext.applyIf(config || {}, {
+                stateful: false,
+                isWindow: true,
+                constrainHeader: true,
+                minimizable: true,
+                maximizable: true
+            });
+
+        cls = cls || Ext.window.Window;
+        win = me.add(new cls(cfg));
+
+        me.windows.add(win);
+
+        win.taskButton = me.taskbar.addTaskButton(win);
         win.animateTarget = win.taskButton.el;
 
         win.on({
-            'activate': {
-                fn: markActive
-            },
-            'beforeshow': {
-                fn: markActive
-            },
-            'deactivate': {
-                fn: markInactive
-            },
-            'minimize': {
-                fn: minimizeWin
+            activate: me.updateActiveWindow,
+            beforeshow: me.updateActiveWindow,
+            deactivate: me.updateActiveWindow,
+            minimize: me.minimizeWindow,
+            destroy: me.onWindowClose,
+            scope: me
+        });
+
+        win.on({
+            afterrender: function () {
+                win.dd.xTickSize = me.xTickSize;
+                win.dd.yTickSize = me.yTickSize;
+
+                if (win.resizer) {
+                    win.resizer.widthIncrement = me.xTickSize;
+                    win.resizer.heightIncrement = me.yTickSize;
+                }
             },
-            'close': {
-                fn: removeWin
-            }
+            single: true
         });
 
-        layout();
+        // replace normal window close w/fadeOut animation:
+        win.doClose = function ()  {
+            win.el.disableShadow();
+            win.el.fadeOut({
+                listeners: {
+                    afteranimate: function () {
+                        win.destroy();
+                    }
+                }
+            });
+        };
+
         return win;
-    };
-
-    this.getManager = function() {
-        return windows;
-    };
-
-    this.getWindow = function(id) {
-        return windows.get(id);
-    };
-
-    this.getWinWidth = function() {
-        var width = Ext.lib.Dom.getViewWidth();
-        return width < 200 ? 200: width;
-    };
-
-    this.getWinHeight = function() {
-        var height = (Ext.lib.Dom.getViewHeight() - taskbarEl.getHeight());
-        return height < 100 ? 100: height;
-    };
-
-    this.getWinX = function(width) {
-        return (Ext.lib.Dom.getViewWidth() - width) / 2;
-    };
-
-    this.getWinY = function(height) {
-        return (Ext.lib.Dom.getViewHeight() - taskbarEl.getHeight() - height) / 2;
-    };
-
-    this.setTickSize = function(xTickSize, yTickSize) {
-        this.xTickSize = xTickSize;
-        if (arguments.length == 1) {
-            this.yTickSize = xTickSize;
+    },
+
+    getActiveWindow: function () {
+        var win = null,
+            zmgr = this.getDesktopZIndexManager();
+
+        if (zmgr) {
+            // We cannot rely on activate/deactive because that fires against non-Window
+            // components in the stack.
+
+            zmgr.eachTopDown(function (comp) {
+                if (comp.isWindow && !comp.hidden) {
+                    win = comp;
+                    return false;
+                }
+                return true;
+            });
+        }
+
+        return win;
+    },
+
+    getDesktopZIndexManager: function () {
+        var windows = this.windows;
+        // TODO - there has to be a better way to get this...
+        return (windows.getCount() && windows.getAt(0).zIndexManager) || null;
+    },
+
+    getWindow: function(id) {
+        return this.windows.get(id);
+    },
+
+    minimizeWindow: function(win) {
+        win.minimized = true;
+        win.hide();
+    },
+
+    restoreWindow: function (win) {
+        if (win.isVisible()) {
+            win.restore();
+            win.toFront();
         } else {
-            this.yTickSize = yTickSize;
+            win.show();
         }
-        windows.each(function(win) {
-            win.dd.xTickSize = this.xTickSize;
-            win.dd.yTickSize = this.yTickSize;
-            win.resizer.widthIncrement = this.xTickSize;
-            win.resizer.heightIncrement = this.yTickSize;
-        },
-        this);
-    };
-
-    this.cascade = function() {
-        var x = 0,
-        y = 0;
-        windows.each(function(win) {
-            if (win.isVisible() && !win.maximized) {
-                win.setPosition(x, y);
-                x += 20;
-                y += 20;
-            }
-        },
-        this);
-    };
-
-    this.tile = function() {
-        var availWidth = desktopEl.getWidth(true);
-        var x = this.xTickSize;
-        var y = this.yTickSize;
-        var nextY = y;
-        windows.each(function(win) {
+        return win;
+    },
+
+    tileWindows: function() {
+        var me = this, availWidth = me.body.getWidth(true);
+        var x = me.xTickSize, y = me.yTickSize, nextY = y;
+
+        me.windows.each(function(win) {
             if (win.isVisible() && !win.maximized) {
                 var w = win.el.getWidth();
 
-                //              Wrap to next row if we are not at the line start and this Window will go off the end
-                if ((x > this.xTickSize) && (x + w > availWidth)) {
-                    x = this.xTickSize;
+                // Wrap to next row if we are not at the line start and this Window will
+                // go off the end
+                if (x > me.xTickSize && x + w > availWidth) {
+                    x = me.xTickSize;
                     y = nextY;
                 }
 
                 win.setPosition(x, y);
-                x += w + this.xTickSize;
-                nextY = Math.max(nextY, y + win.el.getHeight() + this.yTickSize);
-            }
-        },
-        this);
-    };
-
-    this.contextMenu = new Ext.menu.Menu({
-        items: [{
-            text: 'Tile',
-            handler: this.tile,
-            scope: this
-        },
-        {
-            text: 'Cascade',
-            handler: this.cascade,
-            scope: this
-        }]
-    });
-    desktopEl.on('contextmenu',
-        function(e) {
-            e.stopEvent();
-            this.contextMenu.showAt(e.getXY());
-        },
-        this);
-
-    layout();
-
-    if (shortcuts) {
-        shortcuts.on('click',
-        function(e, t) {
-            t = e.getTarget('dt', shortcuts);
-            if (t) {
-                e.stopEvent();
-                var module = app.getModule(t.id.replace('-shortcut', ''));
-                if (module) {
-                    module.createWindow();
-                }
+                x += w + me.xTickSize;
+                nextY = Math.max(nextY, y + win.el.getHeight() + me.yTickSize);
             }
         });
+    },
+
+    updateActiveWindow: function () {
+        var me = this, activeWindow = me.getActiveWindow(), last = me.lastActiveWindow;
+        if (activeWindow === last) {
+            return;
+        }
+
+        if (last) {
+            if (last.el.dom) {
+                last.addCls(me.inactiveWindowCls);
+                last.removeCls(me.activeWindowCls);
+            }
+            last.active = false;
+        }
+
+        me.lastActiveWindow = activeWindow;
+
+        if (activeWindow) {
+            activeWindow.addCls(me.activeWindowCls);
+            activeWindow.removeCls(me.inactiveWindowCls);
+            activeWindow.minimized = false;
+            activeWindow.active = true;
+        }
+
+        me.taskbar.setActiveButton(activeWindow && activeWindow.taskButton);
     }
-};
+});