Upgrade to ExtJS 3.1.0 - Released 12/16/2009
[extjs.git] / examples / ux / ux-all-debug.js
index 695e1ce..0a52e43 100644 (file)
@@ -1,5 +1,5 @@
 /*!
- * Ext JS Library 3.0.3
+ * Ext JS Library 3.1.0
  * Copyright(c) 2006-2009 Ext JS, LLC
  * licensing@extjs.com
  * http://www.extjs.com/license
@@ -346,7 +346,483 @@ Ext.ux.grid.CheckColumn.prototype ={
 Ext.preg('checkcolumn', Ext.ux.grid.CheckColumn);\r
 \r
 // backwards compat\r
-Ext.grid.CheckColumn = Ext.ux.grid.CheckColumn;Ext.ns('Ext.ux.tree');\r
+Ext.grid.CheckColumn = Ext.ux.grid.CheckColumn;Ext.ns('Ext.ux.grid');\r
+\r
+if(Ext.isWebKit){\r
+    Ext.grid.GridView.prototype.borderWidth = 0;\r
+}\r
+\r
+Ext.ux.grid.ColumnHeaderGroup = Ext.extend(Ext.util.Observable, {\r
+\r
+    constructor: function(config){\r
+        this.config = config;\r
+    },\r
+\r
+    init: function(grid){\r
+        Ext.applyIf(grid.colModel, this.config);\r
+        Ext.apply(grid.getView(), this.viewConfig);\r
+    },\r
+\r
+    viewConfig: {\r
+        initTemplates: function(){\r
+            this.constructor.prototype.initTemplates.apply(this, arguments);\r
+            var ts = this.templates || {};\r
+            if(!ts.gcell){\r
+                ts.gcell = new Ext.XTemplate('<td class="x-grid3-hd x-grid3-gcell x-grid3-td-{id} ux-grid-hd-group-row-{row} {cls}" style="{style}">', '<div {tooltip} class="x-grid3-hd-inner x-grid3-hd-{id}" unselectable="on" style="{istyle}">', this.grid.enableHdMenu ? '<a class="x-grid3-hd-btn" href="#"></a>' : '', '{value}</div></td>');\r
+            }\r
+            this.templates = ts;\r
+            this.hrowRe = new RegExp("ux-grid-hd-group-row-(\\d+)", "");\r
+        },\r
+\r
+        renderHeaders: function(){\r
+            var ts = this.templates, headers = [], cm = this.cm, rows = cm.rows, tstyle = 'width:' + this.getTotalWidth() + ';';\r
+\r
+            for(var row = 0, rlen = rows.length; row < rlen; row++){\r
+                var r = rows[row], cells = [];\r
+                for(var i = 0, gcol = 0, len = r.length; i < len; i++){\r
+                    var group = r[i];\r
+                    group.colspan = group.colspan || 1;\r
+                    var id = this.getColumnId(group.dataIndex ? cm.findColumnIndex(group.dataIndex) : gcol), gs = Ext.ux.grid.ColumnHeaderGroup.prototype.getGroupStyle.call(this, group, gcol);\r
+                    cells[i] = ts.gcell.apply({\r
+                        cls: 'ux-grid-hd-group-cell',\r
+                        id: id,\r
+                        row: row,\r
+                        style: 'width:' + gs.width + ';' + (gs.hidden ? 'display:none;' : '') + (group.align ? 'text-align:' + group.align + ';' : ''),\r
+                        tooltip: group.tooltip ? (Ext.QuickTips.isEnabled() ? 'ext:qtip' : 'title') + '="' + group.tooltip + '"' : '',\r
+                        istyle: group.align == 'right' ? 'padding-right:16px' : '',\r
+                        btn: this.grid.enableHdMenu && group.header,\r
+                        value: group.header || '&nbsp;'\r
+                    });\r
+                    gcol += group.colspan;\r
+                }\r
+                headers[row] = ts.header.apply({\r
+                    tstyle: tstyle,\r
+                    cells: cells.join('')\r
+                });\r
+            }\r
+            headers.push(this.constructor.prototype.renderHeaders.apply(this, arguments));\r
+            return headers.join('');\r
+        },\r
+\r
+        onColumnWidthUpdated: function(){\r
+            this.constructor.prototype.onColumnWidthUpdated.apply(this, arguments);\r
+            Ext.ux.grid.ColumnHeaderGroup.prototype.updateGroupStyles.call(this);\r
+        },\r
+\r
+        onAllColumnWidthsUpdated: function(){\r
+            this.constructor.prototype.onAllColumnWidthsUpdated.apply(this, arguments);\r
+            Ext.ux.grid.ColumnHeaderGroup.prototype.updateGroupStyles.call(this);\r
+        },\r
+\r
+        onColumnHiddenUpdated: function(){\r
+            this.constructor.prototype.onColumnHiddenUpdated.apply(this, arguments);\r
+            Ext.ux.grid.ColumnHeaderGroup.prototype.updateGroupStyles.call(this);\r
+        },\r
+\r
+        getHeaderCell: function(index){\r
+            return this.mainHd.query(this.cellSelector)[index];\r
+        },\r
+\r
+        findHeaderCell: function(el){\r
+            return el ? this.fly(el).findParent('td.x-grid3-hd', this.cellSelectorDepth) : false;\r
+        },\r
+\r
+        findHeaderIndex: function(el){\r
+            var cell = this.findHeaderCell(el);\r
+            return cell ? this.getCellIndex(cell) : false;\r
+        },\r
+\r
+        updateSortIcon: function(col, dir){\r
+            var sc = this.sortClasses, hds = this.mainHd.select(this.cellSelector).removeClass(sc);\r
+            hds.item(col).addClass(sc[dir == "DESC" ? 1 : 0]);\r
+        },\r
+\r
+        handleHdDown: function(e, t){\r
+            var el = Ext.get(t);\r
+            if(el.hasClass('x-grid3-hd-btn')){\r
+                e.stopEvent();\r
+                var hd = this.findHeaderCell(t);\r
+                Ext.fly(hd).addClass('x-grid3-hd-menu-open');\r
+                var index = this.getCellIndex(hd);\r
+                this.hdCtxIndex = index;\r
+                var ms = this.hmenu.items, cm = this.cm;\r
+                ms.get('asc').setDisabled(!cm.isSortable(index));\r
+                ms.get('desc').setDisabled(!cm.isSortable(index));\r
+                this.hmenu.on('hide', function(){\r
+                    Ext.fly(hd).removeClass('x-grid3-hd-menu-open');\r
+                }, this, {\r
+                    single: true\r
+                });\r
+                this.hmenu.show(t, 'tl-bl?');\r
+            }else if(el.hasClass('ux-grid-hd-group-cell') || Ext.fly(t).up('.ux-grid-hd-group-cell')){\r
+                e.stopEvent();\r
+            }\r
+        },\r
+\r
+        handleHdMove: function(e, t){\r
+            var hd = this.findHeaderCell(this.activeHdRef);\r
+            if(hd && !this.headersDisabled && !Ext.fly(hd).hasClass('ux-grid-hd-group-cell')){\r
+                var hw = this.splitHandleWidth || 5, r = this.activeHdRegion, x = e.getPageX(), ss = hd.style, cur = '';\r
+                if(this.grid.enableColumnResize !== false){\r
+                    if(x - r.left <= hw && this.cm.isResizable(this.activeHdIndex - 1)){\r
+                        cur = Ext.isAir ? 'move' : Ext.isWebKit ? 'e-resize' : 'col-resize'; // col-resize\r
+                                                                                                // not\r
+                                                                                                // always\r
+                                                                                                // supported\r
+                    }else if(r.right - x <= (!this.activeHdBtn ? hw : 2) && this.cm.isResizable(this.activeHdIndex)){\r
+                        cur = Ext.isAir ? 'move' : Ext.isWebKit ? 'w-resize' : 'col-resize';\r
+                    }\r
+                }\r
+                ss.cursor = cur;\r
+            }\r
+        },\r
+\r
+        handleHdOver: function(e, t){\r
+            var hd = this.findHeaderCell(t);\r
+            if(hd && !this.headersDisabled){\r
+                this.activeHdRef = t;\r
+                this.activeHdIndex = this.getCellIndex(hd);\r
+                var fly = this.fly(hd);\r
+                this.activeHdRegion = fly.getRegion();\r
+                if(!(this.cm.isMenuDisabled(this.activeHdIndex) || fly.hasClass('ux-grid-hd-group-cell'))){\r
+                    fly.addClass('x-grid3-hd-over');\r
+                    this.activeHdBtn = fly.child('.x-grid3-hd-btn');\r
+                    if(this.activeHdBtn){\r
+                        this.activeHdBtn.dom.style.height = (hd.firstChild.offsetHeight - 1) + 'px';\r
+                    }\r
+                }\r
+            }\r
+        },\r
+\r
+        handleHdOut: function(e, t){\r
+            var hd = this.findHeaderCell(t);\r
+            if(hd && (!Ext.isIE || !e.within(hd, true))){\r
+                this.activeHdRef = null;\r
+                this.fly(hd).removeClass('x-grid3-hd-over');\r
+                hd.style.cursor = '';\r
+            }\r
+        },\r
+\r
+        handleHdMenuClick: function(item){\r
+            var index = this.hdCtxIndex, cm = this.cm, ds = this.ds, id = item.getItemId();\r
+            switch(id){\r
+                case 'asc':\r
+                    ds.sort(cm.getDataIndex(index), 'ASC');\r
+                    break;\r
+                case 'desc':\r
+                    ds.sort(cm.getDataIndex(index), 'DESC');\r
+                    break;\r
+                default:\r
+                    if(id.substr(0, 5) == 'group'){\r
+                        var i = id.split('-'), row = parseInt(i[1], 10), col = parseInt(i[2], 10), r = this.cm.rows[row], group, gcol = 0;\r
+                        for(var i = 0, len = r.length; i < len; i++){\r
+                            group = r[i];\r
+                            if(col >= gcol && col < gcol + group.colspan){\r
+                                break;\r
+                            }\r
+                            gcol += group.colspan;\r
+                        }\r
+                        if(item.checked){\r
+                            var max = cm.getColumnsBy(this.isHideableColumn, this).length;\r
+                            for(var i = gcol, len = gcol + group.colspan; i < len; i++){\r
+                                if(!cm.isHidden(i)){\r
+                                    max--;\r
+                                }\r
+                            }\r
+                            if(max < 1){\r
+                                this.onDenyColumnHide();\r
+                                return false;\r
+                            }\r
+                        }\r
+                        for(var i = gcol, len = gcol + group.colspan; i < len; i++){\r
+                            if(cm.config[i].fixed !== true && cm.config[i].hideable !== false){\r
+                                cm.setHidden(i, item.checked);\r
+                            }\r
+                        }\r
+                    }else{\r
+                        index = cm.getIndexById(id.substr(4));\r
+                        if(index != -1){\r
+                            if(item.checked && cm.getColumnsBy(this.isHideableColumn, this).length <= 1){\r
+                                this.onDenyColumnHide();\r
+                                return false;\r
+                            }\r
+                            cm.setHidden(index, item.checked);\r
+                        }\r
+                    }\r
+                    item.checked = !item.checked;\r
+                    if(item.menu){\r
+                        var updateChildren = function(menu){\r
+                            menu.items.each(function(childItem){\r
+                                if(!childItem.disabled){\r
+                                    childItem.setChecked(item.checked, false);\r
+                                    if(childItem.menu){\r
+                                        updateChildren(childItem.menu);\r
+                                    }\r
+                                }\r
+                            });\r
+                        }\r
+                        updateChildren(item.menu);\r
+                    }\r
+                    var parentMenu = item, parentItem;\r
+                    while(parentMenu = parentMenu.parentMenu){\r
+                        if(!parentMenu.parentMenu || !(parentItem = parentMenu.parentMenu.items.get(parentMenu.getItemId())) || !parentItem.setChecked){\r
+                            break;\r
+                        }\r
+                        var checked = parentMenu.items.findIndexBy(function(m){\r
+                            return m.checked;\r
+                        }) >= 0;\r
+                        parentItem.setChecked(checked, true);\r
+                    }\r
+                    item.checked = !item.checked;\r
+            }\r
+            return true;\r
+        },\r
+\r
+        beforeColMenuShow: function(){\r
+            var cm = this.cm, rows = this.cm.rows;\r
+            this.colMenu.removeAll();\r
+            for(var col = 0, clen = cm.getColumnCount(); col < clen; col++){\r
+                var menu = this.colMenu, title = cm.getColumnHeader(col), text = [];\r
+                if(cm.config[col].fixed !== true && cm.config[col].hideable !== false){\r
+                    for(var row = 0, rlen = rows.length; row < rlen; row++){\r
+                        var r = rows[row], group, gcol = 0;\r
+                        for(var i = 0, len = r.length; i < len; i++){\r
+                            group = r[i];\r
+                            if(col >= gcol && col < gcol + group.colspan){\r
+                                break;\r
+                            }\r
+                            gcol += group.colspan;\r
+                        }\r
+                        if(group && group.header){\r
+                            if(cm.hierarchicalColMenu){\r
+                                var gid = 'group-' + row + '-' + gcol;\r
+                                var item = menu.items.item(gid);\r
+                                var submenu = item ? item.menu : null;\r
+                                if(!submenu){\r
+                                    submenu = new Ext.menu.Menu({\r
+                                        itemId: gid\r
+                                    });\r
+                                    submenu.on("itemclick", this.handleHdMenuClick, this);\r
+                                    var checked = false, disabled = true;\r
+                                    for(var c = gcol, lc = gcol + group.colspan; c < lc; c++){\r
+                                        if(!cm.isHidden(c)){\r
+                                            checked = true;\r
+                                        }\r
+                                        if(cm.config[c].hideable !== false){\r
+                                            disabled = false;\r
+                                        }\r
+                                    }\r
+                                    menu.add({\r
+                                        itemId: gid,\r
+                                        text: group.header,\r
+                                        menu: submenu,\r
+                                        hideOnClick: false,\r
+                                        checked: checked,\r
+                                        disabled: disabled\r
+                                    });\r
+                                }\r
+                                menu = submenu;\r
+                            }else{\r
+                                text.push(group.header);\r
+                            }\r
+                        }\r
+                    }\r
+                    text.push(title);\r
+                    menu.add(new Ext.menu.CheckItem({\r
+                        itemId: "col-" + cm.getColumnId(col),\r
+                        text: text.join(' '),\r
+                        checked: !cm.isHidden(col),\r
+                        hideOnClick: false,\r
+                        disabled: cm.config[col].hideable === false\r
+                    }));\r
+                }\r
+            }\r
+        },\r
+\r
+        renderUI: function(){\r
+            this.constructor.prototype.renderUI.apply(this, arguments);\r
+            Ext.apply(this.columnDrop, Ext.ux.grid.ColumnHeaderGroup.prototype.columnDropConfig);\r
+            Ext.apply(this.splitZone, Ext.ux.grid.ColumnHeaderGroup.prototype.splitZoneConfig);\r
+        }\r
+    },\r
+\r
+    splitZoneConfig: {\r
+        allowHeaderDrag: function(e){\r
+            return !e.getTarget(null, null, true).hasClass('ux-grid-hd-group-cell');\r
+        }\r
+    },\r
+\r
+    columnDropConfig: {\r
+        getTargetFromEvent: function(e){\r
+            var t = Ext.lib.Event.getTarget(e);\r
+            return this.view.findHeaderCell(t);\r
+        },\r
+\r
+        positionIndicator: function(h, n, e){\r
+            var data = Ext.ux.grid.ColumnHeaderGroup.prototype.getDragDropData.call(this, h, n, e);\r
+            if(data === false){\r
+                return false;\r
+            }\r
+            var px = data.px + this.proxyOffsets[0];\r
+            this.proxyTop.setLeftTop(px, data.r.top + this.proxyOffsets[1]);\r
+            this.proxyTop.show();\r
+            this.proxyBottom.setLeftTop(px, data.r.bottom);\r
+            this.proxyBottom.show();\r
+            return data.pt;\r
+        },\r
+\r
+        onNodeDrop: function(n, dd, e, data){\r
+            var h = data.header;\r
+            if(h != n){\r
+                var d = Ext.ux.grid.ColumnHeaderGroup.prototype.getDragDropData.call(this, h, n, e);\r
+                if(d === false){\r
+                    return false;\r
+                }\r
+                var cm = this.grid.colModel, right = d.oldIndex < d.newIndex, rows = cm.rows;\r
+                for(var row = d.row, rlen = rows.length; row < rlen; row++){\r
+                    var r = rows[row], len = r.length, fromIx = 0, span = 1, toIx = len;\r
+                    for(var i = 0, gcol = 0; i < len; i++){\r
+                        var group = r[i];\r
+                        if(d.oldIndex >= gcol && d.oldIndex < gcol + group.colspan){\r
+                            fromIx = i;\r
+                        }\r
+                        if(d.oldIndex + d.colspan - 1 >= gcol && d.oldIndex + d.colspan - 1 < gcol + group.colspan){\r
+                            span = i - fromIx + 1;\r
+                        }\r
+                        if(d.newIndex >= gcol && d.newIndex < gcol + group.colspan){\r
+                            toIx = i;\r
+                        }\r
+                        gcol += group.colspan;\r
+                    }\r
+                    var groups = r.splice(fromIx, span);\r
+                    rows[row] = r.splice(0, toIx - (right ? span : 0)).concat(groups).concat(r);\r
+                }\r
+                for(var c = 0; c < d.colspan; c++){\r
+                    var oldIx = d.oldIndex + (right ? 0 : c), newIx = d.newIndex + (right ? -1 : c);\r
+                    cm.moveColumn(oldIx, newIx);\r
+                    this.grid.fireEvent("columnmove", oldIx, newIx);\r
+                }\r
+                return true;\r
+            }\r
+            return false;\r
+        }\r
+    },\r
+\r
+    getGroupStyle: function(group, gcol){\r
+        var width = 0, hidden = true;\r
+        for(var i = gcol, len = gcol + group.colspan; i < len; i++){\r
+            if(!this.cm.isHidden(i)){\r
+                var cw = this.cm.getColumnWidth(i);\r
+                if(typeof cw == 'number'){\r
+                    width += cw;\r
+                }\r
+                hidden = false;\r
+            }\r
+        }\r
+        return {\r
+            width: (Ext.isBorderBox ? width : Math.max(width - this.borderWidth, 0)) + 'px',\r
+            hidden: hidden\r
+        };\r
+    },\r
+\r
+    updateGroupStyles: function(col){\r
+        var tables = this.mainHd.query('.x-grid3-header-offset > table'), tw = this.getTotalWidth(), rows = this.cm.rows;\r
+        for(var row = 0; row < tables.length; row++){\r
+            tables[row].style.width = tw;\r
+            if(row < rows.length){\r
+                var cells = tables[row].firstChild.firstChild.childNodes;\r
+                for(var i = 0, gcol = 0; i < cells.length; i++){\r
+                    var group = rows[row][i];\r
+                    if((typeof col != 'number') || (col >= gcol && col < gcol + group.colspan)){\r
+                        var gs = Ext.ux.grid.ColumnHeaderGroup.prototype.getGroupStyle.call(this, group, gcol);\r
+                        cells[i].style.width = gs.width;\r
+                        cells[i].style.display = gs.hidden ? 'none' : '';\r
+                    }\r
+                    gcol += group.colspan;\r
+                }\r
+            }\r
+        }\r
+    },\r
+\r
+    getGroupRowIndex: function(el){\r
+        if(el){\r
+            var m = el.className.match(this.hrowRe);\r
+            if(m && m[1]){\r
+                return parseInt(m[1], 10);\r
+            }\r
+        }\r
+        return this.cm.rows.length;\r
+    },\r
+\r
+    getGroupSpan: function(row, col){\r
+        if(row < 0){\r
+            return {\r
+                col: 0,\r
+                colspan: this.cm.getColumnCount()\r
+            };\r
+        }\r
+        var r = this.cm.rows[row];\r
+        if(r){\r
+            for(var i = 0, gcol = 0, len = r.length; i < len; i++){\r
+                var group = r[i];\r
+                if(col >= gcol && col < gcol + group.colspan){\r
+                    return {\r
+                        col: gcol,\r
+                        colspan: group.colspan\r
+                    };\r
+                }\r
+                gcol += group.colspan;\r
+            }\r
+            return {\r
+                col: gcol,\r
+                colspan: 0\r
+            };\r
+        }\r
+        return {\r
+            col: col,\r
+            colspan: 1\r
+        };\r
+    },\r
+\r
+    getDragDropData: function(h, n, e){\r
+        if(h.parentNode != n.parentNode){\r
+            return false;\r
+        }\r
+        var cm = this.grid.colModel, x = Ext.lib.Event.getPageX(e), r = Ext.lib.Dom.getRegion(n.firstChild), px, pt;\r
+        if((r.right - x) <= (r.right - r.left) / 2){\r
+            px = r.right + this.view.borderWidth;\r
+            pt = "after";\r
+        }else{\r
+            px = r.left;\r
+            pt = "before";\r
+        }\r
+        var oldIndex = this.view.getCellIndex(h), newIndex = this.view.getCellIndex(n);\r
+        if(cm.isFixed(newIndex)){\r
+            return false;\r
+        }\r
+        var row = Ext.ux.grid.ColumnHeaderGroup.prototype.getGroupRowIndex.call(this.view, h), \r
+            oldGroup = Ext.ux.grid.ColumnHeaderGroup.prototype.getGroupSpan.call(this.view, row, oldIndex), \r
+            newGroup = Ext.ux.grid.ColumnHeaderGroup.prototype.getGroupSpan.call(this.view, row, newIndex),\r
+            oldIndex = oldGroup.col;\r
+            newIndex = newGroup.col + (pt == "after" ? newGroup.colspan : 0);\r
+        if(newIndex >= oldGroup.col && newIndex <= oldGroup.col + oldGroup.colspan){\r
+            return false;\r
+        }\r
+        var parentGroup = Ext.ux.grid.ColumnHeaderGroup.prototype.getGroupSpan.call(this.view, row - 1, oldIndex);\r
+        if(newIndex < parentGroup.col || newIndex > parentGroup.col + parentGroup.colspan){\r
+            return false;\r
+        }\r
+        return {\r
+            r: r,\r
+            px: px,\r
+            pt: pt,\r
+            row: row,\r
+            oldIndex: oldIndex,\r
+            newIndex: newIndex,\r
+            colspan: oldGroup.colspan\r
+        };\r
+    }\r
+});Ext.ns('Ext.ux.tree');\r
 \r
 /**\r
  * @class Ext.ux.tree.ColumnTree\r
@@ -1162,7 +1638,8 @@ Ext.ux.grid.GridFilters = Ext.extend(Ext.util.Observable, {
     updateBuffer : 500,\r
 \r
     /** @private */\r
-    constructor : function (config) {          \r
+    constructor : function (config) {\r
+        config = config || {};\r
         this.deferredUpdate = new Ext.util.DelayedTask(this.reload, this);\r
         this.filters = new Ext.util.MixedCollection();\r
         this.filters.getKey = function (o) {\r
@@ -1177,8 +1654,12 @@ Ext.ux.grid.GridFilters = Ext.extend(Ext.util.Observable, {
     init : function (grid) {\r
         if (grid instanceof Ext.grid.GridPanel) {\r
             this.grid = grid;\r
-\r
+            \r
             this.bindStore(this.grid.getStore(), true);\r
+            // assumes no filters were passed in the constructor, so try and use ones from the colModel\r
+            if(this.filters.getCount() == 0){\r
+                this.addFilters(this.grid.getColumnModel());\r
+            }\r
           \r
             this.grid.filters = this;\r
              \r
@@ -1429,7 +1910,7 @@ TODO: lazy rendering
      */\r
     onBeforeLoad : function (store, options) {\r
         options.params = options.params || {};\r
-        this.cleanParams(options.params);              \r
+        this.cleanParams(options.params);       \r
         var params = this.buildQuery(this.getFilterData());\r
         Ext.apply(options.params, params);\r
     },\r
@@ -1633,7 +2114,7 @@ filters[0][data][value]="someValue3"&
      * </ul></div>\r
      * Override this method to customize the format of the filter query for remote requests.\r
      * @param {Array} filters A collection of objects representing active filters and their configuration.\r
-     *           Each element will take the form of {field: dataIndex, data: filterConf}. dataIndex is not assured\r
+     *    Each element will take the form of {field: dataIndex, data: filterConf}. dataIndex is not assured\r
      *    to be unique as any one filter may be a composite of more basic filters for the same dataIndex.\r
      * @return {Object} Query keys and values\r
      */\r
@@ -3495,20 +3976,19 @@ Ext.ux.GroupTab = Ext.extend(Ext.Container, {
      */\r
     setActiveTab : function(item){\r
         item = this.getComponent(item);\r
-        if(!item || this.fireEvent('beforetabchange', this, item, this.activeTab) === false){\r
-            return;\r
+        if(!item){\r
+            return false;\r
         }\r
         if(!this.rendered){\r
             this.activeTab = item;\r
-            return;\r
+            return true;\r
         }\r
-        if(this.activeTab != item){\r
+        if(this.activeTab != item && this.fireEvent('beforetabchange', this, item, this.activeTab) !== false){\r
             if(this.activeTab && this.activeTab != this.mainItem){\r
                 var oldEl = this.getTabEl(this.activeTab);\r
                 if(oldEl){\r
                     Ext.fly(oldEl).removeClass('x-grouptabs-strip-active');\r
                 }\r
-                this.activeTab.fireEvent('deactivate', this.activeTab);\r
             }\r
             var el = this.getTabEl(item);\r
             Ext.fly(el).addClass('x-grouptabs-strip-active');\r
@@ -3523,9 +4003,10 @@ Ext.ux.GroupTab = Ext.extend(Ext.Container, {
                 this.scrollToTab(item, this.animScroll);\r
             }\r
 \r
-            item.fireEvent('activate', item);\r
             this.fireEvent('tabchange', this, item);\r
+            return true;\r
         }\r
+        return false;\r
     },\r
     \r
     getTabEl: function(item){\r
@@ -3734,7 +4215,7 @@ Ext.ux.GroupTabPanel = Ext.extend(Ext.TabPanel, {
         \r
         this.on('beforeadd', function(gtp, item, index){\r
             this.initGroup(item, index);\r
-        });          \r
+        });                 \r
     },\r
     \r
     initEvents : function() {\r
@@ -3756,8 +4237,8 @@ Ext.ux.GroupTabPanel = Ext.extend(Ext.TabPanel, {
         var beforeEl = (this.tabPosition=='bottom' ? this.stripWrap : null);\r
         this.strip = new Ext.Element(this.stripWrap.dom.firstChild);\r
 \r
-        this.header.addClass('x-grouptabs-panel-header');\r
-        this.bwrap.addClass('x-grouptabs-bwrap');\r
+               this.header.addClass('x-grouptabs-panel-header');\r
+               this.bwrap.addClass('x-grouptabs-bwrap');\r
         this.body.addClass('x-tab-panel-body-'+this.tabPosition + ' x-grouptabs-panel-body');\r
 \r
         if (!this.groupTpl) {\r
@@ -3842,6 +4323,7 @@ Ext.ux.GroupTabPanel = Ext.extend(Ext.TabPanel, {
             groupEl = this.getGroupEl(groupEl);\r
         }\r
         Ext.fly(groupEl).addClass('x-grouptabs-expanded');\r
+               this.syncTabJoint();\r
     },\r
     \r
     toggleGroup: function(groupEl){\r
@@ -3849,9 +4331,17 @@ Ext.ux.GroupTabPanel = Ext.extend(Ext.TabPanel, {
             groupEl = this.getGroupEl(groupEl);\r
         }        \r
         Ext.fly(groupEl).toggleClass('x-grouptabs-expanded');\r
-        this.syncTabJoint();\r
+               this.syncTabJoint();\r
     },    \r
-    \r
+\r
+    collapseGroup: function(groupEl){\r
+        if(groupEl.isXType) {\r
+            groupEl = this.getGroupEl(groupEl);\r
+        }\r
+        Ext.fly(groupEl).removeClass('x-grouptabs-expanded');\r
+               this.syncTabJoint();\r
+    },\r
+        \r
     syncTabJoint: function(groupEl){\r
         if (!this.tabJoint) {\r
             return;\r
@@ -3860,7 +4350,7 @@ Ext.ux.GroupTabPanel = Ext.extend(Ext.TabPanel, {
         groupEl = groupEl || this.getGroupEl(this.activeGroup);\r
         if(groupEl) {\r
             this.tabJoint.setHeight(Ext.fly(groupEl).getHeight() - 2); \r
-            \r
+                       \r
             var y = Ext.isGecko2 ? 0 : 1;\r
             if (this.tabPosition == 'left'){\r
                 this.tabJoint.alignTo(groupEl, 'tl-tr', [-2,y]);\r
@@ -3903,6 +4393,7 @@ Ext.ux.GroupTabPanel = Ext.extend(Ext.TabPanel, {
             tl = this.createCorner(el, 'top-' + this.tabPosition),\r
             bl = this.createCorner(el, 'bottom-' + this.tabPosition);\r
 \r
+        group.tabEl = el;\r
         if (group.expanded) {\r
             this.expandGroup(el);\r
         }\r
@@ -3923,20 +4414,19 @@ Ext.ux.GroupTabPanel = Ext.extend(Ext.TabPanel, {
     \r
     setActiveGroup : function(group) {\r
         group = this.getComponent(group);\r
-        if(!group || this.fireEvent('beforegroupchange', this, group, this.activeGroup) === false){\r
-            return;\r
+        if(!group){\r
+            return false;\r
         }\r
         if(!this.rendered){\r
             this.activeGroup = group;\r
-            return;\r
+            return true;\r
         }\r
-        if(this.activeGroup != group){\r
+        if(this.activeGroup != group && this.fireEvent('beforegroupchange', this, group, this.activeGroup) !== false){\r
             if(this.activeGroup){\r
                 var oldEl = this.getGroupEl(this.activeGroup);\r
                 if(oldEl){\r
                     Ext.fly(oldEl).removeClass('x-grouptabs-strip-active');\r
                 }\r
-                this.activeGroup.fireEvent('deactivate', this.activeGroup);\r
             }\r
 \r
             var groupEl = this.getGroupEl(group);\r
@@ -3948,18 +4438,20 @@ Ext.ux.GroupTabPanel = Ext.extend(Ext.TabPanel, {
             this.layout.setActiveItem(group);\r
             this.syncTabJoint(groupEl);\r
 \r
-            group.fireEvent('activate', group);\r
             this.fireEvent('groupchange', this, group);\r
-        }        \r
+            return true;\r
+        }\r
+        return false; \r
     },\r
     \r
     onGroupBeforeTabChange: function(group, newTab, oldTab){\r
         if(group !== this.activeGroup || newTab !== oldTab) {\r
             this.strip.select('.x-grouptabs-sub > li.x-grouptabs-strip-active', true).removeClass('x-grouptabs-strip-active');\r
         } \r
-        \r
         this.expandGroup(this.getGroupEl(group));\r
-        this.setActiveGroup(group);\r
+        if(group !== this.activeGroup) {\r
+            return this.setActiveGroup(group);\r
+        }        \r
     },\r
     \r
     getFrameHeight: function(){\r
@@ -4304,95 +4796,862 @@ Ext.reg('itemselector', Ext.ux.form.ItemSelector);
 \r
 //backwards compat\r
 Ext.ux.ItemSelector = Ext.ux.form.ItemSelector;\r
-Ext.ns('Ext.ux.form');\r
+Ext.ns('Ext.ux.grid');\r
 \r
-/**\r
- * @class Ext.ux.form.MultiSelect\r
- * @extends Ext.form.Field\r
- * A control that allows selection and form submission of multiple list items.\r
- *\r
- *  @history\r
- *    2008-06-19 bpm Original code contributed by Toby Stuart (with contributions from Robert Williams)\r
- *    2008-06-19 bpm Docs and demo code clean up\r
- *\r
- * @constructor\r
- * Create a new MultiSelect\r
- * @param {Object} config Configuration options\r
- * @xtype multiselect \r
- */\r
-Ext.ux.form.MultiSelect = Ext.extend(Ext.form.Field,  {\r
-    /**\r
-     * @cfg {String} legend Wraps the object with a fieldset and specified legend.\r
-     */\r
-    /**\r
-     * @cfg {Ext.ListView} view The {@link Ext.ListView} used to render the multiselect list.\r
-     */\r
-    /**\r
-     * @cfg {String/Array} dragGroup The ddgroup name(s) for the MultiSelect DragZone (defaults to undefined).\r
-     */\r
-    /**\r
-     * @cfg {String/Array} dropGroup The ddgroup name(s) for the MultiSelect DropZone (defaults to undefined).\r
-     */\r
-    /**\r
-     * @cfg {Boolean} ddReorder Whether the items in the MultiSelect list are drag/drop reorderable (defaults to false).\r
-     */\r
-    ddReorder:false,\r
-    /**\r
-     * @cfg {Object/Array} tbar The top toolbar of the control. This can be a {@link Ext.Toolbar} object, a\r
-     * toolbar config, or an array of buttons/button configs to be added to the toolbar.\r
-     */\r
-    /**\r
-     * @cfg {String} appendOnly True if the list should only allow append drops when drag/drop is enabled\r
-     * (use for lists which are sorted, defaults to false).\r
-     */\r
-    appendOnly:false,\r
-    /**\r
-     * @cfg {Number} width Width in pixels of the control (defaults to 100).\r
-     */\r
-    width:100,\r
-    /**\r
-     * @cfg {Number} height Height in pixels of the control (defaults to 100).\r
-     */\r
-    height:100,\r
-    /**\r
-     * @cfg {String/Number} displayField Name/Index of the desired display field in the dataset (defaults to 0).\r
-     */\r
-    displayField:0,\r
-    /**\r
-     * @cfg {String/Number} valueField Name/Index of the desired value field in the dataset (defaults to 1).\r
-     */\r
-    valueField:1,\r
-    /**\r
-     * @cfg {Boolean} allowBlank False to require at least one item in the list to be selected, true to allow no\r
-     * selection (defaults to true).\r
-     */\r
-    allowBlank:true,\r
-    /**\r
-     * @cfg {Number} minSelections Minimum number of selections allowed (defaults to 0).\r
-     */\r
-    minSelections:0,\r
-    /**\r
-     * @cfg {Number} maxSelections Maximum number of selections allowed (defaults to Number.MAX_VALUE).\r
-     */\r
-    maxSelections:Number.MAX_VALUE,\r
-    /**\r
-     * @cfg {String} blankText Default text displayed when the control contains no items (defaults to the same value as\r
-     * {@link Ext.form.TextField#blankText}.\r
-     */\r
-    blankText:Ext.form.TextField.prototype.blankText,\r
-    /**\r
-     * @cfg {String} minSelectionsText Validation message displayed when {@link #minSelections} is not met (defaults to 'Minimum {0}\r
-     * item(s) required').  The {0} token will be replaced by the value of {@link #minSelections}.\r
-     */\r
-    minSelectionsText:'Minimum {0} item(s) required',\r
-    /**\r
-     * @cfg {String} maxSelectionsText Validation message displayed when {@link #maxSelections} is not met (defaults to 'Maximum {0}\r
-     * item(s) allowed').  The {0} token will be replaced by the value of {@link #maxSelections}.\r
-     */\r
-    maxSelectionsText:'Maximum {0} item(s) allowed',\r
-    /**\r
-     * @cfg {String} delimiter The string used to delimit between items when set or returned as a string of values\r
-     * (defaults to ',').\r
+Ext.ux.grid.LockingGridView = Ext.extend(Ext.grid.GridView, {\r
+    lockText : 'Lock',\r
+    unlockText : 'Unlock',\r
+    rowBorderWidth : 1,\r
+    lockedBorderWidth : 1,\r
+    /*\r
+     * This option ensures that height between the rows is synchronized\r
+     * between the locked and unlocked sides. This option only needs to be used\r
+     * when the row heights isn't predictable.\r
+     */\r
+    syncHeights: false,\r
+    initTemplates : function(){\r
+        var ts = this.templates || {};\r
+        if(!ts.master){\r
+            ts.master = new Ext.Template(\r
+                '<div class="x-grid3" hidefocus="true">',\r
+                    '<div class="x-grid3-locked">',\r
+                        '<div class="x-grid3-header"><div class="x-grid3-header-inner"><div class="x-grid3-header-offset" style="{lstyle}">{lockedHeader}</div></div><div class="x-clear"></div></div>',\r
+                        '<div class="x-grid3-scroller"><div class="x-grid3-body" style="{lstyle}">{lockedBody}</div><div class="x-grid3-scroll-spacer"></div></div>',\r
+                    '</div>',\r
+                    '<div class="x-grid3-viewport x-grid3-unlocked">',\r
+                        '<div class="x-grid3-header"><div class="x-grid3-header-inner"><div class="x-grid3-header-offset" style="{ostyle}">{header}</div></div><div class="x-clear"></div></div>',\r
+                        '<div class="x-grid3-scroller"><div class="x-grid3-body" style="{bstyle}">{body}</div><a href="#" class="x-grid3-focus" tabIndex="-1"></a></div>',\r
+                    '</div>',\r
+                    '<div class="x-grid3-resize-marker">&#160;</div>',\r
+                    '<div class="x-grid3-resize-proxy">&#160;</div>',\r
+                '</div>'\r
+            );\r
+        }\r
+        this.templates = ts;\r
+        Ext.ux.grid.LockingGridView.superclass.initTemplates.call(this);\r
+    },\r
+    getEditorParent : function(ed){\r
+        return this.el.dom;\r
+    },\r
+    initElements : function(){\r
+        var E = Ext.Element;\r
+        var el = this.grid.getGridEl().dom.firstChild;\r
+        var cs = el.childNodes;\r
+        this.el = new E(el);\r
+        this.lockedWrap = new E(cs[0]);\r
+        this.lockedHd = new E(this.lockedWrap.dom.firstChild);\r
+        this.lockedInnerHd = this.lockedHd.dom.firstChild;\r
+        this.lockedScroller = new E(this.lockedWrap.dom.childNodes[1]);\r
+        this.lockedBody = new E(this.lockedScroller.dom.firstChild);\r
+        this.mainWrap = new E(cs[1]);\r
+        this.mainHd = new E(this.mainWrap.dom.firstChild);\r
+        if(this.grid.hideHeaders){\r
+            this.lockedHd.setDisplayed(false);\r
+            this.mainHd.setDisplayed(false);\r
+        }\r
+        this.innerHd = this.mainHd.dom.firstChild;\r
+        this.scroller = new E(this.mainWrap.dom.childNodes[1]);\r
+        if(this.forceFit){\r
+            this.scroller.setStyle('overflow-x', 'hidden');\r
+        }\r
+        this.mainBody = new E(this.scroller.dom.firstChild);\r
+        this.focusEl = new E(this.scroller.dom.childNodes[1]);\r
+        this.focusEl.swallowEvent('click', true);\r
+        this.resizeMarker = new E(cs[2]);\r
+        this.resizeProxy = new E(cs[3]);\r
+    },\r
+    \r
+    getLockedRows : function(){\r
+        return this.hasRows() ? this.lockedBody.dom.childNodes : [];\r
+    },\r
+    \r
+    getLockedRow : function(row){\r
+        return this.getLockedRows()[row];\r
+    },\r
+    \r
+    getCell : function(row, col){\r
+        var llen = this.cm.getLockedCount();\r
+        if(col < llen){\r
+            return this.getLockedRow(row).getElementsByTagName('td')[col];\r
+        }\r
+        return Ext.ux.grid.LockingGridView.superclass.getCell.call(this, row, col - llen);\r
+    },\r
+    \r
+    getHeaderCell : function(index){\r
+        var llen = this.cm.getLockedCount();\r
+        if(index < llen){\r
+            return this.lockedHd.dom.getElementsByTagName('td')[index];\r
+        }\r
+        return Ext.ux.grid.LockingGridView.superclass.getHeaderCell.call(this, index - llen);\r
+    },\r
+    \r
+    addRowClass : function(row, cls){\r
+        var r = this.getLockedRow(row);\r
+        if(r){\r
+            this.fly(r).addClass(cls);\r
+        }\r
+        Ext.ux.grid.LockingGridView.superclass.addRowClass.call(this, row, cls);\r
+    },\r
+    \r
+    removeRowClass : function(row, cls){\r
+        var r = this.getLockedRow(row);\r
+        if(r){\r
+            this.fly(r).removeClass(cls);\r
+        }\r
+        Ext.ux.grid.LockingGridView.superclass.removeRowClass.call(this, row, cls);\r
+    },\r
+    \r
+    removeRow : function(row) {\r
+        Ext.removeNode(this.getLockedRow(row));\r
+        Ext.ux.grid.LockingGridView.superclass.removeRow.call(this, row);\r
+    },\r
+    \r
+    removeRows : function(firstRow, lastRow){\r
+        var bd = this.lockedBody.dom;\r
+        for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){\r
+            Ext.removeNode(bd.childNodes[firstRow]);\r
+        }\r
+        Ext.ux.grid.LockingGridView.superclass.removeRows.call(this, firstRow, lastRow);\r
+    },\r
+    \r
+    syncScroll : function(e){\r
+        var mb = this.scroller.dom;\r
+        this.lockedScroller.dom.scrollTop = mb.scrollTop;\r
+        Ext.ux.grid.LockingGridView.superclass.syncScroll.call(this, e);\r
+    },\r
+    \r
+    updateSortIcon : function(col, dir){\r
+        var sc = this.sortClasses,\r
+            lhds = this.lockedHd.select('td').removeClass(sc),\r
+            hds = this.mainHd.select('td').removeClass(sc),\r
+            llen = this.cm.getLockedCount(),\r
+            cls = sc[dir == 'DESC' ? 1 : 0];\r
+        if(col < llen){\r
+            lhds.item(col).addClass(cls);\r
+        }else{\r
+            hds.item(col - llen).addClass(cls);\r
+        }\r
+    },\r
+    \r
+    updateAllColumnWidths : function(){\r
+        var tw = this.getTotalWidth(),\r
+            clen = this.cm.getColumnCount(),\r
+            lw = this.getLockedWidth(),\r
+            llen = this.cm.getLockedCount(),\r
+            ws = [], len, i;\r
+        this.updateLockedWidth();\r
+        for(i = 0; i < clen; i++){\r
+            ws[i] = this.getColumnWidth(i);\r
+            var hd = this.getHeaderCell(i);\r
+            hd.style.width = ws[i];\r
+        }\r
+        var lns = this.getLockedRows(), ns = this.getRows(), row, trow, j;\r
+        for(i = 0, len = ns.length; i < len; i++){\r
+            row = lns[i];\r
+            row.style.width = lw;\r
+            if(row.firstChild){\r
+                row.firstChild.style.width = lw;\r
+                trow = row.firstChild.rows[0];\r
+                for (j = 0; j < llen; j++) {\r
+                   trow.childNodes[j].style.width = ws[j];\r
+                }\r
+            }\r
+            row = ns[i];\r
+            row.style.width = tw;\r
+            if(row.firstChild){\r
+                row.firstChild.style.width = tw;\r
+                trow = row.firstChild.rows[0];\r
+                for (j = llen; j < clen; j++) {\r
+                   trow.childNodes[j - llen].style.width = ws[j];\r
+                }\r
+            }\r
+        }\r
+        this.onAllColumnWidthsUpdated(ws, tw);\r
+        this.syncHeaderHeight();\r
+    },\r
+    \r
+    updateColumnWidth : function(col, width){\r
+        var w = this.getColumnWidth(col),\r
+            llen = this.cm.getLockedCount(),\r
+            ns, rw, c, row;\r
+        this.updateLockedWidth();\r
+        if(col < llen){\r
+            ns = this.getLockedRows();\r
+            rw = this.getLockedWidth();\r
+            c = col;\r
+        }else{\r
+            ns = this.getRows();\r
+            rw = this.getTotalWidth();\r
+            c = col - llen;\r
+        }\r
+        var hd = this.getHeaderCell(col);\r
+        hd.style.width = w;\r
+        for(var i = 0, len = ns.length; i < len; i++){\r
+            row = ns[i];\r
+            row.style.width = rw;\r
+            if(row.firstChild){\r
+                row.firstChild.style.width = rw;\r
+                row.firstChild.rows[0].childNodes[c].style.width = w;\r
+            }\r
+        }\r
+        this.onColumnWidthUpdated(col, w, this.getTotalWidth());\r
+        this.syncHeaderHeight();\r
+    },\r
+    \r
+    updateColumnHidden : function(col, hidden){\r
+        var llen = this.cm.getLockedCount(),\r
+            ns, rw, c, row,\r
+            display = hidden ? 'none' : '';\r
+        this.updateLockedWidth();\r
+        if(col < llen){\r
+            ns = this.getLockedRows();\r
+            rw = this.getLockedWidth();\r
+            c = col;\r
+        }else{\r
+            ns = this.getRows();\r
+            rw = this.getTotalWidth();\r
+            c = col - llen;\r
+        }\r
+        var hd = this.getHeaderCell(col);\r
+        hd.style.display = display;\r
+        for(var i = 0, len = ns.length; i < len; i++){\r
+            row = ns[i];\r
+            row.style.width = rw;\r
+            if(row.firstChild){\r
+                row.firstChild.style.width = rw;\r
+                row.firstChild.rows[0].childNodes[c].style.display = display;\r
+            }\r
+        }\r
+        this.onColumnHiddenUpdated(col, hidden, this.getTotalWidth());\r
+        delete this.lastViewWidth;\r
+        this.layout();\r
+    },\r
+    \r
+    doRender : function(cs, rs, ds, startRow, colCount, stripe){\r
+        var ts = this.templates, ct = ts.cell, rt = ts.row, last = colCount-1,\r
+            tstyle = 'width:'+this.getTotalWidth()+';',\r
+            lstyle = 'width:'+this.getLockedWidth()+';',\r
+            buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r;\r
+        for(var j = 0, len = rs.length; j < len; j++){\r
+            r = rs[j]; cb = []; lcb = [];\r
+            var rowIndex = (j+startRow);\r
+            for(var i = 0; i < colCount; i++){\r
+                c = cs[i];\r
+                p.id = c.id;\r
+                p.css = (i === 0 ? 'x-grid3-cell-first ' : (i == last ? 'x-grid3-cell-last ' : '')) +\r
+                    (this.cm.config[i].cellCls ? ' ' + this.cm.config[i].cellCls : '');\r
+                p.attr = p.cellAttr = '';\r
+                p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);\r
+                p.style = c.style;\r
+                if(Ext.isEmpty(p.value)){\r
+                    p.value = '&#160;';\r
+                }\r
+                if(this.markDirty && r.dirty && Ext.isDefined(r.modified[c.name])){\r
+                    p.css += ' x-grid3-dirty-cell';\r
+                }\r
+                if(c.locked){\r
+                    lcb[lcb.length] = ct.apply(p);\r
+                }else{\r
+                    cb[cb.length] = ct.apply(p);\r
+                }\r
+            }\r
+            var alt = [];\r
+            if(stripe && ((rowIndex+1) % 2 === 0)){\r
+                alt[0] = 'x-grid3-row-alt';\r
+            }\r
+            if(r.dirty){\r
+                alt[1] = ' x-grid3-dirty-row';\r
+            }\r
+            rp.cols = colCount;\r
+            if(this.getRowClass){\r
+                alt[2] = this.getRowClass(r, rowIndex, rp, ds);\r
+            }\r
+            rp.alt = alt.join(' ');\r
+            rp.cells = cb.join('');\r
+            rp.tstyle = tstyle;\r
+            buf[buf.length] = rt.apply(rp);\r
+            rp.cells = lcb.join('');\r
+            rp.tstyle = lstyle;\r
+            lbuf[lbuf.length] = rt.apply(rp);\r
+        }\r
+        return [buf.join(''), lbuf.join('')];\r
+    },\r
+    processRows : function(startRow, skipStripe){\r
+        if(!this.ds || this.ds.getCount() < 1){\r
+            return;\r
+        }\r
+        var rows = this.getRows(),\r
+            lrows = this.getLockedRows(),\r
+            row, lrow;\r
+        skipStripe = skipStripe || !this.grid.stripeRows;\r
+        startRow = startRow || 0;\r
+        for(var i = 0, len = rows.length; i < len; ++i){\r
+            row = rows[i];\r
+            lrow = lrows[i];\r
+            row.rowIndex = i;\r
+            lrow.rowIndex = i;\r
+            if(!skipStripe){\r
+                row.className = row.className.replace(this.rowClsRe, ' ');\r
+                lrow.className = lrow.className.replace(this.rowClsRe, ' ');\r
+                if ((idx + 1) % 2 === 0){\r
+                    row.className += ' x-grid3-row-alt';\r
+                    lrow.className += ' x-grid3-row-alt';\r
+                }\r
+            }\r
+            if(this.syncHeights){\r
+                var el1 = Ext.get(row),\r
+                    el2 = Ext.get(lrow),\r
+                    h1 = el1.getHeight(),\r
+                    h2 = el2.getHeight();\r
+                \r
+                if(h1 > h2){\r
+                    el2.setHeight(h1);    \r
+                }else if(h2 > h1){\r
+                    el1.setHeight(h2);\r
+                }\r
+            }\r
+        }\r
+        if(startRow === 0){\r
+            Ext.fly(rows[0]).addClass(this.firstRowCls);\r
+            Ext.fly(lrows[0]).addClass(this.firstRowCls);\r
+        }\r
+        Ext.fly(rows[rows.length - 1]).addClass(this.lastRowCls);\r
+        Ext.fly(lrows[lrows.length - 1]).addClass(this.lastRowCls);\r
+    },\r
+    \r
+    afterRender : function(){\r
+        if(!this.ds || !this.cm){\r
+            return;\r
+        }\r
+        var bd = this.renderRows() || ['&#160;', '&#160;'];\r
+        this.mainBody.dom.innerHTML = bd[0];\r
+        this.lockedBody.dom.innerHTML = bd[1];\r
+        this.processRows(0, true);\r
+        if(this.deferEmptyText !== true){\r
+            this.applyEmptyText();\r
+        }\r
+    },\r
+    \r
+    renderUI : function(){\r
+        var header = this.renderHeaders();\r
+        var body = this.templates.body.apply({rows:'&#160;'});\r
+        var html = this.templates.master.apply({\r
+            body: body,\r
+            header: header[0],\r
+            ostyle: 'width:'+this.getOffsetWidth()+';',\r
+            bstyle: 'width:'+this.getTotalWidth()+';',\r
+            lockedBody: body,\r
+            lockedHeader: header[1],\r
+            lstyle: 'width:'+this.getLockedWidth()+';'\r
+        });\r
+        var g = this.grid;\r
+        g.getGridEl().dom.innerHTML = html;\r
+        this.initElements();\r
+        Ext.fly(this.innerHd).on('click', this.handleHdDown, this);\r
+        Ext.fly(this.lockedInnerHd).on('click', this.handleHdDown, this);\r
+        this.mainHd.on({\r
+            scope: this,\r
+            mouseover: this.handleHdOver,\r
+            mouseout: this.handleHdOut,\r
+            mousemove: this.handleHdMove\r
+        });\r
+        this.lockedHd.on({\r
+            scope: this,\r
+            mouseover: this.handleHdOver,\r
+            mouseout: this.handleHdOut,\r
+            mousemove: this.handleHdMove\r
+        });\r
+        this.scroller.on('scroll', this.syncScroll,  this);\r
+        if(g.enableColumnResize !== false){\r
+            this.splitZone = new Ext.grid.GridView.SplitDragZone(g, this.mainHd.dom);\r
+            this.splitZone.setOuterHandleElId(Ext.id(this.lockedHd.dom));\r
+            this.splitZone.setOuterHandleElId(Ext.id(this.mainHd.dom));\r
+        }\r
+        if(g.enableColumnMove){\r
+            this.columnDrag = new Ext.grid.GridView.ColumnDragZone(g, this.innerHd);\r
+            this.columnDrag.setOuterHandleElId(Ext.id(this.lockedInnerHd));\r
+            this.columnDrag.setOuterHandleElId(Ext.id(this.innerHd));\r
+            this.columnDrop = new Ext.grid.HeaderDropZone(g, this.mainHd.dom);\r
+        }\r
+        if(g.enableHdMenu !== false){\r
+            this.hmenu = new Ext.menu.Menu({id: g.id + '-hctx'});\r
+            this.hmenu.add(\r
+                {itemId: 'asc', text: this.sortAscText, cls: 'xg-hmenu-sort-asc'},\r
+                {itemId: 'desc', text: this.sortDescText, cls: 'xg-hmenu-sort-desc'}\r
+            );\r
+            if(this.grid.enableColLock !== false){\r
+                this.hmenu.add('-',\r
+                    {itemId: 'lock', text: this.lockText, cls: 'xg-hmenu-lock'},\r
+                    {itemId: 'unlock', text: this.unlockText, cls: 'xg-hmenu-unlock'}\r
+                );\r
+            }\r
+            if(g.enableColumnHide !== false){\r
+                this.colMenu = new Ext.menu.Menu({id:g.id + '-hcols-menu'});\r
+                this.colMenu.on({\r
+                    scope: this,\r
+                    beforeshow: this.beforeColMenuShow,\r
+                    itemclick: this.handleHdMenuClick\r
+                });\r
+                this.hmenu.add('-', {\r
+                    itemId:'columns',\r
+                    hideOnClick: false,\r
+                    text: this.columnsText,\r
+                    menu: this.colMenu,\r
+                    iconCls: 'x-cols-icon'\r
+                });\r
+            }\r
+            this.hmenu.on('itemclick', this.handleHdMenuClick, this);\r
+        }\r
+        if(g.trackMouseOver){\r
+            this.mainBody.on({\r
+                scope: this,\r
+                mouseover: this.onRowOver,\r
+                mouseout: this.onRowOut\r
+            });\r
+            this.lockedBody.on({\r
+                scope: this,\r
+                mouseover: this.onRowOver,\r
+                mouseout: this.onRowOut\r
+            });\r
+        }\r
+        \r
+        if(g.enableDragDrop || g.enableDrag){\r
+            this.dragZone = new Ext.grid.GridDragZone(g, {\r
+                ddGroup : g.ddGroup || 'GridDD'\r
+            });\r
+        }\r
+        this.updateHeaderSortState();\r
+    },\r
+    \r
+    layout : function(){\r
+        if(!this.mainBody){\r
+            return;\r
+        }\r
+        var g = this.grid;\r
+        var c = g.getGridEl();\r
+        var csize = c.getSize(true);\r
+        var vw = csize.width;\r
+        if(!g.hideHeaders && (vw < 20 || csize.height < 20)){\r
+            return;\r
+        }\r
+        this.syncHeaderHeight();\r
+        if(g.autoHeight){\r
+            this.scroller.dom.style.overflow = 'visible';\r
+            this.lockedScroller.dom.style.overflow = 'visible';\r
+            if(Ext.isWebKit){\r
+                this.scroller.dom.style.position = 'static';\r
+                this.lockedScroller.dom.style.position = 'static';\r
+            }\r
+        }else{\r
+            this.el.setSize(csize.width, csize.height);\r
+            var hdHeight = this.mainHd.getHeight();\r
+            var vh = csize.height - (hdHeight);\r
+        }\r
+        this.updateLockedWidth();\r
+        if(this.forceFit){\r
+            if(this.lastViewWidth != vw){\r
+                this.fitColumns(false, false);\r
+                this.lastViewWidth = vw;\r
+            }\r
+        }else {\r
+            this.autoExpand();\r
+            this.syncHeaderScroll();\r
+        }\r
+        this.onLayout(vw, vh);\r
+    },\r
+    \r
+    getOffsetWidth : function() {\r
+        return (this.cm.getTotalWidth() - this.cm.getTotalLockedWidth() + this.getScrollOffset()) + 'px';\r
+    },\r
+    \r
+    renderHeaders : function(){\r
+        var cm = this.cm,\r
+            ts = this.templates,\r
+            ct = ts.hcell,\r
+            cb = [], lcb = [],\r
+            p = {},\r
+            len = cm.getColumnCount(),\r
+            last = len - 1;\r
+        for(var i = 0; i < len; i++){\r
+            p.id = cm.getColumnId(i);\r
+            p.value = cm.getColumnHeader(i) || '';\r
+            p.style = this.getColumnStyle(i, true);\r
+            p.tooltip = this.getColumnTooltip(i);\r
+            p.css = (i === 0 ? 'x-grid3-cell-first ' : (i == last ? 'x-grid3-cell-last ' : '')) +\r
+                (cm.config[i].headerCls ? ' ' + cm.config[i].headerCls : '');\r
+            if(cm.config[i].align == 'right'){\r
+                p.istyle = 'padding-right:16px';\r
+            } else {\r
+                delete p.istyle;\r
+            }\r
+            if(cm.isLocked(i)){\r
+                lcb[lcb.length] = ct.apply(p);\r
+            }else{\r
+                cb[cb.length] = ct.apply(p);\r
+            }\r
+        }\r
+        return [ts.header.apply({cells: cb.join(''), tstyle:'width:'+this.getTotalWidth()+';'}),\r
+                ts.header.apply({cells: lcb.join(''), tstyle:'width:'+this.getLockedWidth()+';'})];\r
+    },\r
+    \r
+    updateHeaders : function(){\r
+        var hd = this.renderHeaders();\r
+        this.innerHd.firstChild.innerHTML = hd[0];\r
+        this.innerHd.firstChild.style.width = this.getOffsetWidth();\r
+        this.innerHd.firstChild.firstChild.style.width = this.getTotalWidth();\r
+        this.lockedInnerHd.firstChild.innerHTML = hd[1];\r
+        var lw = this.getLockedWidth();\r
+        this.lockedInnerHd.firstChild.style.width = lw;\r
+        this.lockedInnerHd.firstChild.firstChild.style.width = lw;\r
+    },\r
+    \r
+    getResolvedXY : function(resolved){\r
+        if(!resolved){\r
+            return null;\r
+        }\r
+        var c = resolved.cell, r = resolved.row;\r
+        return c ? Ext.fly(c).getXY() : [this.scroller.getX(), Ext.fly(r).getY()];\r
+    },\r
+    \r
+    syncFocusEl : function(row, col, hscroll){\r
+        Ext.ux.grid.LockingGridView.superclass.syncFocusEl.call(this, row, col, col < this.cm.getLockedCount() ? false : hscroll);\r
+    },\r
+    \r
+    ensureVisible : function(row, col, hscroll){\r
+        return Ext.ux.grid.LockingGridView.superclass.ensureVisible.call(this, row, col, col < this.cm.getLockedCount() ? false : hscroll);\r
+    },\r
+    \r
+    insertRows : function(dm, firstRow, lastRow, isUpdate){\r
+        var last = dm.getCount() - 1;\r
+        if(!isUpdate && firstRow === 0 && lastRow >= last){\r
+            this.refresh();\r
+        }else{\r
+            if(!isUpdate){\r
+                this.fireEvent('beforerowsinserted', this, firstRow, lastRow);\r
+            }\r
+            var html = this.renderRows(firstRow, lastRow),\r
+                before = this.getRow(firstRow);\r
+            if(before){\r
+                if(firstRow === 0){\r
+                    this.removeRowClass(0, this.firstRowCls);\r
+                }\r
+                Ext.DomHelper.insertHtml('beforeBegin', before, html[0]);\r
+                before = this.getLockedRow(firstRow);\r
+                Ext.DomHelper.insertHtml('beforeBegin', before, html[1]);\r
+            }else{\r
+                this.removeRowClass(last - 1, this.lastRowCls);\r
+                Ext.DomHelper.insertHtml('beforeEnd', this.mainBody.dom, html[0]);\r
+                Ext.DomHelper.insertHtml('beforeEnd', this.lockedBody.dom, html[1]);\r
+            }\r
+            if(!isUpdate){\r
+                this.fireEvent('rowsinserted', this, firstRow, lastRow);\r
+                this.processRows(firstRow);\r
+            }else if(firstRow === 0 || firstRow >= last){\r
+                this.addRowClass(firstRow, firstRow === 0 ? this.firstRowCls : this.lastRowCls);\r
+            }\r
+        }\r
+        this.syncFocusEl(firstRow);\r
+    },\r
+    \r
+    getColumnStyle : function(col, isHeader){\r
+        var style = !isHeader ? this.cm.config[col].cellStyle || this.cm.config[col].css || '' : this.cm.config[col].headerStyle || '';\r
+        style += 'width:'+this.getColumnWidth(col)+';';\r
+        if(this.cm.isHidden(col)){\r
+            style += 'display:none;';\r
+        }\r
+        var align = this.cm.config[col].align;\r
+        if(align){\r
+            style += 'text-align:'+align+';';\r
+        }\r
+        return style;\r
+    },\r
+    \r
+    getLockedWidth : function() {\r
+        return this.cm.getTotalLockedWidth() + 'px';\r
+    },\r
+    \r
+    getTotalWidth : function() {\r
+        return (this.cm.getTotalWidth() - this.cm.getTotalLockedWidth()) + 'px';\r
+    },\r
+    \r
+    getColumnData : function(){\r
+        var cs = [], cm = this.cm, colCount = cm.getColumnCount();\r
+        for(var i = 0; i < colCount; i++){\r
+            var name = cm.getDataIndex(i);\r
+            cs[i] = {\r
+                name : (!Ext.isDefined(name) ? this.ds.fields.get(i).name : name),\r
+                renderer : cm.getRenderer(i),\r
+                id : cm.getColumnId(i),\r
+                style : this.getColumnStyle(i),\r
+                locked : cm.isLocked(i)\r
+            };\r
+        }\r
+        return cs;\r
+    },\r
+    \r
+    renderBody : function(){\r
+        var markup = this.renderRows() || ['&#160;', '&#160;'];\r
+        return [this.templates.body.apply({rows: markup[0]}), this.templates.body.apply({rows: markup[1]})];\r
+    },\r
+    \r
+    refreshRow : function(record){\r
+        Ext.ux.grid.LockingGridView.superclass.refreshRow.call(this, record);\r
+        var index = Ext.isNumber(record) ? record : this.ds.indexOf(record);\r
+        this.getLockedRow(index).rowIndex = index;\r
+    },\r
+    \r
+    refresh : function(headersToo){\r
+        this.fireEvent('beforerefresh', this);\r
+        this.grid.stopEditing(true);\r
+        var result = this.renderBody();\r
+        this.mainBody.update(result[0]).setWidth(this.getTotalWidth());\r
+        this.lockedBody.update(result[1]).setWidth(this.getLockedWidth());\r
+        if(headersToo === true){\r
+            this.updateHeaders();\r
+            this.updateHeaderSortState();\r
+        }\r
+        this.processRows(0, true);\r
+        this.layout();\r
+        this.applyEmptyText();\r
+        this.fireEvent('refresh', this);\r
+    },\r
+    \r
+    onDenyColumnLock : function(){\r
+\r
+    },\r
+    \r
+    initData : function(ds, cm){\r
+        if(this.cm){\r
+            this.cm.un('columnlockchange', this.onColumnLock, this);\r
+        }\r
+        Ext.ux.grid.LockingGridView.superclass.initData.call(this, ds, cm);\r
+        if(this.cm){\r
+            this.cm.on('columnlockchange', this.onColumnLock, this);\r
+        }\r
+    },\r
+    \r
+    onColumnLock : function(){\r
+        this.refresh(true);\r
+    },\r
+    \r
+    handleHdMenuClick : function(item){\r
+        var index = this.hdCtxIndex,\r
+            cm = this.cm,\r
+            id = item.getItemId(),\r
+            llen = cm.getLockedCount();\r
+        switch(id){\r
+            case 'lock':\r
+                if(cm.getColumnCount(true) <= llen + 1){\r
+                    this.onDenyColumnLock();\r
+                    return;\r
+                }\r
+                if(llen != index){\r
+                    cm.setLocked(index, true, true);\r
+                    cm.moveColumn(index, llen);\r
+                    this.grid.fireEvent('columnmove', index, llen);\r
+                }else{\r
+                    cm.setLocked(index, true);\r
+                }\r
+            break;\r
+            case 'unlock':\r
+                if(llen - 1 != index){\r
+                    cm.setLocked(index, false, true);\r
+                    cm.moveColumn(index, llen - 1);\r
+                    this.grid.fireEvent('columnmove', index, llen - 1);\r
+                }else{\r
+                    cm.setLocked(index, false);\r
+                }\r
+            break;\r
+            default:\r
+                return Ext.ux.grid.LockingGridView.superclass.handleHdMenuClick.call(this, item);\r
+        }\r
+        return true;\r
+    },\r
+    \r
+    handleHdDown : function(e, t){\r
+        Ext.ux.grid.LockingGridView.superclass.handleHdDown.call(this, e, t);\r
+        if(this.grid.enableColLock !== false){\r
+            if(Ext.fly(t).hasClass('x-grid3-hd-btn')){\r
+                var hd = this.findHeaderCell(t),\r
+                    index = this.getCellIndex(hd),\r
+                    ms = this.hmenu.items, cm = this.cm;\r
+                ms.get('lock').setDisabled(cm.isLocked(index));\r
+                ms.get('unlock').setDisabled(!cm.isLocked(index));\r
+            }\r
+        }\r
+    },\r
+    \r
+    syncHeaderHeight: function(){\r
+        this.innerHd.firstChild.firstChild.style.height = 'auto';\r
+        this.lockedInnerHd.firstChild.firstChild.style.height = 'auto';\r
+        var hd = this.innerHd.firstChild.firstChild.offsetHeight,\r
+            lhd = this.lockedInnerHd.firstChild.firstChild.offsetHeight,\r
+            height = (lhd > hd ? lhd : hd) + 'px';\r
+        this.innerHd.firstChild.firstChild.style.height = height;\r
+        this.lockedInnerHd.firstChild.firstChild.style.height = height;\r
+    },\r
+    \r
+    updateLockedWidth: function(){\r
+        var lw = this.cm.getTotalLockedWidth(),\r
+            tw = this.cm.getTotalWidth() - lw,\r
+            csize = this.grid.getGridEl().getSize(true),\r
+            lp = Ext.isBorderBox ? 0 : this.lockedBorderWidth,\r
+            rp = Ext.isBorderBox ? 0 : this.rowBorderWidth,\r
+            vw = (csize.width - lw - lp - rp) + 'px',\r
+            so = this.getScrollOffset();\r
+        if(!this.grid.autoHeight){\r
+            var vh = (csize.height - this.mainHd.getHeight()) + 'px';\r
+            this.lockedScroller.dom.style.height = vh;\r
+            this.scroller.dom.style.height = vh;\r
+        }\r
+        this.lockedWrap.dom.style.width = (lw + rp) + 'px';\r
+        this.scroller.dom.style.width = vw;\r
+        this.mainWrap.dom.style.left = (lw + lp + rp) + 'px';\r
+        if(this.innerHd){\r
+            this.lockedInnerHd.firstChild.style.width = lw + 'px';\r
+            this.lockedInnerHd.firstChild.firstChild.style.width = lw + 'px';\r
+            this.innerHd.style.width = vw;\r
+            this.innerHd.firstChild.style.width = (tw + rp + so) + 'px';\r
+            this.innerHd.firstChild.firstChild.style.width = tw + 'px';\r
+        }\r
+        if(this.mainBody){\r
+            this.lockedBody.dom.style.width = (lw + rp) + 'px';\r
+            this.mainBody.dom.style.width = (tw + rp) + 'px';\r
+        }\r
+    }\r
+});\r
+\r
+Ext.ux.grid.LockingColumnModel = Ext.extend(Ext.grid.ColumnModel, {\r
+    isLocked : function(colIndex){\r
+        return this.config[colIndex].locked === true;\r
+    },\r
+    \r
+    setLocked : function(colIndex, value, suppressEvent){\r
+        if(this.isLocked(colIndex) == value){\r
+            return;\r
+        }\r
+        this.config[colIndex].locked = value;\r
+        if(!suppressEvent){\r
+            this.fireEvent('columnlockchange', this, colIndex, value);\r
+        }\r
+    },\r
+    \r
+    getTotalLockedWidth : function(){\r
+        var totalWidth = 0;\r
+        for(var i = 0, len = this.config.length; i < len; i++){\r
+            if(this.isLocked(i) && !this.isHidden(i)){\r
+                totalWidth += this.getColumnWidth(i);\r
+            }\r
+        }\r
+        return totalWidth;\r
+    },\r
+    \r
+    getLockedCount : function(){\r
+        for(var i = 0, len = this.config.length; i < len; i++){\r
+            if(!this.isLocked(i)){\r
+                return i;\r
+            }\r
+        }\r
+    },\r
+    \r
+    moveColumn : function(oldIndex, newIndex){\r
+        if(oldIndex < newIndex && this.isLocked(oldIndex) && !this.isLocked(newIndex)){\r
+            this.setLocked(oldIndex, false, true);\r
+        }else if(oldIndex > newIndex && !this.isLocked(oldIndex) && this.isLocked(newIndex)){\r
+            this.setLocked(oldIndex, true, true);\r
+        }\r
+        Ext.ux.grid.LockingColumnModel.superclass.moveColumn.apply(this, arguments);\r
+    }\r
+});\r
+Ext.ns('Ext.ux.form');\r
+\r
+/**\r
+ * @class Ext.ux.form.MultiSelect\r
+ * @extends Ext.form.Field\r
+ * A control that allows selection and form submission of multiple list items.\r
+ *\r
+ *  @history\r
+ *    2008-06-19 bpm Original code contributed by Toby Stuart (with contributions from Robert Williams)\r
+ *    2008-06-19 bpm Docs and demo code clean up\r
+ *\r
+ * @constructor\r
+ * Create a new MultiSelect\r
+ * @param {Object} config Configuration options\r
+ * @xtype multiselect \r
+ */\r
+Ext.ux.form.MultiSelect = Ext.extend(Ext.form.Field,  {\r
+    /**\r
+     * @cfg {String} legend Wraps the object with a fieldset and specified legend.\r
+     */\r
+    /**\r
+     * @cfg {Ext.ListView} view The {@link Ext.ListView} used to render the multiselect list.\r
+     */\r
+    /**\r
+     * @cfg {String/Array} dragGroup The ddgroup name(s) for the MultiSelect DragZone (defaults to undefined).\r
+     */\r
+    /**\r
+     * @cfg {String/Array} dropGroup The ddgroup name(s) for the MultiSelect DropZone (defaults to undefined).\r
+     */\r
+    /**\r
+     * @cfg {Boolean} ddReorder Whether the items in the MultiSelect list are drag/drop reorderable (defaults to false).\r
+     */\r
+    ddReorder:false,\r
+    /**\r
+     * @cfg {Object/Array} tbar The top toolbar of the control. This can be a {@link Ext.Toolbar} object, a\r
+     * toolbar config, or an array of buttons/button configs to be added to the toolbar.\r
+     */\r
+    /**\r
+     * @cfg {String} appendOnly True if the list should only allow append drops when drag/drop is enabled\r
+     * (use for lists which are sorted, defaults to false).\r
+     */\r
+    appendOnly:false,\r
+    /**\r
+     * @cfg {Number} width Width in pixels of the control (defaults to 100).\r
+     */\r
+    width:100,\r
+    /**\r
+     * @cfg {Number} height Height in pixels of the control (defaults to 100).\r
+     */\r
+    height:100,\r
+    /**\r
+     * @cfg {String/Number} displayField Name/Index of the desired display field in the dataset (defaults to 0).\r
+     */\r
+    displayField:0,\r
+    /**\r
+     * @cfg {String/Number} valueField Name/Index of the desired value field in the dataset (defaults to 1).\r
+     */\r
+    valueField:1,\r
+    /**\r
+     * @cfg {Boolean} allowBlank False to require at least one item in the list to be selected, true to allow no\r
+     * selection (defaults to true).\r
+     */\r
+    allowBlank:true,\r
+    /**\r
+     * @cfg {Number} minSelections Minimum number of selections allowed (defaults to 0).\r
+     */\r
+    minSelections:0,\r
+    /**\r
+     * @cfg {Number} maxSelections Maximum number of selections allowed (defaults to Number.MAX_VALUE).\r
+     */\r
+    maxSelections:Number.MAX_VALUE,\r
+    /**\r
+     * @cfg {String} blankText Default text displayed when the control contains no items (defaults to the same value as\r
+     * {@link Ext.form.TextField#blankText}.\r
+     */\r
+    blankText:Ext.form.TextField.prototype.blankText,\r
+    /**\r
+     * @cfg {String} minSelectionsText Validation message displayed when {@link #minSelections} is not met (defaults to 'Minimum {0}\r
+     * item(s) required').  The {0} token will be replaced by the value of {@link #minSelections}.\r
+     */\r
+    minSelectionsText:'Minimum {0} item(s) required',\r
+    /**\r
+     * @cfg {String} maxSelectionsText Validation message displayed when {@link #maxSelections} is not met (defaults to 'Maximum {0}\r
+     * item(s) allowed').  The {0} token will be replaced by the value of {@link #maxSelections}.\r
+     */\r
+    maxSelectionsText:'Maximum {0} item(s) allowed',\r
+    /**\r
+     * @cfg {String} delimiter The string used to delimit between items when set or returned as a string of values\r
+     * (defaults to ',').\r
      */\r
     delimiter:',',\r
     /**\r
@@ -4957,8 +6216,8 @@ Ext.ux.data.PagingMemoryProxy = Ext.extend(Ext.data.MemoryProxy, {
             // use integer as params.sort to specify column, since arrays are not named
             // params.sort=0; would also match a array without columns
             var dir = String(params.dir).toUpperCase() == 'DESC' ? -1 : 1;
-            var fn = function(r1, r2){
-                return r1 < r2;
+            var fn = function(v1, v2){
+                return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
             };
             result.records.sort(function(a, b){
                 var v = 0;
@@ -5289,42 +6548,41 @@ Ext.ux.ProgressBarPager  = Ext.extend(Object, {
        },
        //public
        init : function (parent) {
-        
-        if(parent.displayInfo){
-            this.parent = parent;
-            var ind  = parent.items.indexOf(parent.displayItem);
-            parent.remove(parent.displayItem, true);
-            this.progressBar = new Ext.ProgressBar({
-                text    : this.defaultText,
-                width   : this.progBarWidth,
-                animate :  this.defaultAnimCfg
-            });                 
-           
-            parent.displayItem = this.progressBar;
-            
-            parent.add(parent.displayItem); 
-            parent.doLayout();
-            Ext.apply(parent, this.parentOverrides);        
-            
-            this.progressBar.on('render', function(pb) {
+               
+               if(parent.displayInfo){
+                       this.parent = parent;
+                       var ind  = parent.items.indexOf(parent.displayItem);
+                       parent.remove(parent.displayItem, true);
+                       this.progressBar = new Ext.ProgressBar({
+                               text    : this.defaultText,
+                               width   : this.progBarWidth,
+                               animate :  this.defaultAnimCfg
+                       });                                     
+                  
+                       parent.displayItem = this.progressBar;
+                       
+                       parent.add(parent.displayItem); 
+                       parent.doLayout();
+                       Ext.apply(parent, this.parentOverrides);                
+                       
+                       this.progressBar.on('render', function(pb) {
                 pb.mon(pb.getEl().applyStyles('cursor:pointer'), 'click', this.handleProgressBarClick, this);
             }, this, {single: true});
-                        
-        }
-          
-    },
+                                               
+               }
+                 
+       },
        // private
        // This method handles the click for the progress bar
        handleProgressBarClick : function(e){
-               var parent = this.parent;
-               var displayItem = parent.displayItem;
-               
-               var box = this.progressBar.getBox();
-               var xy = e.getXY();
-               var position = xy[0]-box.x;
-               var pages = Math.ceil(parent.store.getTotalCount()/parent.pageSize);
-               
-               var newpage = Math.ceil(position/(displayItem.width/pages));
+               var parent = this.parent,
+                   displayItem = parent.displayItem,
+                   box = this.progressBar.getBox(),
+                   xy = e.getXY(),
+                   position = xy[0]-box.x,
+                   pages = Math.ceil(parent.store.getTotalCount()/parent.pageSize),
+                   newpage = Math.ceil(position/(displayItem.width/pages));
+            
                parent.changePage(newpage);
        },
        
@@ -5334,11 +6592,10 @@ Ext.ux.ProgressBarPager  = Ext.extend(Object, {
                // This method updates the information via the progress bar.
                updateInfo : function(){
                        if(this.displayItem){
-                               var count   = this.store.getCount();
-                               var pgData  = this.getPageData();
-                               var pageNum = this.readPage(pgData);
-                               
-                               var msg    = count == 0 ?
+                               var count = this.store.getCount(),
+                                   pgData = this.getPageData(),
+                                   pageNum = this.readPage(pgData),
+                                   msg = count == 0 ?
                                        this.emptyMsg :
                                        String.format(
                                                this.displayMsg,
@@ -5455,8 +6712,8 @@ Ext.ux.grid.RowEditor = Ext.extend(Ext.Panel, {
             columnresize: this.verifyLayout,
             columnmove: this.refreshFields,
             reconfigure: this.refreshFields,
-            beforedestroy : this.beforedestroy,
-            destroy : this.destroy,
+               beforedestroy : this.beforedestroy,
+               destroy : this.destroy,
             bodyscroll: {
                 buffer: 250,
                 fn: this.positionButtons
@@ -5845,7 +7102,7 @@ Ext.ux.grid.RowEditor = Ext.extend(Ext.Panel, {
                 t.hide();
             }
             t.body.update(msg);
-            t.doAutoWidth();
+            t.doAutoWidth(20);
             t.show();
         }else if(t.rendered){
             t.hide();
@@ -5856,7 +7113,7 @@ Ext.ux.grid.RowEditor = Ext.extend(Ext.Panel, {
         var data = ['<ul>'];
         this.items.each(function(f){
             if(!f.isValid(true)){
-                data.push('<li>', f.activeError, '</li>');
+                data.push('<li>', f.getActiveError(), '</li>');
             }
         });
         data.push('</ul>');
@@ -5864,46 +7121,6 @@ Ext.ux.grid.RowEditor = Ext.extend(Ext.Panel, {
     }
 });
 Ext.preg('roweditor', Ext.ux.grid.RowEditor);
-
-Ext.override(Ext.form.Field, {
-    markInvalid : function(msg){
-        if(!this.rendered || this.preventMark){ // not rendered
-            return;
-        }
-        msg = msg || this.invalidText;
-
-        var mt = this.getMessageHandler();
-        if(mt){
-            mt.mark(this, msg);
-        }else if(this.msgTarget){
-            this.el.addClass(this.invalidClass);
-            var t = Ext.getDom(this.msgTarget);
-            if(t){
-                t.innerHTML = msg;
-                t.style.display = this.msgDisplay;
-            }
-        }
-        this.activeError = msg;
-        this.fireEvent('invalid', this, msg);
-    }
-});
-
-Ext.override(Ext.ToolTip, {
-    doAutoWidth : function(){
-        var bw = this.body.getTextWidth();
-        if(this.title){
-            bw = Math.max(bw, this.header.child('span').getTextWidth(this.title));
-        }
-        bw += this.getFrameWidth() + (this.closable ? 20 : 0) + this.body.getPadding("lr") + 20;
-        this.setWidth(bw.constrain(this.minWidth, this.maxWidth));
-
-        // IE7 repaint bug on initial show
-        if(Ext.isIE7 && !this.repainted){
-            this.el.repaint();
-            this.repainted = true;
-        }
-    }
-});
 Ext.ns('Ext.ux.grid');\r
 \r
 /**\r
@@ -6221,13 +7438,13 @@ Ext.ux.layout.RowLayout = Ext.extend(Ext.layout.ContainerLayout, {
         }
         this.renderAll(ct, this.innerCt);
 
-        var size = target.getViewSize();
+        var size = target.getViewSize(true);
 
         if(size.width < 1 && size.height < 1){ // display none?
             return;
         }
 
-        var h = size.height - target.getPadding('tb'),
+        var h = size.height,
             ph = h;
 
         this.innerCt.setSize({height:h});
@@ -6320,182 +7537,182 @@ Ext.ux.form.SearchField = Ext.extend(Ext.form.TwinTriggerField, {
  * @xtype selectbox\r
  */\r
 Ext.ux.form.SelectBox = Ext.extend(Ext.form.ComboBox, {\r
-    constructor: function(config){\r
-        this.searchResetDelay = 1000;\r
-        config = config || {};\r
-        config = Ext.apply(config || {}, {\r
-            editable: false,\r
-            forceSelection: true,\r
-            rowHeight: false,\r
-            lastSearchTerm: false,\r
-            triggerAction: 'all',\r
-            mode: 'local'\r
-        });\r
-\r
-        Ext.ux.form.SelectBox.superclass.constructor.apply(this, arguments);\r
-\r
-        this.lastSelectedIndex = this.selectedIndex || 0;\r
-    },\r
-\r
-    initEvents : function(){\r
-        Ext.ux.form.SelectBox.superclass.initEvents.apply(this, arguments);\r
-        // you need to use keypress to capture upper/lower case and shift+key, but it doesn't work in IE\r
-        this.el.on('keydown', this.keySearch, this, true);\r
-        this.cshTask = new Ext.util.DelayedTask(this.clearSearchHistory, this);\r
-    },\r
-\r
-    keySearch : function(e, target, options) {\r
-        var raw = e.getKey();\r
-        var key = String.fromCharCode(raw);\r
-        var startIndex = 0;\r
-\r
-        if( !this.store.getCount() ) {\r
-            return;\r
-        }\r
+       constructor: function(config){\r
+               this.searchResetDelay = 1000;\r
+               config = config || {};\r
+               config = Ext.apply(config || {}, {\r
+                       editable: false,\r
+                       forceSelection: true,\r
+                       rowHeight: false,\r
+                       lastSearchTerm: false,\r
+                       triggerAction: 'all',\r
+                       mode: 'local'\r
+               });\r
+\r
+               Ext.ux.form.SelectBox.superclass.constructor.apply(this, arguments);\r
+\r
+               this.lastSelectedIndex = this.selectedIndex || 0;\r
+       },\r
 \r
-        switch(raw) {\r
-            case Ext.EventObject.HOME:\r
-                e.stopEvent();\r
-                this.selectFirst();\r
-                return;\r
+       initEvents : function(){\r
+               Ext.ux.form.SelectBox.superclass.initEvents.apply(this, arguments);\r
+               // you need to use keypress to capture upper/lower case and shift+key, but it doesn't work in IE\r
+               this.el.on('keydown', this.keySearch, this, true);\r
+               this.cshTask = new Ext.util.DelayedTask(this.clearSearchHistory, this);\r
+       },\r
 \r
-            case Ext.EventObject.END:\r
-                e.stopEvent();\r
-                this.selectLast();\r
-                return;\r
+       keySearch : function(e, target, options) {\r
+               var raw = e.getKey();\r
+               var key = String.fromCharCode(raw);\r
+               var startIndex = 0;\r
 \r
-            case Ext.EventObject.PAGEDOWN:\r
-                this.selectNextPage();\r
-                e.stopEvent();\r
-                return;\r
+               if( !this.store.getCount() ) {\r
+                       return;\r
+               }\r
 \r
-            case Ext.EventObject.PAGEUP:\r
-                this.selectPrevPage();\r
-                e.stopEvent();\r
-                return;\r
-        }\r
+               switch(raw) {\r
+                       case Ext.EventObject.HOME:\r
+                               e.stopEvent();\r
+                               this.selectFirst();\r
+                               return;\r
+\r
+                       case Ext.EventObject.END:\r
+                               e.stopEvent();\r
+                               this.selectLast();\r
+                               return;\r
+\r
+                       case Ext.EventObject.PAGEDOWN:\r
+                               this.selectNextPage();\r
+                               e.stopEvent();\r
+                               return;\r
+\r
+                       case Ext.EventObject.PAGEUP:\r
+                               this.selectPrevPage();\r
+                               e.stopEvent();\r
+                               return;\r
+               }\r
 \r
-        // skip special keys other than the shift key\r
-        if( (e.hasModifier() && !e.shiftKey) || e.isNavKeyPress() || e.isSpecialKey() ) {\r
-            return;\r
-        }\r
-        if( this.lastSearchTerm == key ) {\r
-            startIndex = this.lastSelectedIndex;\r
-        }\r
-        this.search(this.displayField, key, startIndex);\r
-        this.cshTask.delay(this.searchResetDelay);\r
-    },\r
+               // skip special keys other than the shift key\r
+               if( (e.hasModifier() && !e.shiftKey) || e.isNavKeyPress() || e.isSpecialKey() ) {\r
+                       return;\r
+               }\r
+               if( this.lastSearchTerm == key ) {\r
+                       startIndex = this.lastSelectedIndex;\r
+               }\r
+               this.search(this.displayField, key, startIndex);\r
+               this.cshTask.delay(this.searchResetDelay);\r
+       },\r
 \r
-    onRender : function(ct, position) {\r
-        this.store.on('load', this.calcRowsPerPage, this);\r
-        Ext.ux.form.SelectBox.superclass.onRender.apply(this, arguments);\r
-        if( this.mode == 'local' ) {\r
+       onRender : function(ct, position) {\r
+               this.store.on('load', this.calcRowsPerPage, this);\r
+               Ext.ux.form.SelectBox.superclass.onRender.apply(this, arguments);\r
+               if( this.mode == 'local' ) {\r
             this.initList();\r
-            this.calcRowsPerPage();\r
-        }\r
-    },\r
-\r
-    onSelect : function(record, index, skipCollapse){\r
-        if(this.fireEvent('beforeselect', this, record, index) !== false){\r
-            this.setValue(record.data[this.valueField || this.displayField]);\r
-            if( !skipCollapse ) {\r
-                this.collapse();\r
-            }\r
-            this.lastSelectedIndex = index + 1;\r
-            this.fireEvent('select', this, record, index);\r
-        }\r
-    },\r
-\r
-    afterRender : function() {\r
-        Ext.ux.form.SelectBox.superclass.afterRender.apply(this, arguments);\r
-        if(Ext.isWebKit) {\r
-            this.el.swallowEvent('mousedown', true);\r
-        }\r
-        this.el.unselectable();\r
-        this.innerList.unselectable();\r
-        this.trigger.unselectable();\r
-        this.innerList.on('mouseup', function(e, target, options) {\r
-            if( target.id && target.id == this.innerList.id ) {\r
-                return;\r
-            }\r
-            this.onViewClick();\r
-        }, this);\r
-\r
-        this.innerList.on('mouseover', function(e, target, options) {\r
-            if( target.id && target.id == this.innerList.id ) {\r
-                return;\r
-            }\r
-            this.lastSelectedIndex = this.view.getSelectedIndexes()[0] + 1;\r
-            this.cshTask.delay(this.searchResetDelay);\r
-        }, this);\r
-\r
-        this.trigger.un('click', this.onTriggerClick, this);\r
-        this.trigger.on('mousedown', function(e, target, options) {\r
-            e.preventDefault();\r
-            this.onTriggerClick();\r
-        }, this);\r
+                       this.calcRowsPerPage();\r
+               }\r
+       },\r
 \r
-        this.on('collapse', function(e, target, options) {\r
-            Ext.getDoc().un('mouseup', this.collapseIf, this);\r
-        }, this, true);\r
+       onSelect : function(record, index, skipCollapse){\r
+               if(this.fireEvent('beforeselect', this, record, index) !== false){\r
+                       this.setValue(record.data[this.valueField || this.displayField]);\r
+                       if( !skipCollapse ) {\r
+                               this.collapse();\r
+                       }\r
+                       this.lastSelectedIndex = index + 1;\r
+                       this.fireEvent('select', this, record, index);\r
+               }\r
+       },\r
 \r
-        this.on('expand', function(e, target, options) {\r
-            Ext.getDoc().on('mouseup', this.collapseIf, this);\r
-        }, this, true);\r
-    },\r
+       afterRender : function() {\r
+               Ext.ux.form.SelectBox.superclass.afterRender.apply(this, arguments);\r
+               if(Ext.isWebKit) {\r
+                       this.el.swallowEvent('mousedown', true);\r
+               }\r
+               this.el.unselectable();\r
+               this.innerList.unselectable();\r
+               this.trigger.unselectable();\r
+               this.innerList.on('mouseup', function(e, target, options) {\r
+                       if( target.id && target.id == this.innerList.id ) {\r
+                               return;\r
+                       }\r
+                       this.onViewClick();\r
+               }, this);\r
+\r
+               this.innerList.on('mouseover', function(e, target, options) {\r
+                       if( target.id && target.id == this.innerList.id ) {\r
+                               return;\r
+                       }\r
+                       this.lastSelectedIndex = this.view.getSelectedIndexes()[0] + 1;\r
+                       this.cshTask.delay(this.searchResetDelay);\r
+               }, this);\r
+\r
+               this.trigger.un('click', this.onTriggerClick, this);\r
+               this.trigger.on('mousedown', function(e, target, options) {\r
+                       e.preventDefault();\r
+                       this.onTriggerClick();\r
+               }, this);\r
+\r
+               this.on('collapse', function(e, target, options) {\r
+                       Ext.getDoc().un('mouseup', this.collapseIf, this);\r
+               }, this, true);\r
+\r
+               this.on('expand', function(e, target, options) {\r
+                       Ext.getDoc().on('mouseup', this.collapseIf, this);\r
+               }, this, true);\r
+       },\r
 \r
-    clearSearchHistory : function() {\r
-        this.lastSelectedIndex = 0;\r
-        this.lastSearchTerm = false;\r
-    },\r
+       clearSearchHistory : function() {\r
+               this.lastSelectedIndex = 0;\r
+               this.lastSearchTerm = false;\r
+       },\r
 \r
-    selectFirst : function() {\r
-        this.focusAndSelect(this.store.data.first());\r
-    },\r
+       selectFirst : function() {\r
+               this.focusAndSelect(this.store.data.first());\r
+       },\r
 \r
-    selectLast : function() {\r
-        this.focusAndSelect(this.store.data.last());\r
-    },\r
+       selectLast : function() {\r
+               this.focusAndSelect(this.store.data.last());\r
+       },\r
 \r
-    selectPrevPage : function() {\r
-        if( !this.rowHeight ) {\r
-            return;\r
-        }\r
-        var index = Math.max(this.selectedIndex-this.rowsPerPage, 0);\r
-        this.focusAndSelect(this.store.getAt(index));\r
-    },\r
+       selectPrevPage : function() {\r
+               if( !this.rowHeight ) {\r
+                       return;\r
+               }\r
+               var index = Math.max(this.selectedIndex-this.rowsPerPage, 0);\r
+               this.focusAndSelect(this.store.getAt(index));\r
+       },\r
 \r
-    selectNextPage : function() {\r
-        if( !this.rowHeight ) {\r
-            return;\r
-        }\r
-        var index = Math.min(this.selectedIndex+this.rowsPerPage, this.store.getCount() - 1);\r
-        this.focusAndSelect(this.store.getAt(index));\r
-    },\r
+       selectNextPage : function() {\r
+               if( !this.rowHeight ) {\r
+                       return;\r
+               }\r
+               var index = Math.min(this.selectedIndex+this.rowsPerPage, this.store.getCount() - 1);\r
+               this.focusAndSelect(this.store.getAt(index));\r
+       },\r
 \r
-    search : function(field, value, startIndex) {\r
-        field = field || this.displayField;\r
-        this.lastSearchTerm = value;\r
-        var index = this.store.find.apply(this.store, arguments);\r
-        if( index !== -1 ) {\r
-            this.focusAndSelect(index);\r
-        }\r
-    },\r
+       search : function(field, value, startIndex) {\r
+               field = field || this.displayField;\r
+               this.lastSearchTerm = value;\r
+               var index = this.store.find.apply(this.store, arguments);\r
+               if( index !== -1 ) {\r
+                       this.focusAndSelect(index);\r
+               }\r
+       },\r
 \r
-    focusAndSelect : function(record) {\r
+       focusAndSelect : function(record) {\r
         var index = Ext.isNumber(record) ? record : this.store.indexOf(record);\r
         this.select(index, this.isExpanded());\r
         this.onSelect(this.store.getAt(index), index, this.isExpanded());\r
-    },\r
+       },\r
 \r
-    calcRowsPerPage : function() {\r
-        if( this.store.getCount() ) {\r
-            this.rowHeight = Ext.fly(this.view.getNode(0)).getHeight();\r
-            this.rowsPerPage = this.maxHeight / this.rowHeight;\r
-        } else {\r
-            this.rowHeight = false;\r
-        }\r
-    }\r
+       calcRowsPerPage : function() {\r
+               if( this.store.getCount() ) {\r
+                       this.rowHeight = Ext.fly(this.view.getNode(0)).getHeight();\r
+                       this.rowsPerPage = this.maxHeight / this.rowHeight;\r
+               } else {\r
+                       this.rowHeight = false;\r
+               }\r
+       }\r
 \r
 });\r
 \r
@@ -7741,18 +8958,35 @@ Ext.extend(Ext.ux.grid.TableGrid, Ext.grid.GridPanel);
 
 //backwards compat
 Ext.grid.TableGrid = Ext.ux.grid.TableGrid;
-
-
+Ext.ns('Ext.ux');
+/**
+ * @class Ext.ux.TabScrollerMenu
+ * @extends Object 
+ * Plugin (ptype = 'tabscrollermenu') for adding a tab scroller menu to tabs.
+ * @constructor 
+ * @param {Object} config Configuration options
+ * @ptype tabscrollermenu
+ */
 Ext.ux.TabScrollerMenu =  Ext.extend(Object, {
+    /**
+     * @cfg {Number} pageSize How many items to allow per submenu.
+     */
        pageSize       : 10,
+    /**
+     * @cfg {Number} maxText How long should the title of each {@link Ext.menu.Item} be.
+     */
        maxText        : 15,
+    /**
+     * @cfg {String} menuPrefixText Text to prefix the submenus.
+     */    
        menuPrefixText : 'Items',
        constructor    : function(config) {
                config = config || {};
                Ext.apply(this, config);
        },
+    //private
        init : function(tabPanel) {
-               Ext.apply(tabPanel, this.tabPanelMethods);
+               Ext.apply(tabPanel, this.parentOverrides);
                
                tabPanel.tabScrollerMenu = this;
                var thisRef = this;
@@ -7800,45 +9034,66 @@ Ext.ux.TabScrollerMenu =  Ext.extend(Object, {
                });
                
        },
-       // public
+    /**
+     * Returns an the current page size (this.pageSize);
+     * @return {Number} this.pageSize The current page size.
+     */
        getPageSize : function() {
                return this.pageSize;
        },
-       // public
-       setPageSize : function(pageSize) {
+    /**
+     * Sets the number of menu items per submenu "page size".
+     * @param {Number} pageSize The page size
+     */
+    setPageSize : function(pageSize) {
                this.pageSize = pageSize;
        },
-       // public
-       getMaxText : function() {
+    /**
+     * Returns the current maxText length;
+     * @return {Number} this.maxText The current max text length.
+     */
+    getMaxText : function() {
                return this.maxText;
        },
-       // public
-       setMaxText : function(t) {
+    /**
+     * Sets the maximum text size for each menu item.
+     * @param {Number} t The max text per each menu item.
+     */
+    setMaxText : function(t) {
                this.maxText = t;
        },
+    /**
+     * Returns the current menu prefix text String.;
+     * @return {String} this.menuPrefixText The current menu prefix text.
+     */
        getMenuPrefixText : function() {
                return this.menuPrefixText;
        },
+    /**
+     * Sets the menu prefix text String.
+     * @param {String} t The menu prefix text.
+     */    
        setMenuPrefixText : function(t) {
                this.menuPrefixText = t;
        },
        // private && applied to the tab panel itself.
-       tabPanelMethods : {
+       parentOverrides : {
                // all execute within the scope of the tab panel
                // private      
                showTabsMenu : function(e) {            
-                       if (! this.tabsMenu) {
-                               this.tabsMenu =  new Ext.menu.Menu();
-                               this.on('beforedestroy', this.tabsMenu.destroy, this.tabsMenu);
+                       if  (this.tabsMenu) {
+                               this.tabsMenu.destroy();
+                this.un('destroy', this.tabsMenu.destroy, this.tabsMenu);
+                this.tabsMenu = null;
                        }
-                       
-                       this.tabsMenu.removeAll();
-                       
-                       this.generateTabMenuItems();
-                       
-                       var target = Ext.get(e.getTarget());
+            this.tabsMenu =  new Ext.menu.Menu();
+            this.on('destroy', this.tabsMenu.destroy, this.tabsMenu);
+
+            this.generateTabMenuItems();
+
+            var target = Ext.get(e.getTarget());
                        var xy     = target.getXY();
-                       
+//
                        //Y param + 24 pixels
                        xy[1] += 24;
                        
@@ -7882,12 +9137,10 @@ Ext.ux.TabScrollerMenu =  Ext.extend(Object, {
                                                menuItems.push(this.autoGenMenuItem(item));
                                        }
                                        
-                                       
                                        this.tabsMenu.add({
                                                text : this.tabScrollerMenu.menuPrefixText  + ' ' + (start + 1) + ' - ' + (start + menuItems.length),
                                                menu : menuItems
                                        });
-                                       
 
                                }
                        }
@@ -7897,7 +9150,7 @@ Ext.ux.TabScrollerMenu =  Ext.extend(Object, {
                                                menuItems.push(this.autoGenMenuItem(item));
                                        }
                                }, this);
-                       }       
+                       }
                },
                // private
                autoGenMenuItem : function(item) {
@@ -7920,6 +9173,8 @@ Ext.ux.TabScrollerMenu =  Ext.extend(Object, {
                }       
        }       
 });
+
+Ext.reg('tabscrollermenu', Ext.ux.TabScrollerMenu);
 Ext.ns('Ext.ux.tree');
 
 /**
@@ -8211,4 +9466,773 @@ Ext.ux.ValidationStatus = Ext.extend(Ext.Component, {
             this.showErrors();
         }
     }
-});
\ No newline at end of file
+});(function() {    
+    Ext.override(Ext.list.Column, {
+        init : function() {            
+            if(!this.type){
+                this.type = "auto";
+            }
+
+            var st = Ext.data.SortTypes;
+            // named sortTypes are supported, here we look them up
+            if(typeof this.sortType == "string"){
+                this.sortType = st[this.sortType];
+            }
+
+            // set default sortType for strings and dates
+            if(!this.sortType){
+                switch(this.type){
+                    case "string":
+                        this.sortType = st.asUCString;
+                        break;
+                    case "date":
+                        this.sortType = st.asDate;
+                        break;
+                    default:
+                        this.sortType = st.none;
+                }
+            }
+        }
+    });
+
+    Ext.tree.Column = Ext.extend(Ext.list.Column, {});
+    Ext.tree.NumberColumn = Ext.extend(Ext.list.NumberColumn, {});
+    Ext.tree.DateColumn = Ext.extend(Ext.list.DateColumn, {});
+    Ext.tree.BooleanColumn = Ext.extend(Ext.list.BooleanColumn, {});
+
+    Ext.reg('tgcolumn', Ext.tree.Column);
+    Ext.reg('tgnumbercolumn', Ext.tree.NumberColumn);
+    Ext.reg('tgdatecolumn', Ext.tree.DateColumn);
+    Ext.reg('tgbooleancolumn', Ext.tree.BooleanColumn);
+})();
+/**
+ * @class Ext.ux.tree.TreeGridNodeUI
+ * @extends Ext.tree.TreeNodeUI
+ */
+Ext.ux.tree.TreeGridNodeUI = Ext.extend(Ext.tree.TreeNodeUI, {
+    isTreeGridNodeUI: true,
+    
+    renderElements : function(n, a, targetNode, bulkRender){
+        var t = n.getOwnerTree(),
+            cols = t.columns,
+            c = cols[0],
+            i, buf, len;
+
+        this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
+
+        buf = [
+             '<tbody class="x-tree-node">',
+                '<tr ext:tree-node-id="', n.id ,'" class="x-tree-node-el ', a.cls, '">',
+                    '<td class="x-treegrid-col">',
+                        '<span class="x-tree-node-indent">', this.indentMarkup, "</span>",
+                        '<img src="', this.emptyIcon, '" class="x-tree-ec-icon x-tree-elbow">',
+                        '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon', (a.icon ? " x-tree-node-inline-icon" : ""), (a.iconCls ? " "+a.iconCls : ""), '" unselectable="on">',
+                        '<a hidefocus="on" class="x-tree-node-anchor" href="', a.href ? a.href : '#', '" tabIndex="1" ',
+                            a.hrefTarget ? ' target="'+a.hrefTarget+'"' : '', '>',
+                        '<span unselectable="on">', (c.tpl ? c.tpl.apply(a) : a[c.dataIndex] || c.text), '</span></a>',
+                    '</td>'
+        ];
+
+        for(i = 1, len = cols.length; i < len; i++){
+            c = cols[i];
+            buf.push(
+                    '<td class="x-treegrid-col ', (c.cls ? c.cls : ''), '">',
+                        '<div unselectable="on" class="x-treegrid-text"', (c.align ? ' style="text-align: ' + c.align + ';"' : ''), '>',
+                            (c.tpl ? c.tpl.apply(a) : a[c.dataIndex]),
+                        '</div>',
+                    '</td>'
+            );
+        }
+
+        buf.push(
+            '</tr><tr class="x-tree-node-ct"><td colspan="', cols.length, '">',
+            '<table class="x-treegrid-node-ct-table" cellpadding="0" cellspacing="0" style="table-layout: fixed; display: none; width: ', t.innerCt.getWidth() ,'px;"><colgroup>'
+        );
+        for(i = 0, len = cols.length; i<len; i++) {
+            buf.push('<col style="width: ', (cols[i].hidden ? 0 : cols[i].width) ,'px;" />');
+        }
+        buf.push('</colgroup></table></td></tr></tbody>');
+
+        if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
+            this.wrap = Ext.DomHelper.insertHtml("beforeBegin", n.nextSibling.ui.getEl(), buf.join(''));
+        }else{
+            this.wrap = Ext.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(''));
+        }
+
+        this.elNode = this.wrap.childNodes[0];
+        this.ctNode = this.wrap.childNodes[1].firstChild.firstChild;
+        var cs = this.elNode.firstChild.childNodes;
+        this.indentNode = cs[0];
+        this.ecNode = cs[1];
+        this.iconNode = cs[2];
+        this.anchor = cs[3];
+        this.textNode = cs[3].firstChild;
+    },
+
+    // private
+    animExpand : function(cb){
+        this.ctNode.style.display = "";
+        Ext.ux.tree.TreeGridNodeUI.superclass.animExpand.call(this, cb);
+    }
+});
+
+Ext.ux.tree.TreeGridRootNodeUI = Ext.extend(Ext.tree.TreeNodeUI, {
+    isTreeGridNodeUI: true,
+    
+    // private
+    render : function(){
+        if(!this.rendered){
+            this.wrap = this.ctNode = this.node.ownerTree.innerCt.dom;
+            this.node.expanded = true;
+        }
+        
+        if(Ext.isWebKit) {
+            // weird table-layout: fixed issue in webkit
+            var ct = this.ctNode;
+            ct.style.tableLayout = null;
+            (function() {
+                ct.style.tableLayout = 'fixed';
+            }).defer(1);
+        }
+    },
+
+    destroy : function(){
+        if(this.elNode){
+            Ext.dd.Registry.unregister(this.elNode.id);
+        }
+        delete this.node;
+    },
+    
+    collapse : Ext.emptyFn,
+    expand : Ext.emptyFn
+});/**
+ * @class Ext.tree.ColumnResizer
+ * @extends Ext.util.Observable
+ */
+Ext.tree.ColumnResizer = Ext.extend(Ext.util.Observable, {
+    /**
+     * @cfg {Number} minWidth The minimum width the column can be dragged to.
+     * Defaults to <tt>14</tt>.
+     */
+    minWidth: 14,
+
+    constructor: function(config){
+        Ext.apply(this, config);
+        Ext.tree.ColumnResizer.superclass.constructor.call(this);
+    },
+
+    init : function(tree){
+        this.tree = tree;
+        tree.on('render', this.initEvents, this);
+    },
+
+    initEvents : function(tree){
+        tree.mon(tree.innerHd, 'mousemove', this.handleHdMove, this);
+        this.tracker = new Ext.dd.DragTracker({
+            onBeforeStart: this.onBeforeStart.createDelegate(this),
+            onStart: this.onStart.createDelegate(this),
+            onDrag: this.onDrag.createDelegate(this),
+            onEnd: this.onEnd.createDelegate(this),
+            tolerance: 3,
+            autoStart: 300
+        });
+        this.tracker.initEl(tree.innerHd);
+        tree.on('beforedestroy', this.tracker.destroy, this.tracker);
+    },
+
+    handleHdMove : function(e, t){
+        var hw = 5,
+            x = e.getPageX(),
+            hd = e.getTarget('.x-treegrid-hd', 3, true);
+        
+        if(hd){                                 
+            var r = hd.getRegion(),
+                ss = hd.dom.style,
+                pn = hd.dom.parentNode;
+            
+            if(x - r.left <= hw && hd.dom !== pn.firstChild) {
+                var ps = hd.dom.previousSibling;
+                while(ps && Ext.fly(ps).hasClass('x-treegrid-hd-hidden')) {
+                    ps = ps.previousSibling;
+                }
+                if(ps) {                    
+                    this.activeHd = Ext.get(ps);
+                               ss.cursor = Ext.isWebKit ? 'e-resize' : 'col-resize';
+                }
+            } else if(r.right - x <= hw) {
+                var ns = hd.dom;
+                while(ns && Ext.fly(ns).hasClass('x-treegrid-hd-hidden')) {
+                    ns = ns.previousSibling;
+                }
+                if(ns) {
+                    this.activeHd = Ext.get(ns);
+                               ss.cursor = Ext.isWebKit ? 'w-resize' : 'col-resize';                    
+                }
+            } else{
+                delete this.activeHd;
+                ss.cursor = '';
+            }
+        }
+    },
+
+    onBeforeStart : function(e){
+        this.dragHd = this.activeHd;
+        return !!this.dragHd;
+    },
+
+    onStart : function(e){
+        this.tree.headersDisabled = true;
+        this.proxy = this.tree.body.createChild({cls:'x-treegrid-resizer'});
+        this.proxy.setHeight(this.tree.body.getHeight());
+
+        var x = this.tracker.getXY()[0];
+
+        this.hdX = this.dragHd.getX();
+        this.hdIndex = this.tree.findHeaderIndex(this.dragHd);
+
+        this.proxy.setX(this.hdX);
+        this.proxy.setWidth(x-this.hdX);
+
+        this.maxWidth = this.tree.outerCt.getWidth() - this.tree.innerBody.translatePoints(this.hdX).left;
+    },
+
+    onDrag : function(e){
+        var cursorX = this.tracker.getXY()[0];
+        this.proxy.setWidth((cursorX-this.hdX).constrain(this.minWidth, this.maxWidth));
+    },
+
+    onEnd : function(e){
+        var nw = this.proxy.getWidth(),
+            tree = this.tree;
+        
+        this.proxy.remove();
+        delete this.dragHd;
+        
+        tree.columns[this.hdIndex].width = nw;
+        tree.updateColumnWidths();
+        
+        setTimeout(function(){
+            tree.headersDisabled = false;
+        }, 100);
+    }
+});Ext.ns('Ext.ux.tree');
+
+/**
+ * @class Ext.ux.tree.TreeGridSorter
+ * @extends Ext.tree.TreeSorter
+ */
+Ext.ux.tree.TreeGridSorter = Ext.extend(Ext.tree.TreeSorter, {
+    /**
+     * @cfg {Array} sortClasses The CSS classes applied to a header when it is sorted. (defaults to <tt>['sort-asc', 'sort-desc']</tt>)
+     */
+    sortClasses : ['sort-asc', 'sort-desc'],
+    /**
+     * @cfg {String} sortAscText The text displayed in the 'Sort Ascending' menu item (defaults to <tt>'Sort Ascending'</tt>)
+     */
+    sortAscText : 'Sort Ascending',
+    /**
+     * @cfg {String} sortDescText The text displayed in the 'Sort Descending' menu item (defaults to <tt>'Sort Descending'</tt>)
+     */
+    sortDescText : 'Sort Descending',
+
+    constructor : function(tree, config) {
+        if(!Ext.isObject(config)) {
+            config = {
+                property: tree.columns[0].dataIndex || 'text',
+                folderSort: true
+            }
+        }
+
+        Ext.ux.tree.TreeGridSorter.superclass.constructor.apply(this, arguments);
+
+        this.tree = tree;
+        tree.on('headerclick', this.onHeaderClick, this);
+        tree.ddAppendOnly = true;
+
+        me = this;
+        this.defaultSortFn = function(n1, n2){
+
+            var dsc = me.dir && me.dir.toLowerCase() == 'desc';
+            var p = me.property || 'text';
+            var sortType = me.sortType;
+            var fs = me.folderSort;
+            var cs = me.caseSensitive === true;
+            var leafAttr = me.leafAttr || 'leaf';
+
+            if(fs){
+                if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
+                    return 1;
+                }
+                if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
+                    return -1;
+                }
+            }
+               var v1 = sortType ? sortType(n1.attributes[p]) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
+               var v2 = sortType ? sortType(n2.attributes[p]) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
+               if(v1 < v2){
+                       return dsc ? +1 : -1;
+               }else if(v1 > v2){
+                       return dsc ? -1 : +1;
+            }else{
+               return 0;
+            }
+        };
+
+        tree.on('afterrender', this.onAfterTreeRender, this, {single: true});
+        tree.on('headermenuclick', this.onHeaderMenuClick, this);
+    },
+
+    onAfterTreeRender : function() {
+        var hmenu = this.tree.hmenu;
+        hmenu.insert(0,
+            {itemId:'asc', text: this.sortAscText, cls: 'xg-hmenu-sort-asc'},
+            {itemId:'desc', text: this.sortDescText, cls: 'xg-hmenu-sort-desc'}
+        );
+        this.updateSortIcon(0, 'asc');
+    },
+
+    onHeaderMenuClick : function(c, id, index) {
+        if(id === 'asc' || id === 'desc') {
+            this.onHeaderClick(c, null, index);
+            return false;
+        }
+    },
+
+    onHeaderClick : function(c, el, i) {
+        if(c && !this.tree.headersDisabled){
+            var me = this;
+
+            me.property = c.dataIndex;
+            me.dir = c.dir = (c.dir === 'desc' ? 'asc' : 'desc');
+            me.sortType = c.sortType;
+            me.caseSensitive === Ext.isBoolean(c.caseSensitive) ? c.caseSensitive : this.caseSensitive;
+            me.sortFn = c.sortFn || this.defaultSortFn;
+
+            this.tree.root.cascade(function(n) {
+                if(!n.isLeaf()) {
+                    me.updateSort(me.tree, n);
+                }
+            });
+
+            this.updateSortIcon(i, c.dir);
+        }
+    },
+
+    // private
+    updateSortIcon : function(col, dir){
+        var sc = this.sortClasses;
+        var hds = this.tree.innerHd.select('td').removeClass(sc);
+        hds.item(col).addClass(sc[dir == 'desc' ? 1 : 0]);
+    }
+});/**
+ * @class Ext.ux.tree.TreeGridLoader
+ * @extends Ext.tree.TreeLoader
+ */
+Ext.ux.tree.TreeGridLoader = Ext.extend(Ext.tree.TreeLoader, {
+    createNode : function(attr) {
+        if (!attr.uiProvider) {
+            attr.uiProvider = Ext.ux.tree.TreeGridNodeUI;
+        }
+        return Ext.tree.TreeLoader.prototype.createNode.call(this, attr);
+    }
+});/**
+ * @class Ext.ux.tree.TreeGrid
+ * @extends Ext.tree.TreePanel
+ * 
+ * @xtype treegrid
+ */
+Ext.ux.tree.TreeGrid = Ext.extend(Ext.tree.TreePanel, {
+    rootVisible : false,
+    useArrows : true,
+    lines : false,
+    borderWidth : Ext.isBorderBox ? 0 : 2, // the combined left/right border for each cell
+    cls : 'x-treegrid',
+
+    columnResize : true,
+    enableSort : true,
+    reserveScrollOffset : true,
+    enableHdMenu : true,
+    
+    columnsText : 'Columns',
+
+    initComponent : function() {
+        if(!this.root) {
+            this.root = new Ext.tree.AsyncTreeNode({text: 'Root'});
+        }
+        
+        // initialize the loader
+        var l = this.loader;
+        if(!l){
+            l = new Ext.ux.tree.TreeGridLoader({
+                dataUrl: this.dataUrl,
+                requestMethod: this.requestMethod,
+                store: this.store
+            });
+        }else if(Ext.isObject(l) && !l.load){
+            l = new Ext.ux.tree.TreeGridLoader(l);
+        }
+        else if(l) {
+            l.createNode = function(attr) {
+                if (!attr.uiProvider) {
+                    attr.uiProvider = Ext.ux.tree.TreeGridNodeUI;
+                }
+                return Ext.tree.TreeLoader.prototype.createNode.call(this, attr);
+            }
+        }
+        this.loader = l;
+                            
+        Ext.ux.tree.TreeGrid.superclass.initComponent.call(this);                    
+        
+        this.initColumns();
+        
+        if(this.enableSort) {
+            this.treeGridSorter = new Ext.ux.tree.TreeGridSorter(this, this.enableSort);
+        }
+        
+        if(this.columnResize){
+            this.colResizer = new Ext.tree.ColumnResizer(this.columnResize);
+            this.colResizer.init(this);
+        }
+        
+        var c = this.columns;
+        if(!this.internalTpl){                                
+            this.internalTpl = new Ext.XTemplate(
+                '<div class="x-grid3-header">',
+                    '<div class="x-treegrid-header-inner">',
+                        '<div class="x-grid3-header-offset">',
+                            '<table cellspacing="0" cellpadding="0" border="0"><colgroup><tpl for="columns"><col /></tpl></colgroup>',
+                            '<thead><tr class="x-grid3-hd-row">',
+                            '<tpl for="columns">',
+                            '<td class="x-grid3-hd x-grid3-cell x-treegrid-hd" style="text-align: {align};" id="', this.id, '-xlhd-{#}">',
+                                '<div class="x-grid3-hd-inner x-treegrid-hd-inner" unselectable="on">',
+                                     this.enableHdMenu ? '<a class="x-grid3-hd-btn" href="#"></a>' : '',
+                                     '{header}<img class="x-grid3-sort-icon" src="', Ext.BLANK_IMAGE_URL, '" />',
+                                 '</div>',
+                            '</td></tpl>',
+                            '</tr></thead>',
+                        '</div></table>',
+                    '</div></div>',
+                '</div>',
+                '<div class="x-treegrid-root-node">',
+                    '<table class="x-treegrid-root-table" cellpadding="0" cellspacing="0" style="table-layout: fixed;"></table>',
+                '</div>'
+            );
+        }
+        
+        if(!this.colgroupTpl) {
+            this.colgroupTpl = new Ext.XTemplate(
+                '<colgroup><tpl for="columns"><col style="width: {width}px"/></tpl></colgroup>'
+            );
+        }
+    },
+
+    initColumns : function() {
+        var cs = this.columns,
+            len = cs.length, 
+            columns = [],
+            i, c;
+
+        for(i = 0; i < len; i++){
+            c = cs[i];
+            if(!c.isColumn) {
+                c.xtype = c.xtype ? (/^tg/.test(c.xtype) ? c.xtype : 'tg' + c.xtype) : 'tgcolumn';
+                c = Ext.create(c);
+            }
+            c.init(this);
+            columns.push(c);
+            
+            if(this.enableSort !== false && c.sortable !== false) {
+                c.sortable = true;
+                this.enableSort = true;
+            }
+        }
+
+        this.columns = columns;
+    },
+
+    onRender : function(){
+        Ext.tree.TreePanel.superclass.onRender.apply(this, arguments);
+
+        this.el.addClass('x-treegrid');
+        
+        this.outerCt = this.body.createChild({
+            cls:'x-tree-root-ct x-treegrid-ct ' + (this.useArrows ? 'x-tree-arrows' : this.lines ? 'x-tree-lines' : 'x-tree-no-lines')
+        });
+        
+        this.internalTpl.overwrite(this.outerCt, {columns: this.columns});
+        
+        this.mainHd = Ext.get(this.outerCt.dom.firstChild);
+        this.innerHd = Ext.get(this.mainHd.dom.firstChild);
+        this.innerBody = Ext.get(this.outerCt.dom.lastChild);
+        this.innerCt = Ext.get(this.innerBody.dom.firstChild);
+        
+        this.colgroupTpl.insertFirst(this.innerCt, {columns: this.columns});
+        
+        if(this.hideHeaders){
+            this.header.dom.style.display = 'none';
+        }
+        else if(this.enableHdMenu !== false){
+            this.hmenu = new Ext.menu.Menu({id: this.id + '-hctx'});
+            if(this.enableColumnHide !== false){
+                this.colMenu = new Ext.menu.Menu({id: this.id + '-hcols-menu'});
+                this.colMenu.on({
+                    scope: this,
+                    beforeshow: this.beforeColMenuShow,
+                    itemclick: this.handleHdMenuClick
+                });
+                this.hmenu.add({
+                    itemId:'columns',
+                    hideOnClick: false,
+                    text: this.columnsText,
+                    menu: this.colMenu,
+                    iconCls: 'x-cols-icon'
+                });
+            }
+            this.hmenu.on('itemclick', this.handleHdMenuClick, this);
+        }
+    },
+
+    setRootNode : function(node){
+        node.attributes.uiProvider = Ext.ux.tree.TreeGridRootNodeUI;        
+        node = Ext.ux.tree.TreeGrid.superclass.setRootNode.call(this, node);
+        if(this.innerCt) {
+            this.colgroupTpl.insertFirst(this.innerCt, {columns: this.columns});
+        }
+        return node;
+    },
+    
+    initEvents : function() {
+        Ext.ux.tree.TreeGrid.superclass.initEvents.apply(this, arguments);
+
+        this.mon(this.innerBody, 'scroll', this.syncScroll, this);
+        this.mon(this.innerHd, 'click', this.handleHdDown, this);
+        this.mon(this.mainHd, {
+            scope: this,
+            mouseover: this.handleHdOver,
+            mouseout: this.handleHdOut
+        });
+    },
+    
+    onResize : function(w, h) {
+        Ext.ux.tree.TreeGrid.superclass.onResize.apply(this, arguments);
+        
+        var bd = this.innerBody.dom;
+        var hd = this.innerHd.dom;
+
+        if(!bd){
+            return;
+        }
+
+        if(Ext.isNumber(h)){
+            bd.style.height = this.body.getHeight(true) - hd.offsetHeight + 'px';
+        }
+
+        if(Ext.isNumber(w)){                        
+            var sw = Ext.num(this.scrollOffset, Ext.getScrollBarWidth());
+            if(this.reserveScrollOffset || ((bd.offsetWidth - bd.clientWidth) > 10)){
+                this.setScrollOffset(sw);
+            }else{
+                var me = this;
+                setTimeout(function(){
+                    me.setScrollOffset(bd.offsetWidth - bd.clientWidth > 10 ? sw : 0);
+                }, 10);
+            }
+        }
+    },
+
+    updateColumnWidths : function() {
+        var cols = this.columns,
+            colCount = cols.length,
+            groups = this.outerCt.query('colgroup'),
+            groupCount = groups.length,
+            c, g, i, j;
+
+        for(i = 0; i<colCount; i++) {
+            c = cols[i];
+            for(j = 0; j<groupCount; j++) {
+                g = groups[j];
+                g.childNodes[i].style.width = (c.hidden ? 0 : c.width) + 'px';
+            }
+        }
+        
+        for(i = 0, groups = this.innerHd.query('td'), len = groups.length; i<len; i++) {
+            c = Ext.fly(groups[i]);
+            if(cols[i] && cols[i].hidden) {
+                c.addClass('x-treegrid-hd-hidden');
+            }
+            else {
+                c.removeClass('x-treegrid-hd-hidden');
+            }
+        }
+
+        var tcw = this.getTotalColumnWidth();                        
+        Ext.fly(this.innerHd.dom.firstChild).setWidth(tcw + (this.scrollOffset || 0));
+        this.outerCt.select('table').setWidth(tcw);
+        this.syncHeaderScroll();    
+    },
+                    
+    getVisibleColumns : function() {
+        var columns = [],
+            cs = this.columns,
+            len = cs.length,
+            i;
+            
+        for(i = 0; i<len; i++) {
+            if(!cs[i].hidden) {
+                columns.push(cs[i]);
+            }
+        }        
+        return columns;
+    },
+
+    getTotalColumnWidth : function() {
+        var total = 0;
+        for(var i = 0, cs = this.getVisibleColumns(), len = cs.length; i<len; i++) {
+            total += cs[i].width;
+        }
+        return total;
+    },
+
+    setScrollOffset : function(scrollOffset) {
+        this.scrollOffset = scrollOffset;                        
+        this.updateColumnWidths();
+    },
+
+    // private
+    handleHdDown : function(e, t){
+        var hd = e.getTarget('.x-treegrid-hd');
+
+        if(hd && Ext.fly(t).hasClass('x-grid3-hd-btn')){
+            var ms = this.hmenu.items,
+                cs = this.columns,
+                index = this.findHeaderIndex(hd),
+                c = cs[index],
+                sort = c.sortable;
+                
+            e.stopEvent();
+            Ext.fly(hd).addClass('x-grid3-hd-menu-open');
+            this.hdCtxIndex = index;
+            
+            this.fireEvent('headerbuttonclick', ms, c, hd, index);
+            
+            this.hmenu.on('hide', function(){
+                Ext.fly(hd).removeClass('x-grid3-hd-menu-open');
+            }, this, {single:true});
+            
+            this.hmenu.show(t, 'tl-bl?');
+        }
+        else if(hd) {
+            var index = this.findHeaderIndex(hd);
+            this.fireEvent('headerclick', this.columns[index], hd, index);
+        }
+    },
+
+    // private
+    handleHdOver : function(e, t){                    
+        var hd = e.getTarget('.x-treegrid-hd');                        
+        if(hd && !this.headersDisabled){
+            index = this.findHeaderIndex(hd);
+            this.activeHdRef = t;
+            this.activeHdIndex = index;
+            var el = Ext.get(hd);
+            this.activeHdRegion = el.getRegion();
+            el.addClass('x-grid3-hd-over');
+            this.activeHdBtn = el.child('.x-grid3-hd-btn');
+            if(this.activeHdBtn){
+                this.activeHdBtn.dom.style.height = (hd.firstChild.offsetHeight-1)+'px';
+            }
+        }
+    },
+    
+    // private
+    handleHdOut : function(e, t){
+        var hd = e.getTarget('.x-treegrid-hd');
+        if(hd && (!Ext.isIE || !e.within(hd, true))){
+            this.activeHdRef = null;
+            Ext.fly(hd).removeClass('x-grid3-hd-over');
+            hd.style.cursor = '';
+        }
+    },
+                    
+    findHeaderIndex : function(hd){
+        hd = hd.dom || hd;
+        var cs = hd.parentNode.childNodes;
+        for(var i = 0, c; c = cs[i]; i++){
+            if(c == hd){
+                return i;
+            }
+        }
+        return -1;
+    },
+    
+    // private
+    beforeColMenuShow : function(){
+        var cols = this.columns,  
+            colCount = cols.length,
+            i, c;                        
+        this.colMenu.removeAll();                    
+        for(i = 1; i < colCount; i++){
+            c = cols[i];
+            if(c.hideable !== false){
+                this.colMenu.add(new Ext.menu.CheckItem({
+                    itemId: 'col-' + i,
+                    text: c.header,
+                    checked: !c.hidden,
+                    hideOnClick:false,
+                    disabled: c.hideable === false
+                }));
+            }
+        }
+    },
+                    
+    // private
+    handleHdMenuClick : function(item){
+        var index = this.hdCtxIndex,
+            id = item.getItemId();
+        
+        if(this.fireEvent('headermenuclick', this.columns[index], id, index) !== false) {
+            index = id.substr(4);
+            if(index > 0 && this.columns[index]) {
+                this.setColumnVisible(index, !item.checked);
+            }     
+        }
+        
+        return true;
+    },
+    
+    setColumnVisible : function(index, visible) {
+        this.columns[index].hidden = !visible;        
+        this.updateColumnWidths();
+    },
+
+    /**
+     * Scrolls the grid to the top
+     */
+    scrollToTop : function(){
+        this.innerBody.dom.scrollTop = 0;
+        this.innerBody.dom.scrollLeft = 0;
+    },
+
+    // private
+    syncScroll : function(){
+        this.syncHeaderScroll();
+        var mb = this.innerBody.dom;
+        this.fireEvent('bodyscroll', mb.scrollLeft, mb.scrollTop);
+    },
+
+    // private
+    syncHeaderScroll : function(){
+        var mb = this.innerBody.dom;
+        this.innerHd.dom.scrollLeft = mb.scrollLeft;
+        this.innerHd.dom.scrollLeft = mb.scrollLeft; // second time for IE (1/2 time first fails, other browsers ignore)
+    },
+    
+    registerNode : function(n) {
+        Ext.ux.tree.TreeGrid.superclass.registerNode.call(this, n);
+        if(!n.uiProvider && !n.isRoot && !n.ui.isTreeGridNodeUI) {
+            n.ui = new Ext.ux.tree.TreeGridNodeUI(n);
+        }
+    }
+});
+
+Ext.reg('treegrid', Ext.ux.tree.TreeGrid);
\ No newline at end of file