ext-all-debug.js
上传用户:dawnssy
上传日期:2022-08-06
资源大小:9345k
文件大小:1167k
源码类别:

JavaScript

开发平台:

JavaScript

  1.     stripeRows : false,
  2.     
  3.     trackMouseOver : true,
  4.     
  5.     stateEvents : ['columnmove', 'columnresize', 'sortchange'],
  6.     
  7.     view : null,
  8.     
  9.     
  10.     bubbleEvents: [],
  11.     
  12.     
  13.     
  14.     rendered : false,
  15.     
  16.     viewReady : false,
  17.     
  18.     initComponent : function(){
  19.         Ext.grid.GridPanel.superclass.initComponent.call(this);
  20.         if(this.columnLines){
  21.             this.cls = (this.cls || '') + ' x-grid-with-col-lines';
  22.         }
  23.         
  24.         
  25.         this.autoScroll = false;
  26.         this.autoWidth = false;
  27.         if(Ext.isArray(this.columns)){
  28.             this.colModel = new Ext.grid.ColumnModel(this.columns);
  29.             delete this.columns;
  30.         }
  31.         
  32.         if(this.ds){
  33.             this.store = this.ds;
  34.             delete this.ds;
  35.         }
  36.         if(this.cm){
  37.             this.colModel = this.cm;
  38.             delete this.cm;
  39.         }
  40.         if(this.sm){
  41.             this.selModel = this.sm;
  42.             delete this.sm;
  43.         }
  44.         this.store = Ext.StoreMgr.lookup(this.store);
  45.         this.addEvents(
  46.             
  47.             
  48.             'click',
  49.             
  50.             'dblclick',
  51.             
  52.             'contextmenu',
  53.             
  54.             'mousedown',
  55.             
  56.             'mouseup',
  57.             
  58.             'mouseover',
  59.             
  60.             'mouseout',
  61.             
  62.             'keypress',
  63.             
  64.             'keydown',
  65.             
  66.             
  67.             'cellmousedown',
  68.             
  69.             'rowmousedown',
  70.             
  71.             'headermousedown',
  72.             
  73.             
  74.             'groupmousedown',
  75.             
  76.             
  77.             'rowbodymousedown',
  78.             
  79.             
  80.             'containermousedown',
  81.             
  82.             'cellclick',
  83.             
  84.             'celldblclick',
  85.             
  86.             'rowclick',
  87.             
  88.             'rowdblclick',
  89.             
  90.             'headerclick',
  91.             
  92.             'headerdblclick',
  93.             
  94.             'groupclick',
  95.             
  96.             'groupdblclick',
  97.             
  98.             'containerclick',
  99.             
  100.             'containerdblclick',
  101.             
  102.             
  103.             'rowbodyclick',
  104.             
  105.             'rowbodydblclick',
  106.             
  107.             
  108.             'rowcontextmenu',
  109.             
  110.             'cellcontextmenu',
  111.             
  112.             'headercontextmenu',
  113.             
  114.             'groupcontextmenu',
  115.             
  116.             'containercontextmenu',
  117.             
  118.             'rowbodycontextmenu',
  119.             
  120.             'bodyscroll',
  121.             
  122.             'columnresize',
  123.             
  124.             'columnmove',
  125.             
  126.             'sortchange',
  127.             
  128.             'reconfigure',
  129.             
  130.             'viewready'
  131.         );
  132.     },
  133.     
  134.     onRender : function(ct, position){
  135.         Ext.grid.GridPanel.superclass.onRender.apply(this, arguments);
  136.         var c = this.getGridEl();
  137.         this.el.addClass('x-grid-panel');
  138.         this.mon(c, {
  139.             scope: this,
  140.             mousedown: this.onMouseDown,
  141.             click: this.onClick,
  142.             dblclick: this.onDblClick,
  143.             contextmenu: this.onContextMenu
  144.         });
  145.         this.relayEvents(c, ['mousedown','mouseup','mouseover','mouseout','keypress', 'keydown']);
  146.         var view = this.getView();
  147.         view.init(this);
  148.         view.render();
  149.         this.getSelectionModel().init(this);
  150.     },
  151.     
  152.     initEvents : function(){
  153.         Ext.grid.GridPanel.superclass.initEvents.call(this);
  154.         if(this.loadMask){
  155.             this.loadMask = new Ext.LoadMask(this.bwrap,
  156.                     Ext.apply({store:this.store}, this.loadMask));
  157.         }
  158.     },
  159.     initStateEvents : function(){
  160.         Ext.grid.GridPanel.superclass.initStateEvents.call(this);
  161.         this.mon(this.colModel, 'hiddenchange', this.saveState, this, {delay: 100});
  162.     },
  163.     applyState : function(state){
  164.         var cm = this.colModel,
  165.             cs = state.columns;
  166.         if(cs){
  167.             for(var i = 0, len = cs.length; i < len; i++){
  168.                 var s = cs[i],
  169.                     c = cm.getColumnById(s.id);
  170.                 if(c){
  171.                     c.hidden = s.hidden;
  172.                     c.width = s.width;
  173.                     var oldIndex = cm.getIndexById(s.id);
  174.                     if(oldIndex != i){
  175.                         cm.moveColumn(oldIndex, i);
  176.                     }
  177.                 }
  178.             }
  179.         }
  180.         if(state.sort && this.store){
  181.             this.store[this.store.remoteSort ? 'setDefaultSort' : 'sort'](state.sort.field, state.sort.direction);
  182.         }
  183.         var o = Ext.apply({}, state);
  184.         delete o.columns;
  185.         delete o.sort;
  186.         Ext.grid.GridPanel.superclass.applyState.call(this, o);
  187.     },
  188.     getState : function(){
  189.         var o = {columns: []};
  190.         for(var i = 0, c; (c = this.colModel.config[i]); i++){
  191.             o.columns[i] = {
  192.                 id: c.id,
  193.                 width: c.width
  194.             };
  195.             if(c.hidden){
  196.                 o.columns[i].hidden = true;
  197.             }
  198.         }
  199.         if(this.store){
  200.             var ss = this.store.getSortState();
  201.             if(ss){
  202.                 o.sort = ss;
  203.             }
  204.         }
  205.         return o;
  206.     },
  207.     
  208.     afterRender : function(){
  209.         Ext.grid.GridPanel.superclass.afterRender.call(this);
  210.         var v = this.view;
  211.         this.on('bodyresize', v.layout, v);
  212.         v.layout();
  213.         if(this.deferRowRender){
  214.             v.afterRender.defer(10, this.view);
  215.         }else{
  216.             v.afterRender();
  217.         }
  218.         this.viewReady = true;
  219.     },
  220.     
  221.     reconfigure : function(store, colModel){
  222.         var rendered = this.rendered;
  223.         if(rendered){
  224.             if(this.loadMask){
  225.                 this.loadMask.destroy();
  226.                 this.loadMask = new Ext.LoadMask(this.bwrap,
  227.                         Ext.apply({}, {store:store}, this.initialConfig.loadMask));
  228.             }
  229.         }
  230.         if(this.view){
  231.             this.view.initData(store, colModel);
  232.         }
  233.         this.store = store;
  234.         this.colModel = colModel;
  235.         if(rendered){
  236.             this.view.refresh(true);
  237.         }
  238.         this.fireEvent('reconfigure', this, store, colModel);
  239.     },
  240.     
  241.     onDestroy : function(){
  242.         if(this.rendered){
  243.             Ext.destroy(this.view, this.loadMask);
  244.         }else if(this.store && this.store.autoDestroy){
  245.             this.store.destroy();
  246.         }
  247.         Ext.destroy(this.colModel, this.selModel);
  248.         this.store = this.selModel = this.colModel = this.view = this.loadMask = null;
  249.         Ext.grid.GridPanel.superclass.onDestroy.call(this);
  250.     },
  251.     
  252.     processEvent : function(name, e){
  253.         this.fireEvent(name, e);
  254.         var t = e.getTarget(),
  255.             v = this.view,
  256.             header = v.findHeaderIndex(t);
  257.             
  258.         if(header !== false){
  259.             this.fireEvent('header' + name, this, header, e);
  260.         }else{
  261.             var row = v.findRowIndex(t),
  262.                 cell,
  263.                 body;
  264.             if(row !== false){
  265.                 this.fireEvent('row' + name, this, row, e);
  266.                 cell = v.findCellIndex(t);
  267.                 body = v.findRowBody(t);
  268.                 if(cell !== false){
  269.                     this.fireEvent('cell' + name, this, row, cell, e);
  270.                 }
  271.                 if(body){
  272.                     this.fireEvent('rowbody' + name, this, row, e);
  273.                 }
  274.             }else{
  275.                 this.fireEvent('container' + name, this, e);
  276.             }
  277.         }
  278.         this.view.processEvent(name, e);
  279.     },
  280.     
  281.     onClick : function(e){
  282.         this.processEvent('click', e);
  283.     },
  284.     
  285.     onMouseDown : function(e){
  286.         this.processEvent('mousedown', e);
  287.     },
  288.     
  289.     onContextMenu : function(e, t){
  290.         this.processEvent('contextmenu', e);
  291.     },
  292.     
  293.     onDblClick : function(e){
  294.         this.processEvent('dblclick', e);
  295.     },
  296.     
  297.     walkCells : function(row, col, step, fn, scope){
  298.         var cm = this.colModel, 
  299.             clen = cm.getColumnCount(),
  300.             ds = this.store, 
  301.             rlen = ds.getCount(), 
  302.             first = true;
  303.         if(step < 0){
  304.             if(col < 0){
  305.                 row--;
  306.                 first = false;
  307.             }
  308.             while(row >= 0){
  309.                 if(!first){
  310.                     col = clen-1;
  311.                 }
  312.                 first = false;
  313.                 while(col >= 0){
  314.                     if(fn.call(scope || this, row, col, cm) === true){
  315.                         return [row, col];
  316.                     }
  317.                     col--;
  318.                 }
  319.                 row--;
  320.             }
  321.         } else {
  322.             if(col >= clen){
  323.                 row++;
  324.                 first = false;
  325.             }
  326.             while(row < rlen){
  327.                 if(!first){
  328.                     col = 0;
  329.                 }
  330.                 first = false;
  331.                 while(col < clen){
  332.                     if(fn.call(scope || this, row, col, cm) === true){
  333.                         return [row, col];
  334.                     }
  335.                     col++;
  336.                 }
  337.                 row++;
  338.             }
  339.         }
  340.         return null;
  341.     },
  342.     
  343.     onResize : function(){
  344.         Ext.grid.GridPanel.superclass.onResize.apply(this, arguments);
  345.         if(this.viewReady){
  346.             this.view.layout();
  347.         }
  348.     },
  349.     
  350.     getGridEl : function(){
  351.         return this.body;
  352.     },
  353.     
  354.     stopEditing : Ext.emptyFn,
  355.     
  356.     getSelectionModel : function(){
  357.         if(!this.selModel){
  358.             this.selModel = new Ext.grid.RowSelectionModel(
  359.                     this.disableSelection ? {selectRow: Ext.emptyFn} : null);
  360.         }
  361.         return this.selModel;
  362.     },
  363.     
  364.     getStore : function(){
  365.         return this.store;
  366.     },
  367.     
  368.     getColumnModel : function(){
  369.         return this.colModel;
  370.     },
  371.     
  372.     getView : function(){
  373.         if(!this.view){
  374.             this.view = new Ext.grid.GridView(this.viewConfig);
  375.         }
  376.         return this.view;
  377.     },
  378.     
  379.     getDragDropText : function(){
  380.         var count = this.selModel.getCount();
  381.         return String.format(this.ddText, count, count == 1 ? '' : 's');
  382.     }
  383.     
  384.     
  385.     
  386.     
  387.     
  388.     
  389.     
  390.     
  391.     
  392.     
  393.     
  394.     
  395.     
  396.     
  397.     
  398.     
  399.     
  400.     
  401.     
  402.     
  403.     
  404.     
  405.     
  406.     
  407.     
  408.     
  409.     
  410.     
  411.     
  412.     
  413.     
  414.     
  415.     
  416.     
  417.     
  418.     
  419.     
  420.     
  421.     
  422.     
  423.     
  424.     
  425.     
  426.     
  427.     
  428.     
  429.     
  430. });
  431. Ext.reg('grid', Ext.grid.GridPanel);
  432. Ext.grid.GridView = Ext.extend(Ext.util.Observable, {
  433.     
  434.     
  435.     
  436.     
  437.     
  438.     
  439.     deferEmptyText : true,
  440.     
  441.     scrollOffset : undefined,
  442.     
  443.     autoFill : false,
  444.     
  445.     forceFit : false,
  446.     
  447.     sortClasses : ['sort-asc', 'sort-desc'],
  448.     
  449.     sortAscText : 'Sort Ascending',
  450.     
  451.     sortDescText : 'Sort Descending',
  452.     
  453.     columnsText : 'Columns',
  454.     
  455.     selectedRowClass : 'x-grid3-row-selected',
  456.     
  457.     borderWidth : 2,
  458.     tdClass : 'x-grid3-cell',
  459.     hdCls : 'x-grid3-hd',
  460.     markDirty : true,
  461.     
  462.     cellSelectorDepth : 4,
  463.     
  464.     rowSelectorDepth : 10,
  465.     
  466.     
  467.     rowBodySelectorDepth : 10,
  468.     
  469.     cellSelector : 'td.x-grid3-cell',
  470.     
  471.     rowSelector : 'div.x-grid3-row',
  472.     
  473.     
  474.     rowBodySelector : 'div.x-grid3-row-body',
  475.     
  476.     
  477.     firstRowCls: 'x-grid3-row-first',
  478.     lastRowCls: 'x-grid3-row-last',
  479.     rowClsRe: /(?:^|s+)x-grid3-row-(first|last|alt)(?:s+|$)/g,
  480.     
  481.     constructor : function(config){
  482.         Ext.apply(this, config);
  483.     
  484.     this.addEvents(
  485.         
  486.         'beforerowremoved',
  487.         
  488.         'beforerowsinserted',
  489.         
  490.         'beforerefresh',
  491.         
  492.         'rowremoved',
  493.         
  494.         'rowsinserted',
  495.         
  496.         'rowupdated',
  497.         
  498.         'refresh'
  499.     );
  500.     Ext.grid.GridView.superclass.constructor.call(this);    
  501.     },
  502.     
  503.     
  504.     initTemplates : function(){
  505.         var ts = this.templates || {};
  506.         if(!ts.master){
  507.             ts.master = new Ext.Template(
  508.                     '<div class="x-grid3" hidefocus="true">',
  509.                         '<div class="x-grid3-viewport">',
  510.                             '<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>',
  511.                             '<div class="x-grid3-scroller"><div class="x-grid3-body" style="{bstyle}">{body}</div><a href="#" class="x-grid3-focus" tabIndex="-1"></a></div>',
  512.                         '</div>',
  513.                         '<div class="x-grid3-resize-marker">&#160;</div>',
  514.                         '<div class="x-grid3-resize-proxy">&#160;</div>',
  515.                     '</div>'
  516.                     );
  517.         }
  518.         if(!ts.header){
  519.             ts.header = new Ext.Template(
  520.                     '<table border="0" cellspacing="0" cellpadding="0" style="{tstyle}">',
  521.                     '<thead><tr class="x-grid3-hd-row">{cells}</tr></thead>',
  522.                     '</table>'
  523.                     );
  524.         }
  525.         if(!ts.hcell){
  526.             ts.hcell = new Ext.Template(
  527.                     '<td class="x-grid3-hd x-grid3-cell x-grid3-td-{id} {css}" style="{style}"><div {tooltip} {attr} class="x-grid3-hd-inner x-grid3-hd-{id}" unselectable="on" style="{istyle}">', this.grid.enableHdMenu ? '<a class="x-grid3-hd-btn" href="#"></a>' : '',
  528.                     '{value}<img class="x-grid3-sort-icon" src="', Ext.BLANK_IMAGE_URL, '" />',
  529.                     '</div></td>'
  530.                     );
  531.         }
  532.         if(!ts.body){
  533.             ts.body = new Ext.Template('{rows}');
  534.         }
  535.         if(!ts.row){
  536.             ts.row = new Ext.Template(
  537.                     '<div class="x-grid3-row {alt}" style="{tstyle}"><table class="x-grid3-row-table" border="0" cellspacing="0" cellpadding="0" style="{tstyle}">',
  538.                     '<tbody><tr>{cells}</tr>',
  539.                     (this.enableRowBody ? '<tr class="x-grid3-row-body-tr" style="{bodyStyle}"><td colspan="{cols}" class="x-grid3-body-cell" tabIndex="0" hidefocus="on"><div class="x-grid3-row-body">{body}</div></td></tr>' : ''),
  540.                     '</tbody></table></div>'
  541.                     );
  542.         }
  543.         if(!ts.cell){
  544.             ts.cell = new Ext.Template(
  545.                     '<td class="x-grid3-col x-grid3-cell x-grid3-td-{id} {css}" style="{style}" tabIndex="0" {cellAttr}>',
  546.                     '<div class="x-grid3-cell-inner x-grid3-col-{id}" unselectable="on" {attr}>{value}</div>',
  547.                     '</td>'
  548.                     );
  549.         }
  550.         for(var k in ts){
  551.             var t = ts[k];
  552.             if(t && Ext.isFunction(t.compile) && !t.compiled){
  553.                 t.disableFormats = true;
  554.                 t.compile();
  555.             }
  556.         }
  557.         this.templates = ts;
  558.         this.colRe = new RegExp('x-grid3-td-([^\s]+)', '');
  559.     },
  560.     
  561.     fly : function(el){
  562.         if(!this._flyweight){
  563.             this._flyweight = new Ext.Element.Flyweight(document.body);
  564.         }
  565.         this._flyweight.dom = el;
  566.         return this._flyweight;
  567.     },
  568.     
  569.     getEditorParent : function(){
  570.         return this.scroller.dom;
  571.     },
  572.     
  573.     initElements : function(){
  574.         var E = Ext.Element;
  575.         var el = this.grid.getGridEl().dom.firstChild;
  576.         var cs = el.childNodes;
  577.         this.el = new E(el);
  578.         this.mainWrap = new E(cs[0]);
  579.         this.mainHd = new E(this.mainWrap.dom.firstChild);
  580.         if(this.grid.hideHeaders){
  581.             this.mainHd.setDisplayed(false);
  582.         }
  583.         this.innerHd = this.mainHd.dom.firstChild;
  584.         this.scroller = new E(this.mainWrap.dom.childNodes[1]);
  585.         if(this.forceFit){
  586.             this.scroller.setStyle('overflow-x', 'hidden');
  587.         }
  588.         
  589.         this.mainBody = new E(this.scroller.dom.firstChild);
  590.         this.focusEl = new E(this.scroller.dom.childNodes[1]);
  591.         this.focusEl.swallowEvent('click', true);
  592.         this.resizeMarker = new E(cs[1]);
  593.         this.resizeProxy = new E(cs[2]);
  594.     },
  595.     
  596.     getRows : function(){
  597.         return this.hasRows() ? this.mainBody.dom.childNodes : [];
  598.     },
  599.     
  600.     
  601.     findCell : function(el){
  602.         if(!el){
  603.             return false;
  604.         }
  605.         return this.fly(el).findParent(this.cellSelector, this.cellSelectorDepth);
  606.     },
  607.     
  608.     findCellIndex : function(el, requiredCls){
  609.         var cell = this.findCell(el);
  610.         if(cell && (!requiredCls || this.fly(cell).hasClass(requiredCls))){
  611.             return this.getCellIndex(cell);
  612.         }
  613.         return false;
  614.     },
  615.     
  616.     getCellIndex : function(el){
  617.         if(el){
  618.             var m = el.className.match(this.colRe);
  619.             if(m && m[1]){
  620.                 return this.cm.getIndexById(m[1]);
  621.             }
  622.         }
  623.         return false;
  624.     },
  625.     
  626.     findHeaderCell : function(el){
  627.         var cell = this.findCell(el);
  628.         return cell && this.fly(cell).hasClass(this.hdCls) ? cell : null;
  629.     },
  630.     
  631.     findHeaderIndex : function(el){
  632.         return this.findCellIndex(el, this.hdCls);
  633.     },
  634.     
  635.     findRow : function(el){
  636.         if(!el){
  637.             return false;
  638.         }
  639.         return this.fly(el).findParent(this.rowSelector, this.rowSelectorDepth);
  640.     },
  641.     
  642.     findRowIndex : function(el){
  643.         var r = this.findRow(el);
  644.         return r ? r.rowIndex : false;
  645.     },
  646.     
  647.     
  648.     findRowBody : function(el){
  649.         if(!el){
  650.             return false;
  651.         }
  652.         return this.fly(el).findParent(this.rowBodySelector, this.rowBodySelectorDepth);
  653.     },
  654.     
  655.     
  656.     getRow : function(row){
  657.         return this.getRows()[row];
  658.     },
  659.     
  660.     getCell : function(row, col){
  661.         return this.getRow(row).getElementsByTagName('td')[col];
  662.     },
  663.     
  664.     getHeaderCell : function(index){
  665.       return this.mainHd.dom.getElementsByTagName('td')[index];
  666.     },
  667.     
  668.     
  669.     addRowClass : function(row, cls){
  670.         var r = this.getRow(row);
  671.         if(r){
  672.             this.fly(r).addClass(cls);
  673.         }
  674.     },
  675.     
  676.     removeRowClass : function(row, cls){
  677.         var r = this.getRow(row);
  678.         if(r){
  679.             this.fly(r).removeClass(cls);
  680.         }
  681.     },
  682.     
  683.     removeRow : function(row){
  684.         Ext.removeNode(this.getRow(row));
  685.         this.syncFocusEl(row);
  686.     },
  687.     
  688.     
  689.     removeRows : function(firstRow, lastRow){
  690.         var bd = this.mainBody.dom;
  691.         for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
  692.             Ext.removeNode(bd.childNodes[firstRow]);
  693.         }
  694.         this.syncFocusEl(firstRow);
  695.     },
  696.     
  697.     
  698.     getScrollState : function(){
  699.         var sb = this.scroller.dom;
  700.         return {left: sb.scrollLeft, top: sb.scrollTop};
  701.     },
  702.     
  703.     restoreScroll : function(state){
  704.         var sb = this.scroller.dom;
  705.         sb.scrollLeft = state.left;
  706.         sb.scrollTop = state.top;
  707.     },
  708.     
  709.     scrollToTop : function(){
  710.         this.scroller.dom.scrollTop = 0;
  711.         this.scroller.dom.scrollLeft = 0;
  712.     },
  713.     
  714.     syncScroll : function(){
  715.       this.syncHeaderScroll();
  716.       var mb = this.scroller.dom;
  717.         this.grid.fireEvent('bodyscroll', mb.scrollLeft, mb.scrollTop);
  718.     },
  719.     
  720.     syncHeaderScroll : function(){
  721.         var mb = this.scroller.dom;
  722.         this.innerHd.scrollLeft = mb.scrollLeft;
  723.         this.innerHd.scrollLeft = mb.scrollLeft; 
  724.     },
  725.     
  726.     updateSortIcon : function(col, dir){
  727.         var sc = this.sortClasses;
  728.         var hds = this.mainHd.select('td').removeClass(sc);
  729.         hds.item(col).addClass(sc[dir == 'DESC' ? 1 : 0]);
  730.     },
  731.     
  732.     updateAllColumnWidths : function(){
  733.         var tw = this.getTotalWidth(),
  734.             clen = this.cm.getColumnCount(),
  735.             ws = [],
  736.             len,
  737.             i;
  738.         for(i = 0; i < clen; i++){
  739.             ws[i] = this.getColumnWidth(i);
  740.         }
  741.         this.innerHd.firstChild.style.width = this.getOffsetWidth();
  742.         this.innerHd.firstChild.firstChild.style.width = tw;
  743.         this.mainBody.dom.style.width = tw;
  744.         for(i = 0; i < clen; i++){
  745.             var hd = this.getHeaderCell(i);
  746.             hd.style.width = ws[i];
  747.         }
  748.         var ns = this.getRows(), row, trow;
  749.         for(i = 0, len = ns.length; i < len; i++){
  750.             row = ns[i];
  751.             row.style.width = tw;
  752.             if(row.firstChild){
  753.                 row.firstChild.style.width = tw;
  754.                 trow = row.firstChild.rows[0];
  755.                 for (var j = 0; j < clen; j++) {
  756.                    trow.childNodes[j].style.width = ws[j];
  757.                 }
  758.             }
  759.         }
  760.         this.onAllColumnWidthsUpdated(ws, tw);
  761.     },
  762.     
  763.     updateColumnWidth : function(col, width){
  764.         var w = this.getColumnWidth(col);
  765.         var tw = this.getTotalWidth();
  766.         this.innerHd.firstChild.style.width = this.getOffsetWidth();
  767.         this.innerHd.firstChild.firstChild.style.width = tw;
  768.         this.mainBody.dom.style.width = tw;
  769.         var hd = this.getHeaderCell(col);
  770.         hd.style.width = w;
  771.         var ns = this.getRows(), row;
  772.         for(var i = 0, len = ns.length; i < len; i++){
  773.             row = ns[i];
  774.             row.style.width = tw;
  775.             if(row.firstChild){
  776.                 row.firstChild.style.width = tw;
  777.                 row.firstChild.rows[0].childNodes[col].style.width = w;
  778.             }
  779.         }
  780.         this.onColumnWidthUpdated(col, w, tw);
  781.     },
  782.     
  783.     updateColumnHidden : function(col, hidden){
  784.         var tw = this.getTotalWidth();
  785.         this.innerHd.firstChild.style.width = this.getOffsetWidth();
  786.         this.innerHd.firstChild.firstChild.style.width = tw;
  787.         this.mainBody.dom.style.width = tw;
  788.         var display = hidden ? 'none' : '';
  789.         var hd = this.getHeaderCell(col);
  790.         hd.style.display = display;
  791.         var ns = this.getRows(), row;
  792.         for(var i = 0, len = ns.length; i < len; i++){
  793.             row = ns[i];
  794.             row.style.width = tw;
  795.             if(row.firstChild){
  796.                 row.firstChild.style.width = tw;
  797.                 row.firstChild.rows[0].childNodes[col].style.display = display;
  798.             }
  799.         }
  800.         this.onColumnHiddenUpdated(col, hidden, tw);
  801.         delete this.lastViewWidth; 
  802.         this.layout();
  803.     },
  804.     
  805.     doRender : function(cs, rs, ds, startRow, colCount, stripe){
  806.         var ts = this.templates, ct = ts.cell, rt = ts.row, last = colCount-1;
  807.         var tstyle = 'width:'+this.getTotalWidth()+';';
  808.         
  809.         var buf = [], cb, c, p = {}, rp = {tstyle: tstyle}, r;
  810.         for(var j = 0, len = rs.length; j < len; j++){
  811.             r = rs[j]; cb = [];
  812.             var rowIndex = (j+startRow);
  813.             for(var i = 0; i < colCount; i++){
  814.                 c = cs[i];
  815.                 p.id = c.id;
  816.                 p.css = i === 0 ? 'x-grid3-cell-first ' : (i == last ? 'x-grid3-cell-last ' : '');
  817.                 p.attr = p.cellAttr = '';
  818.                 p.value = c.renderer.call(c.scope, r.data[c.name], p, r, rowIndex, i, ds);
  819.                 p.style = c.style;
  820.                 if(Ext.isEmpty(p.value)){
  821.                     p.value = '&#160;';
  822.                 }
  823.                 if(this.markDirty && r.dirty && Ext.isDefined(r.modified[c.name])){
  824.                     p.css += ' x-grid3-dirty-cell';
  825.                 }
  826.                 cb[cb.length] = ct.apply(p);
  827.             }
  828.             var alt = [];
  829.             if(stripe && ((rowIndex+1) % 2 === 0)){
  830.                 alt[0] = 'x-grid3-row-alt';
  831.             }
  832.             if(r.dirty){
  833.                 alt[1] = ' x-grid3-dirty-row';
  834.             }
  835.             rp.cols = colCount;
  836.             if(this.getRowClass){
  837.                 alt[2] = this.getRowClass(r, rowIndex, rp, ds);
  838.             }
  839.             rp.alt = alt.join(' ');
  840.             rp.cells = cb.join('');
  841.             buf[buf.length] =  rt.apply(rp);
  842.         }
  843.         return buf.join('');
  844.     },
  845.     
  846.     processRows : function(startRow, skipStripe){
  847.         if(!this.ds || this.ds.getCount() < 1){
  848.             return;
  849.         }
  850.         var rows = this.getRows(),
  851.             len = rows.length,
  852.             i, r;
  853.             
  854.         skipStripe = skipStripe || !this.grid.stripeRows;
  855.         startRow = startRow || 0;
  856.         for(i = 0; i<len; i++) {
  857.             r = rows[i];
  858.             if(r) {
  859.                 r.rowIndex = i;
  860.                 if(!skipStripe){
  861.                     r.className = r.className.replace(this.rowClsRe, ' ');
  862.                     if ((i + 1) % 2 === 0){
  863.                         r.className += ' x-grid3-row-alt';
  864.                     }
  865.                 }   
  866.             }          
  867.         }
  868.         
  869.         if(startRow === 0){
  870.             Ext.fly(rows[0]).addClass(this.firstRowCls);
  871.         }
  872.         Ext.fly(rows[rows.length - 1]).addClass(this.lastRowCls);
  873.     },
  874.     afterRender : function(){
  875.         if(!this.ds || !this.cm){
  876.             return;
  877.         }
  878.         this.mainBody.dom.innerHTML = this.renderRows() || '&#160;';
  879.         this.processRows(0, true);
  880.         if(this.deferEmptyText !== true){
  881.             this.applyEmptyText();
  882.         }
  883.         this.grid.fireEvent('viewready', this.grid);
  884.     },
  885.     
  886.     renderUI : function(){
  887.         var header = this.renderHeaders();
  888.         var body = this.templates.body.apply({rows:'&#160;'});
  889.         var html = this.templates.master.apply({
  890.             body: body,
  891.             header: header,
  892.             ostyle: 'width:'+this.getOffsetWidth()+';',
  893.             bstyle: 'width:'+this.getTotalWidth()+';'
  894.         });
  895.         var g = this.grid;
  896.         g.getGridEl().dom.innerHTML = html;
  897.         this.initElements();
  898.         
  899.         Ext.fly(this.innerHd).on('click', this.handleHdDown, this);
  900.         this.mainHd.on({
  901.             scope: this,
  902.             mouseover: this.handleHdOver,
  903.             mouseout: this.handleHdOut,
  904.             mousemove: this.handleHdMove
  905.         });
  906.         this.scroller.on('scroll', this.syncScroll,  this);
  907.         if(g.enableColumnResize !== false){
  908.             this.splitZone = new Ext.grid.GridView.SplitDragZone(g, this.mainHd.dom);
  909.         }
  910.         if(g.enableColumnMove){
  911.             this.columnDrag = new Ext.grid.GridView.ColumnDragZone(g, this.innerHd);
  912.             this.columnDrop = new Ext.grid.HeaderDropZone(g, this.mainHd.dom);
  913.         }
  914.         if(g.enableHdMenu !== false){
  915.             this.hmenu = new Ext.menu.Menu({id: g.id + '-hctx'});
  916.             this.hmenu.add(
  917.                 {itemId:'asc', text: this.sortAscText, cls: 'xg-hmenu-sort-asc'},
  918.                 {itemId:'desc', text: this.sortDescText, cls: 'xg-hmenu-sort-desc'}
  919.             );
  920.             if(g.enableColumnHide !== false){
  921.                 this.colMenu = new Ext.menu.Menu({id:g.id + '-hcols-menu'});
  922.                 this.colMenu.on({
  923.                     scope: this,
  924.                     beforeshow: this.beforeColMenuShow,
  925.                     itemclick: this.handleHdMenuClick
  926.                 });
  927.                 this.hmenu.add('-', {
  928.                     itemId:'columns',
  929.                     hideOnClick: false,
  930.                     text: this.columnsText,
  931.                     menu: this.colMenu,
  932.                     iconCls: 'x-cols-icon'
  933.                 });
  934.             }
  935.             this.hmenu.on('itemclick', this.handleHdMenuClick, this);
  936.         }
  937.         if(g.trackMouseOver){
  938.             this.mainBody.on({
  939.                 scope: this,
  940.                 mouseover: this.onRowOver,
  941.                 mouseout: this.onRowOut
  942.             });
  943.         }
  944.         if(g.enableDragDrop || g.enableDrag){
  945.             this.dragZone = new Ext.grid.GridDragZone(g, {
  946.                 ddGroup : g.ddGroup || 'GridDD'
  947.             });
  948.         }
  949.         this.updateHeaderSortState();
  950.     },
  951.     
  952.     
  953.     processEvent: Ext.emptyFn,
  954.     
  955.     layout : function(){
  956.         if(!this.mainBody){
  957.             return; 
  958.         }
  959.         var g = this.grid;
  960.         var c = g.getGridEl();
  961.         var csize = c.getSize(true);
  962.         var vw = csize.width;
  963.         if(!g.hideHeaders && (vw < 20 || csize.height < 20)){ 
  964.             return;
  965.         }
  966.         
  967.         if(g.autoHeight){
  968.             this.scroller.dom.style.overflow = 'visible';
  969.             if(Ext.isWebKit){
  970.                 this.scroller.dom.style.position = 'static';
  971.             }
  972.         }else{
  973.             this.el.setSize(csize.width, csize.height);
  974.             var hdHeight = this.mainHd.getHeight();
  975.             var vh = csize.height - (hdHeight);
  976.             this.scroller.setSize(vw, vh);
  977.             if(this.innerHd){
  978.                 this.innerHd.style.width = (vw)+'px';
  979.             }
  980.         }
  981.         if(this.forceFit){
  982.             if(this.lastViewWidth != vw){
  983.                 this.fitColumns(false, false);
  984.                 this.lastViewWidth = vw;
  985.             }
  986.         }else {
  987.             this.autoExpand();
  988.             this.syncHeaderScroll();
  989.         }
  990.         this.onLayout(vw, vh);
  991.     },
  992.     
  993.     
  994.     onLayout : function(vw, vh){
  995.         
  996.     },
  997.     onColumnWidthUpdated : function(col, w, tw){
  998.         
  999.     },
  1000.     onAllColumnWidthsUpdated : function(ws, tw){
  1001.         
  1002.     },
  1003.     onColumnHiddenUpdated : function(col, hidden, tw){
  1004.         
  1005.     },
  1006.     updateColumnText : function(col, text){
  1007.         
  1008.     },
  1009.     afterMove : function(colIndex){
  1010.         
  1011.     },
  1012.     
  1013.     
  1014.     init : function(grid){
  1015.         this.grid = grid;
  1016.         this.initTemplates();
  1017.         this.initData(grid.store, grid.colModel);
  1018.         this.initUI(grid);
  1019.     },
  1020.     
  1021.     getColumnId : function(index){
  1022.       return this.cm.getColumnId(index);
  1023.     },
  1024.     
  1025.     
  1026.     getOffsetWidth : function() {
  1027.         return (this.cm.getTotalWidth() + this.getScrollOffset()) + 'px';
  1028.     },
  1029.     
  1030.     getScrollOffset: function(){
  1031.         return Ext.num(this.scrollOffset, Ext.getScrollBarWidth());
  1032.     },
  1033.     
  1034.     renderHeaders : function(){
  1035.         var cm = this.cm, 
  1036.             ts = this.templates,
  1037.             ct = ts.hcell,
  1038.             cb = [], 
  1039.             p = {},
  1040.             len = cm.getColumnCount(),
  1041.             last = len - 1;
  1042.             
  1043.         for(var i = 0; i < len; i++){
  1044.             p.id = cm.getColumnId(i);
  1045.             p.value = cm.getColumnHeader(i) || '';
  1046.             p.style = this.getColumnStyle(i, true);
  1047.             p.tooltip = this.getColumnTooltip(i);
  1048.             p.css = i === 0 ? 'x-grid3-cell-first ' : (i == last ? 'x-grid3-cell-last ' : '');
  1049.             if(cm.config[i].align == 'right'){
  1050.                 p.istyle = 'padding-right:16px';
  1051.             } else {
  1052.                 delete p.istyle;
  1053.             }
  1054.             cb[cb.length] = ct.apply(p);
  1055.         }
  1056.         return ts.header.apply({cells: cb.join(''), tstyle:'width:'+this.getTotalWidth()+';'});
  1057.     },
  1058.     
  1059.     getColumnTooltip : function(i){
  1060.         var tt = this.cm.getColumnTooltip(i);
  1061.         if(tt){
  1062.             if(Ext.QuickTips.isEnabled()){
  1063.                 return 'ext:qtip="'+tt+'"';
  1064.             }else{
  1065.                 return 'title="'+tt+'"';
  1066.             }
  1067.         }
  1068.         return '';
  1069.     },
  1070.     
  1071.     beforeUpdate : function(){
  1072.         this.grid.stopEditing(true);
  1073.     },
  1074.     
  1075.     updateHeaders : function(){
  1076.         this.innerHd.firstChild.innerHTML = this.renderHeaders();
  1077.         this.innerHd.firstChild.style.width = this.getOffsetWidth();
  1078.         this.innerHd.firstChild.firstChild.style.width = this.getTotalWidth();
  1079.     },
  1080.     
  1081.     focusRow : function(row){
  1082.         this.focusCell(row, 0, false);
  1083.     },
  1084.     
  1085.     focusCell : function(row, col, hscroll){
  1086.         this.syncFocusEl(this.ensureVisible(row, col, hscroll));
  1087.         if(Ext.isGecko){
  1088.             this.focusEl.focus();
  1089.         }else{
  1090.             this.focusEl.focus.defer(1, this.focusEl);
  1091.         }
  1092.     },
  1093.     resolveCell : function(row, col, hscroll){
  1094.         if(!Ext.isNumber(row)){
  1095.             row = row.rowIndex;
  1096.         }
  1097.         if(!this.ds){
  1098.             return null;
  1099.         }
  1100.         if(row < 0 || row >= this.ds.getCount()){
  1101.             return null;
  1102.         }
  1103.         col = (col !== undefined ? col : 0);
  1104.         var rowEl = this.getRow(row),
  1105.             cm = this.cm,
  1106.             colCount = cm.getColumnCount(),
  1107.             cellEl;
  1108.         if(!(hscroll === false && col === 0)){
  1109.             while(col < colCount && cm.isHidden(col)){
  1110.                 col++;
  1111.             }
  1112.             cellEl = this.getCell(row, col);
  1113.         }
  1114.         return {row: rowEl, cell: cellEl};
  1115.     },
  1116.     getResolvedXY : function(resolved){
  1117.         if(!resolved){
  1118.             return null;
  1119.         }
  1120.         var s = this.scroller.dom, c = resolved.cell, r = resolved.row;
  1121.         return c ? Ext.fly(c).getXY() : [this.el.getX(), Ext.fly(r).getY()];
  1122.     },
  1123.     syncFocusEl : function(row, col, hscroll){
  1124.         var xy = row;
  1125.         if(!Ext.isArray(xy)){
  1126.             row = Math.min(row, Math.max(0, this.getRows().length-1));
  1127.             xy = this.getResolvedXY(this.resolveCell(row, col, hscroll));
  1128.         }
  1129.         this.focusEl.setXY(xy||this.scroller.getXY());
  1130.     },
  1131.     ensureVisible : function(row, col, hscroll){
  1132.         var resolved = this.resolveCell(row, col, hscroll);
  1133.         if(!resolved || !resolved.row){
  1134.             return;
  1135.         }
  1136.         var rowEl = resolved.row, 
  1137.             cellEl = resolved.cell,
  1138.             c = this.scroller.dom,
  1139.             ctop = 0,
  1140.             p = rowEl, 
  1141.             stop = this.el.dom;
  1142.             
  1143.         while(p && p != stop){
  1144.             ctop += p.offsetTop;
  1145.             p = p.offsetParent;
  1146.         }
  1147.         
  1148.         ctop -= this.mainHd.dom.offsetHeight;
  1149.         stop = parseInt(c.scrollTop, 10);
  1150.         
  1151.         var cbot = ctop + rowEl.offsetHeight,
  1152.             ch = c.clientHeight,
  1153.             sbot = stop + ch;
  1154.         
  1155.         if(ctop < stop){
  1156.           c.scrollTop = ctop;
  1157.         }else if(cbot > sbot){
  1158.             c.scrollTop = cbot-ch;
  1159.         }
  1160.         if(hscroll !== false){
  1161.             var cleft = parseInt(cellEl.offsetLeft, 10);
  1162.             var cright = cleft + cellEl.offsetWidth;
  1163.             var sleft = parseInt(c.scrollLeft, 10);
  1164.             var sright = sleft + c.clientWidth;
  1165.             if(cleft < sleft){
  1166.                 c.scrollLeft = cleft;
  1167.             }else if(cright > sright){
  1168.                 c.scrollLeft = cright-c.clientWidth;
  1169.             }
  1170.         }
  1171.         return this.getResolvedXY(resolved);
  1172.     },
  1173.     
  1174.     insertRows : function(dm, firstRow, lastRow, isUpdate){
  1175.         var last = dm.getCount() - 1;
  1176.         if(!isUpdate && firstRow === 0 && lastRow >= last){
  1177.     this.fireEvent('beforerowsinserted', this, firstRow, lastRow);
  1178.             this.refresh();
  1179.     this.fireEvent('rowsinserted', this, firstRow, lastRow);
  1180.         }else{
  1181.             if(!isUpdate){
  1182.                 this.fireEvent('beforerowsinserted', this, firstRow, lastRow);
  1183.             }
  1184.             var html = this.renderRows(firstRow, lastRow),
  1185.                 before = this.getRow(firstRow);
  1186.             if(before){
  1187.                 if(firstRow === 0){
  1188.                     Ext.fly(this.getRow(0)).removeClass(this.firstRowCls);
  1189.                 }
  1190.                 Ext.DomHelper.insertHtml('beforeBegin', before, html);
  1191.             }else{
  1192.                 var r = this.getRow(last - 1);
  1193.                 if(r){
  1194.                     Ext.fly(r).removeClass(this.lastRowCls);
  1195.                 }
  1196.                 Ext.DomHelper.insertHtml('beforeEnd', this.mainBody.dom, html);
  1197.             }
  1198.             if(!isUpdate){
  1199.                 this.fireEvent('rowsinserted', this, firstRow, lastRow);
  1200.                 this.processRows(firstRow);
  1201.             }else if(firstRow === 0 || firstRow >= last){
  1202.                 
  1203.                 Ext.fly(this.getRow(firstRow)).addClass(firstRow === 0 ? this.firstRowCls : this.lastRowCls);
  1204.             }
  1205.         }
  1206.         this.syncFocusEl(firstRow);
  1207.     },
  1208.     
  1209.     deleteRows : function(dm, firstRow, lastRow){
  1210.         if(dm.getRowCount()<1){
  1211.             this.refresh();
  1212.         }else{
  1213.             this.fireEvent('beforerowsdeleted', this, firstRow, lastRow);
  1214.             this.removeRows(firstRow, lastRow);
  1215.             this.processRows(firstRow);
  1216.             this.fireEvent('rowsdeleted', this, firstRow, lastRow);
  1217.         }
  1218.     },
  1219.     
  1220.     getColumnStyle : function(col, isHeader){
  1221.         var style = !isHeader ? (this.cm.config[col].css || '') : '';
  1222.         style += 'width:'+this.getColumnWidth(col)+';';
  1223.         if(this.cm.isHidden(col)){
  1224.             style += 'display:none;';
  1225.         }
  1226.         var align = this.cm.config[col].align;
  1227.         if(align){
  1228.             style += 'text-align:'+align+';';
  1229.         }
  1230.         return style;
  1231.     },
  1232.     
  1233.     getColumnWidth : function(col){
  1234.         var w = this.cm.getColumnWidth(col);
  1235.         if(Ext.isNumber(w)){
  1236.             return (Ext.isBorderBox || (Ext.isWebKit && !Ext.isSafari2) ? w : (w - this.borderWidth > 0 ? w - this.borderWidth : 0)) + 'px';
  1237.         }
  1238.         return w;
  1239.     },
  1240.     
  1241.     getTotalWidth : function(){
  1242.         return this.cm.getTotalWidth()+'px';
  1243.     },
  1244.     
  1245.     fitColumns : function(preventRefresh, onlyExpand, omitColumn){
  1246.         var cm = this.cm, i;
  1247.         var tw = cm.getTotalWidth(false);
  1248.         var aw = this.grid.getGridEl().getWidth(true)-this.getScrollOffset();
  1249.         if(aw < 20){ 
  1250.             return;
  1251.         }
  1252.         var extra = aw - tw;
  1253.         if(extra === 0){
  1254.             return false;
  1255.         }
  1256.         var vc = cm.getColumnCount(true);
  1257.         var ac = vc-(Ext.isNumber(omitColumn) ? 1 : 0);
  1258.         if(ac === 0){
  1259.             ac = 1;
  1260.             omitColumn = undefined;
  1261.         }
  1262.         var colCount = cm.getColumnCount();
  1263.         var cols = [];
  1264.         var extraCol = 0;
  1265.         var width = 0;
  1266.         var w;
  1267.         for (i = 0; i < colCount; i++){
  1268.             if(!cm.isHidden(i) && !cm.isFixed(i) && i !== omitColumn){
  1269.                 w = cm.getColumnWidth(i);
  1270.                 cols.push(i);
  1271.                 extraCol = i;
  1272.                 cols.push(w);
  1273.                 width += w;
  1274.             }
  1275.         }
  1276.         var frac = (aw - cm.getTotalWidth())/width;
  1277.         while (cols.length){
  1278.             w = cols.pop();
  1279.             i = cols.pop();
  1280.             cm.setColumnWidth(i, Math.max(this.grid.minColumnWidth, Math.floor(w + w*frac)), true);
  1281.         }
  1282.         if((tw = cm.getTotalWidth(false)) > aw){
  1283.             var adjustCol = ac != vc ? omitColumn : extraCol;
  1284.              cm.setColumnWidth(adjustCol, Math.max(1,
  1285.                      cm.getColumnWidth(adjustCol)- (tw-aw)), true);
  1286.         }
  1287.         if(preventRefresh !== true){
  1288.             this.updateAllColumnWidths();
  1289.         }
  1290.         return true;
  1291.     },
  1292.     
  1293.     autoExpand : function(preventUpdate){
  1294.         var g = this.grid, cm = this.cm;
  1295.         if(!this.userResized && g.autoExpandColumn){
  1296.             var tw = cm.getTotalWidth(false);
  1297.             var aw = this.grid.getGridEl().getWidth(true)-this.getScrollOffset();
  1298.             if(tw != aw){
  1299.                 var ci = cm.getIndexById(g.autoExpandColumn);
  1300.                 var currentWidth = cm.getColumnWidth(ci);
  1301.                 var cw = Math.min(Math.max(((aw-tw)+currentWidth), g.autoExpandMin), g.autoExpandMax);
  1302.                 if(cw != currentWidth){
  1303.                     cm.setColumnWidth(ci, cw, true);
  1304.                     if(preventUpdate !== true){
  1305.                         this.updateColumnWidth(ci, cw);
  1306.                     }
  1307.                 }
  1308.             }
  1309.         }
  1310.     },
  1311.     
  1312.     getColumnData : function(){
  1313.         
  1314.         var cs = [], cm = this.cm, colCount = cm.getColumnCount();
  1315.         for(var i = 0; i < colCount; i++){
  1316.             var name = cm.getDataIndex(i);
  1317.             cs[i] = {
  1318.                 name : (!Ext.isDefined(name) ? this.ds.fields.get(i).name : name),
  1319.                 renderer : cm.getRenderer(i),
  1320.                 scope: cm.getRendererScope(i),
  1321.                 id : cm.getColumnId(i),
  1322.                 style : this.getColumnStyle(i)
  1323.             };
  1324.         }
  1325.         return cs;
  1326.     },
  1327.     
  1328.     renderRows : function(startRow, endRow){
  1329.         
  1330.         var g = this.grid, cm = g.colModel, ds = g.store, stripe = g.stripeRows;
  1331.         var colCount = cm.getColumnCount();
  1332.         if(ds.getCount() < 1){
  1333.             return '';
  1334.         }
  1335.         var cs = this.getColumnData();
  1336.         startRow = startRow || 0;
  1337.         endRow = !Ext.isDefined(endRow) ? ds.getCount()-1 : endRow;
  1338.         
  1339.         var rs = ds.getRange(startRow, endRow);
  1340.         return this.doRender(cs, rs, ds, startRow, colCount, stripe);
  1341.     },
  1342.     
  1343.     renderBody : function(){
  1344.         var markup = this.renderRows() || '&#160;';
  1345.         return this.templates.body.apply({rows: markup});
  1346.     },
  1347.     
  1348.     refreshRow : function(record){
  1349.         var ds = this.ds, index;
  1350.         if(Ext.isNumber(record)){
  1351.             index = record;
  1352.             record = ds.getAt(index);
  1353.             if(!record){
  1354.                 return;
  1355.             }
  1356.         }else{
  1357.             index = ds.indexOf(record);
  1358.             if(index < 0){
  1359.                 return;
  1360.             }
  1361.         }
  1362.         this.insertRows(ds, index, index, true);
  1363.         this.getRow(index).rowIndex = index;
  1364.         this.onRemove(ds, record, index+1, true);
  1365.         this.fireEvent('rowupdated', this, index, record);
  1366.     },
  1367.     
  1368.     refresh : function(headersToo){
  1369.         this.fireEvent('beforerefresh', this);
  1370.         this.grid.stopEditing(true);
  1371.         var result = this.renderBody();
  1372.         this.mainBody.update(result).setWidth(this.getTotalWidth());
  1373.         if(headersToo === true){
  1374.             this.updateHeaders();
  1375.             this.updateHeaderSortState();
  1376.         }
  1377.         this.processRows(0, true);
  1378.         this.layout();
  1379.         this.applyEmptyText();
  1380.         this.fireEvent('refresh', this);
  1381.     },
  1382.     
  1383.     applyEmptyText : function(){
  1384.         if(this.emptyText && !this.hasRows()){
  1385.             this.mainBody.update('<div class="x-grid-empty">' + this.emptyText + '</div>');
  1386.         }
  1387.     },
  1388.     
  1389.     updateHeaderSortState : function(){
  1390.         var state = this.ds.getSortState();
  1391.         if(!state){
  1392.             return;
  1393.         }
  1394.         if(!this.sortState || (this.sortState.field != state.field || this.sortState.direction != state.direction)){
  1395.             this.grid.fireEvent('sortchange', this.grid, state);
  1396.         }
  1397.         this.sortState = state;
  1398.         var sortColumn = this.cm.findColumnIndex(state.field);
  1399.         if(sortColumn != -1){
  1400.             var sortDir = state.direction;
  1401.             this.updateSortIcon(sortColumn, sortDir);
  1402.         }
  1403.     },
  1404.     
  1405.     clearHeaderSortState : function(){
  1406.         if(!this.sortState){
  1407.             return;
  1408.         }
  1409.         this.grid.fireEvent('sortchange', this.grid, null);
  1410.         this.mainHd.select('td').removeClass(this.sortClasses);
  1411.         delete this.sortState;
  1412.     },
  1413.     
  1414.     destroy : function(){
  1415.         if(this.colMenu){
  1416.             Ext.menu.MenuMgr.unregister(this.colMenu);
  1417.             this.colMenu.destroy();
  1418.             delete this.colMenu;
  1419.         }
  1420.         if(this.hmenu){
  1421.             Ext.menu.MenuMgr.unregister(this.hmenu);
  1422.             this.hmenu.destroy();
  1423.             delete this.hmenu;
  1424.         }
  1425.         this.initData(null, null);
  1426.         this.purgeListeners();
  1427.         Ext.fly(this.innerHd).un("click", this.handleHdDown, this);
  1428.         if(this.grid.enableColumnMove){
  1429.             Ext.destroy(
  1430.                 this.columnDrag.el,
  1431.                 this.columnDrag.proxy.ghost,
  1432.                 this.columnDrag.proxy.el,
  1433.                 this.columnDrop.el,
  1434.                 this.columnDrop.proxyTop,
  1435.                 this.columnDrop.proxyBottom,
  1436.                 this.columnDrag.dragData.ddel,
  1437.                 this.columnDrag.dragData.header
  1438.             );
  1439.             if (this.columnDrag.proxy.anim) {
  1440.                 Ext.destroy(this.columnDrag.proxy.anim);
  1441.             }
  1442.             delete this.columnDrag.proxy.ghost;
  1443.             delete this.columnDrag.dragData.ddel;
  1444.             delete this.columnDrag.dragData.header;
  1445.             this.columnDrag.destroy();
  1446.             delete Ext.dd.DDM.locationCache[this.columnDrag.id];
  1447.             delete this.columnDrag._domRef;
  1448.             delete this.columnDrop.proxyTop;
  1449.             delete this.columnDrop.proxyBottom;
  1450.             this.columnDrop.destroy();
  1451.             delete Ext.dd.DDM.locationCache["gridHeader" + this.grid.getGridEl().id];
  1452.             delete this.columnDrop._domRef;
  1453.             delete Ext.dd.DDM.ids[this.columnDrop.ddGroup];
  1454.         }
  1455.         if (this.splitZone){ 
  1456.             this.splitZone.destroy();
  1457.             delete this.splitZone._domRef;
  1458.             delete Ext.dd.DDM.ids["gridSplitters" + this.grid.getGridEl().id];
  1459.         }
  1460.         Ext.fly(this.innerHd).removeAllListeners();
  1461.         Ext.removeNode(this.innerHd);
  1462.         delete this.innerHd;
  1463.         Ext.destroy(
  1464.             this.el,
  1465.             this.mainWrap,
  1466.             this.mainHd,
  1467.             this.scroller,
  1468.             this.mainBody,
  1469.             this.focusEl,
  1470.             this.resizeMarker,
  1471.             this.resizeProxy,
  1472.             this.activeHdBtn,
  1473.             this.dragZone,
  1474.             this.splitZone,
  1475.             this._flyweight
  1476.         );
  1477.         delete this.grid.container;
  1478.         if(this.dragZone){
  1479.             this.dragZone.destroy();
  1480.         }
  1481.         Ext.dd.DDM.currentTarget = null;
  1482.         delete Ext.dd.DDM.locationCache[this.grid.getGridEl().id];
  1483.         Ext.EventManager.removeResizeListener(this.onWindowResize, this);
  1484.     },
  1485.     
  1486.     onDenyColumnHide : function(){
  1487.     },
  1488.     
  1489.     render : function(){
  1490.         if(this.autoFill){
  1491.             var ct = this.grid.ownerCt;
  1492.             if (ct && ct.getLayout()){
  1493.                 ct.on('afterlayout', function(){ 
  1494.                     this.fitColumns(true, true);
  1495.                     this.updateHeaders(); 
  1496.                 }, this, {single: true}); 
  1497.             }else{ 
  1498.                 this.fitColumns(true, true); 
  1499.             }
  1500.         }else if(this.forceFit){
  1501.             this.fitColumns(true, false);
  1502.         }else if(this.grid.autoExpandColumn){
  1503.             this.autoExpand(true);
  1504.         }
  1505.         this.renderUI();
  1506.     },
  1507.     
  1508.     
  1509.     initData : function(ds, cm){
  1510.         if(this.ds){
  1511.             this.ds.un('load', this.onLoad, this);
  1512.             this.ds.un('datachanged', this.onDataChange, this);
  1513.             this.ds.un('add', this.onAdd, this);
  1514.             this.ds.un('remove', this.onRemove, this);
  1515.             this.ds.un('update', this.onUpdate, this);
  1516.             this.ds.un('clear', this.onClear, this);
  1517.             if(this.ds !== ds && this.ds.autoDestroy){
  1518.                 this.ds.destroy();
  1519.             }
  1520.         }
  1521.         if(ds){
  1522.             ds.on({
  1523.                 scope: this,
  1524.                 load: this.onLoad,
  1525.                 datachanged: this.onDataChange,
  1526.                 add: this.onAdd,
  1527.                 remove: this.onRemove,
  1528.                 update: this.onUpdate,
  1529.                 clear: this.onClear
  1530.             });
  1531.         }
  1532.         this.ds = ds;
  1533.         if(this.cm){
  1534.             this.cm.un('configchange', this.onColConfigChange, this);
  1535.             this.cm.un('widthchange', this.onColWidthChange, this);
  1536.             this.cm.un('headerchange', this.onHeaderChange, this);
  1537.             this.cm.un('hiddenchange', this.onHiddenChange, this);
  1538.             this.cm.un('columnmoved', this.onColumnMove, this);
  1539.         }
  1540.         if(cm){
  1541.             delete this.lastViewWidth;
  1542.             cm.on({
  1543.                 scope: this,
  1544.                 configchange: this.onColConfigChange,
  1545.                 widthchange: this.onColWidthChange,
  1546.                 headerchange: this.onHeaderChange,
  1547.                 hiddenchange: this.onHiddenChange,
  1548.                 columnmoved: this.onColumnMove
  1549.             });
  1550.         }
  1551.         this.cm = cm;
  1552.     },
  1553.     
  1554.     onDataChange : function(){
  1555.         this.refresh();
  1556.         this.updateHeaderSortState();
  1557.         this.syncFocusEl(0);
  1558.     },
  1559.     
  1560.     onClear : function(){
  1561.         this.refresh();
  1562.         this.syncFocusEl(0);
  1563.     },
  1564.     
  1565.     onUpdate : function(ds, record){
  1566.         this.refreshRow(record);
  1567.     },
  1568.     
  1569.     onAdd : function(ds, records, index){
  1570.         this.insertRows(ds, index, index + (records.length-1));
  1571.     },
  1572.     
  1573.     onRemove : function(ds, record, index, isUpdate){
  1574.         if(isUpdate !== true){
  1575.             this.fireEvent('beforerowremoved', this, index, record);
  1576.         }
  1577.         this.removeRow(index);
  1578.         if(isUpdate !== true){
  1579.             this.processRows(index);
  1580.             this.applyEmptyText();
  1581.             this.fireEvent('rowremoved', this, index, record);
  1582.         }
  1583.     },
  1584.     
  1585.     onLoad : function(){
  1586.         this.scrollToTop.defer(Ext.isGecko ? 1 : 0, this);
  1587.     },
  1588.     
  1589.     onColWidthChange : function(cm, col, width){
  1590.         this.updateColumnWidth(col, width);
  1591.     },
  1592.     
  1593.     onHeaderChange : function(cm, col, text){
  1594.         this.updateHeaders();
  1595.     },
  1596.     
  1597.     onHiddenChange : function(cm, col, hidden){
  1598.         this.updateColumnHidden(col, hidden);
  1599.     },
  1600.     
  1601.     onColumnMove : function(cm, oldIndex, newIndex){
  1602.         this.indexMap = null;
  1603.         var s = this.getScrollState();
  1604.         this.refresh(true);
  1605.         this.restoreScroll(s);
  1606.         this.afterMove(newIndex);
  1607.         this.grid.fireEvent('columnmove', oldIndex, newIndex);
  1608.     },
  1609.     
  1610.     onColConfigChange : function(){
  1611.         delete this.lastViewWidth;
  1612.         this.indexMap = null;
  1613.         this.refresh(true);
  1614.     },
  1615.     
  1616.     
  1617.     initUI : function(grid){
  1618.         grid.on('headerclick', this.onHeaderClick, this);
  1619.     },
  1620.     
  1621.     initEvents : function(){
  1622.     },
  1623.     
  1624.     onHeaderClick : function(g, index){
  1625.         if(this.headersDisabled || !this.cm.isSortable(index)){
  1626.             return;
  1627.         }
  1628.         g.stopEditing(true);
  1629.         g.store.sort(this.cm.getDataIndex(index));
  1630.     },
  1631.     
  1632.     onRowOver : function(e, t){
  1633.         var row;
  1634.         if((row = this.findRowIndex(t)) !== false){
  1635.             this.addRowClass(row, 'x-grid3-row-over');
  1636.         }
  1637.     },
  1638.     
  1639.     onRowOut : function(e, t){
  1640.         var row;
  1641.         if((row = this.findRowIndex(t)) !== false && !e.within(this.getRow(row), true)){
  1642.             this.removeRowClass(row, 'x-grid3-row-over');
  1643.         }
  1644.     },
  1645.     
  1646.     handleWheel : function(e){
  1647.         e.stopPropagation();
  1648.     },
  1649.     
  1650.     onRowSelect : function(row){
  1651.         this.addRowClass(row, this.selectedRowClass);
  1652.     },
  1653.     
  1654.     onRowDeselect : function(row){
  1655.         this.removeRowClass(row, this.selectedRowClass);
  1656.     },
  1657.     
  1658.     onCellSelect : function(row, col){
  1659.         var cell = this.getCell(row, col);
  1660.         if(cell){
  1661.             this.fly(cell).addClass('x-grid3-cell-selected');
  1662.         }
  1663.     },
  1664.     
  1665.     onCellDeselect : function(row, col){
  1666.         var cell = this.getCell(row, col);
  1667.         if(cell){
  1668.             this.fly(cell).removeClass('x-grid3-cell-selected');
  1669.         }
  1670.     },
  1671.     
  1672.     onColumnSplitterMoved : function(i, w){
  1673.         this.userResized = true;
  1674.         var cm = this.grid.colModel;
  1675.         cm.setColumnWidth(i, w, true);
  1676.         if(this.forceFit){
  1677.             this.fitColumns(true, false, i);
  1678.             this.updateAllColumnWidths();
  1679.         }else{
  1680.             this.updateColumnWidth(i, w);
  1681.             this.syncHeaderScroll();
  1682.         }
  1683.         this.grid.fireEvent('columnresize', i, w);
  1684.     },
  1685.     
  1686.     handleHdMenuClick : function(item){
  1687.         var index = this.hdCtxIndex,
  1688.             cm = this.cm, 
  1689.             ds = this.ds,
  1690.             id = item.getItemId();
  1691.         switch(id){
  1692.             case 'asc':
  1693.                 ds.sort(cm.getDataIndex(index), 'ASC');
  1694.                 break;
  1695.             case 'desc':
  1696.                 ds.sort(cm.getDataIndex(index), 'DESC');
  1697.                 break;
  1698.             default:
  1699.                 index = cm.getIndexById(id.substr(4));
  1700.                 if(index != -1){
  1701.                     if(item.checked && cm.getColumnsBy(this.isHideableColumn, this).length <= 1){
  1702.                         this.onDenyColumnHide();
  1703.                         return false;
  1704.                     }
  1705.                     cm.setHidden(index, item.checked);
  1706.                 }
  1707.         }
  1708.         return true;
  1709.     },
  1710.     
  1711.     isHideableColumn : function(c){
  1712.         return !c.hidden && !c.fixed;
  1713.     },
  1714.     
  1715.     beforeColMenuShow : function(){
  1716.         var cm = this.cm,  colCount = cm.getColumnCount();
  1717.         this.colMenu.removeAll();
  1718.         for(var i = 0; i < colCount; i++){
  1719.             if(cm.config[i].fixed !== true && cm.config[i].hideable !== false){
  1720.                 this.colMenu.add(new Ext.menu.CheckItem({
  1721.                     itemId: 'col-'+cm.getColumnId(i),
  1722.                     text: cm.getColumnHeader(i),
  1723.                     checked: !cm.isHidden(i),
  1724.                     hideOnClick:false,
  1725.                     disabled: cm.config[i].hideable === false
  1726.                 }));
  1727.             }
  1728.         }
  1729.     },
  1730.     
  1731.     handleHdDown : function(e, t){
  1732.         if(Ext.fly(t).hasClass('x-grid3-hd-btn')){
  1733.             e.stopEvent();
  1734.             var hd = this.findHeaderCell(t);
  1735.             Ext.fly(hd).addClass('x-grid3-hd-menu-open');
  1736.             var index = this.getCellIndex(hd);
  1737.             this.hdCtxIndex = index;
  1738.             var ms = this.hmenu.items, cm = this.cm;
  1739.             ms.get('asc').setDisabled(!cm.isSortable(index));
  1740.             ms.get('desc').setDisabled(!cm.isSortable(index));
  1741.             this.hmenu.on('hide', function(){
  1742.                 Ext.fly(hd).removeClass('x-grid3-hd-menu-open');
  1743.             }, this, {single:true});
  1744.             this.hmenu.show(t, 'tl-bl?');
  1745.         }
  1746.     },
  1747.     
  1748.     handleHdOver : function(e, t){
  1749.         var hd = this.findHeaderCell(t);
  1750.         if(hd && !this.headersDisabled){
  1751.             this.activeHdRef = t;
  1752.             this.activeHdIndex = this.getCellIndex(hd);
  1753.             var fly = this.fly(hd);
  1754.             this.activeHdRegion = fly.getRegion();
  1755.             if(!this.cm.isMenuDisabled(this.activeHdIndex)){
  1756.                 fly.addClass('x-grid3-hd-over');
  1757.                 this.activeHdBtn = fly.child('.x-grid3-hd-btn');
  1758.                 if(this.activeHdBtn){
  1759.                     this.activeHdBtn.dom.style.height = (hd.firstChild.offsetHeight-1)+'px';
  1760.                 }
  1761.             }
  1762.         }
  1763.     },
  1764.     
  1765.     handleHdMove : function(e, t){
  1766.         var hd = this.findHeaderCell(this.activeHdRef);
  1767.         if(hd && !this.headersDisabled){
  1768.             var hw = this.splitHandleWidth || 5,
  1769.                 r = this.activeHdRegion,
  1770.                 x = e.getPageX(),
  1771.                 ss = hd.style,
  1772.                 cur = '';
  1773.             if(this.grid.enableColumnResize !== false){
  1774.                 if(x - r.left <= hw && this.cm.isResizable(this.activeHdIndex-1)){
  1775.                     cur = Ext.isAir ? 'move' : Ext.isWebKit ? 'e-resize' : 'col-resize'; 
  1776.                 }else if(r.right - x <= (!this.activeHdBtn ? hw : 2) && this.cm.isResizable(this.activeHdIndex)){
  1777.                     cur = Ext.isAir ? 'move' : Ext.isWebKit ? 'w-resize' : 'col-resize';
  1778.                 }
  1779.             }
  1780.             ss.cursor = cur;
  1781.         }
  1782.     },
  1783.     
  1784.     handleHdOut : function(e, t){
  1785.         var hd = this.findHeaderCell(t);
  1786.         if(hd && (!Ext.isIE || !e.within(hd, true))){
  1787.             this.activeHdRef = null;
  1788.             this.fly(hd).removeClass('x-grid3-hd-over');
  1789.             hd.style.cursor = '';
  1790.         }
  1791.     },
  1792.     
  1793.     hasRows : function(){
  1794.         var fc = this.mainBody.dom.firstChild;
  1795.         return fc && fc.nodeType == 1 && fc.className != 'x-grid-empty';
  1796.     },
  1797.     
  1798.     bind : function(d, c){
  1799.         this.initData(d, c);
  1800.     }
  1801. });
  1802. Ext.grid.GridView.SplitDragZone = function(grid, hd){
  1803.     this.grid = grid;
  1804.     this.view = grid.getView();
  1805.     this.marker = this.view.resizeMarker;
  1806.     this.proxy = this.view.resizeProxy;
  1807.     Ext.grid.GridView.SplitDragZone.superclass.constructor.call(this, hd,
  1808.         'gridSplitters' + this.grid.getGridEl().id, {
  1809.         dragElId : Ext.id(this.proxy.dom), resizeFrame:false
  1810.     });
  1811.     this.scroll = false;
  1812.     this.hw = this.view.splitHandleWidth || 5;
  1813. };
  1814. Ext.extend(Ext.grid.GridView.SplitDragZone, Ext.dd.DDProxy, {
  1815.     b4StartDrag : function(x, y){
  1816.         this.view.headersDisabled = true;
  1817.         var h = this.view.mainWrap.getHeight();
  1818.         this.marker.setHeight(h);
  1819.         this.marker.show();
  1820.         this.marker.alignTo(this.view.getHeaderCell(this.cellIndex), 'tl-tl', [-2, 0]);
  1821.         this.proxy.setHeight(h);
  1822.         var w = this.cm.getColumnWidth(this.cellIndex);
  1823.         var minw = Math.max(w-this.grid.minColumnWidth, 0);
  1824.         this.resetConstraints();
  1825.         this.setXConstraint(minw, 1000);
  1826.         this.setYConstraint(0, 0);
  1827.         this.minX = x - minw;
  1828.         this.maxX = x + 1000;
  1829.         this.startPos = x;
  1830.         Ext.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
  1831.     },
  1832.     
  1833.     allowHeaderDrag : function(e){
  1834.         return true;
  1835.     },
  1836.     handleMouseDown : function(e){
  1837.         var t = this.view.findHeaderCell(e.getTarget());
  1838.         if(t && this.allowHeaderDrag(e)){
  1839.             var xy = this.view.fly(t).getXY(), x = xy[0], y = xy[1];
  1840.             var exy = e.getXY(), ex = exy[0];
  1841.             var w = t.offsetWidth, adjust = false;
  1842.             if((ex - x) <= this.hw){
  1843.                 adjust = -1;
  1844.             }else if((x+w) - ex <= this.hw){
  1845.                 adjust = 0;
  1846.             }
  1847.             if(adjust !== false){
  1848.                 this.cm = this.grid.colModel;
  1849.                 var ci = this.view.getCellIndex(t);
  1850.                 if(adjust == -1){
  1851.                   if (ci + adjust < 0) {
  1852.                     return;
  1853.                   }
  1854.                     while(this.cm.isHidden(ci+adjust)){
  1855.                         --adjust;
  1856.                         if(ci+adjust < 0){
  1857.                             return;
  1858.                         }
  1859.                     }
  1860.                 }
  1861.                 this.cellIndex = ci+adjust;
  1862.                 this.split = t.dom;
  1863.                 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
  1864.                     Ext.grid.GridView.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
  1865.                 }
  1866.             }else if(this.view.columnDrag){
  1867.                 this.view.columnDrag.callHandleMouseDown(e);
  1868.             }
  1869.         }
  1870.     },
  1871.     endDrag : function(e){
  1872.         this.marker.hide();
  1873.         var v = this.view;
  1874.         var endX = Math.max(this.minX, e.getPageX());
  1875.         var diff = endX - this.startPos;
  1876.         v.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
  1877.         setTimeout(function(){
  1878.             v.headersDisabled = false;
  1879.         }, 50);
  1880.     },
  1881.     autoOffset : function(){
  1882.         this.setDelta(0,0);
  1883.     }
  1884. });
  1885. Ext.grid.HeaderDragZone = Ext.extend(Ext.dd.DragZone, {
  1886.     maxDragWidth: 120,
  1887.     
  1888.     constructor : function(grid, hd, hd2){
  1889.         this.grid = grid;
  1890.         this.view = grid.getView();
  1891.         this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
  1892.         Ext.grid.HeaderDragZone.superclass.constructor.call(this, hd);
  1893.         if(hd2){
  1894.             this.setHandleElId(Ext.id(hd));
  1895.             this.setOuterHandleElId(Ext.id(hd2));
  1896.         }
  1897.         this.scroll = false;
  1898.     },
  1899.     
  1900.     getDragData : function(e){
  1901.         var t = Ext.lib.Event.getTarget(e);
  1902.         var h = this.view.findHeaderCell(t);
  1903.         if(h){
  1904.             return {ddel: h.firstChild, header:h};
  1905.         }
  1906.         return false;
  1907.     },
  1908.     onInitDrag : function(e){
  1909.         this.view.headersDisabled = true;
  1910.         var clone = this.dragData.ddel.cloneNode(true);
  1911.         clone.id = Ext.id();
  1912.         clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
  1913.         this.proxy.update(clone);
  1914.         return true;
  1915.     },
  1916.     afterValidDrop : function(){
  1917.         var v = this.view;
  1918.         setTimeout(function(){
  1919.             v.headersDisabled = false;
  1920.         }, 50);
  1921.     },
  1922.     afterInvalidDrop : function(){
  1923.         var v = this.view;
  1924.         setTimeout(function(){
  1925.             v.headersDisabled = false;
  1926.         }, 50);
  1927.     }
  1928. });
  1929. Ext.grid.HeaderDropZone = Ext.extend(Ext.dd.DropZone, {
  1930.     proxyOffsets : [-4, -9],
  1931.     fly: Ext.Element.fly,
  1932.     
  1933.     constructor : function(grid, hd, hd2){
  1934.         this.grid = grid;
  1935.         this.view = grid.getView();
  1936.         
  1937.         this.proxyTop = Ext.DomHelper.append(document.body, {
  1938.             cls:"col-move-top", html:"&#160;"
  1939.         }, true);
  1940.         this.proxyBottom = Ext.DomHelper.append(document.body, {
  1941.             cls:"col-move-bottom", html:"&#160;"
  1942.         }, true);
  1943.         this.proxyTop.hide = this.proxyBottom.hide = function(){
  1944.             this.setLeftTop(-100,-100);
  1945.             this.setStyle("visibility", "hidden");
  1946.         };
  1947.         this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
  1948.         
  1949.         
  1950.         Ext.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
  1951.     },
  1952.     getTargetFromEvent : function(e){
  1953.         var t = Ext.lib.Event.getTarget(e);
  1954.         var cindex = this.view.findCellIndex(t);
  1955.         if(cindex !== false){
  1956.             return this.view.getHeaderCell(cindex);
  1957.         }
  1958.     },
  1959.     nextVisible : function(h){
  1960.         var v = this.view, cm = this.grid.colModel;
  1961.         h = h.nextSibling;
  1962.         while(h){
  1963.             if(!cm.isHidden(v.getCellIndex(h))){
  1964.                 return h;
  1965.             }
  1966.             h = h.nextSibling;
  1967.         }
  1968.         return null;
  1969.     },
  1970.     prevVisible : function(h){
  1971.         var v = this.view, cm = this.grid.colModel;
  1972.         h = h.prevSibling;
  1973.         while(h){
  1974.             if(!cm.isHidden(v.getCellIndex(h))){
  1975.                 return h;
  1976.             }
  1977.             h = h.prevSibling;
  1978.         }
  1979.         return null;
  1980.     },
  1981.     positionIndicator : function(h, n, e){
  1982.         var x = Ext.lib.Event.getPageX(e);
  1983.         var r = Ext.lib.Dom.getRegion(n.firstChild);
  1984.         var px, pt, py = r.top + this.proxyOffsets[1];
  1985.         if((r.right - x) <= (r.right-r.left)/2){
  1986.             px = r.right+this.view.borderWidth;
  1987.             pt = "after";
  1988.         }else{
  1989.             px = r.left;
  1990.             pt = "before";
  1991.         }
  1992.         if(this.grid.colModel.isFixed(this.view.getCellIndex(n))){
  1993.             return false;
  1994.         }
  1995.         px +=  this.proxyOffsets[0];
  1996.         this.proxyTop.setLeftTop(px, py);
  1997.         this.proxyTop.show();
  1998.         if(!this.bottomOffset){
  1999.             this.bottomOffset = this.view.mainHd.getHeight();
  2000.         }
  2001.         this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
  2002.         this.proxyBottom.show();
  2003.         return pt;
  2004.     },
  2005.     onNodeEnter : function(n, dd, e, data){
  2006.         if(data.header != n){
  2007.             this.positionIndicator(data.header, n, e);
  2008.         }
  2009.     },
  2010.     onNodeOver : function(n, dd, e, data){
  2011.         var result = false;
  2012.         if(data.header != n){
  2013.             result = this.positionIndicator(data.header, n, e);
  2014.         }
  2015.         if(!result){
  2016.             this.proxyTop.hide();
  2017.             this.proxyBottom.hide();
  2018.         }
  2019.         return result ? this.dropAllowed : this.dropNotAllowed;
  2020.     },
  2021.     onNodeOut : function(n, dd, e, data){
  2022.         this.proxyTop.hide();
  2023.         this.proxyBottom.hide();
  2024.     },
  2025.     onNodeDrop : function(n, dd, e, data){
  2026.         var h = data.header;
  2027.         if(h != n){
  2028.             var cm = this.grid.colModel;
  2029.             var x = Ext.lib.Event.getPageX(e);
  2030.             var r = Ext.lib.Dom.getRegion(n.firstChild);
  2031.             var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
  2032.             var oldIndex = this.view.getCellIndex(h);
  2033.             var newIndex = this.view.getCellIndex(n);
  2034.             if(pt == "after"){
  2035.                 newIndex++;
  2036.             }
  2037.             if(oldIndex < newIndex){
  2038.                 newIndex--;
  2039.             }
  2040.             cm.moveColumn(oldIndex, newIndex);
  2041.             return true;
  2042.         }
  2043.         return false;
  2044.     }
  2045. });
  2046. Ext.grid.GridView.ColumnDragZone = Ext.extend(Ext.grid.HeaderDragZone, {
  2047.     
  2048.     constructor : function(grid, hd){
  2049.         Ext.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
  2050.         this.proxy.el.addClass('x-grid3-col-dd');
  2051.     },
  2052.     
  2053.     handleMouseDown : function(e){
  2054.     },
  2055.     callHandleMouseDown : function(e){
  2056.         Ext.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
  2057.     }
  2058. });
  2059. Ext.grid.SplitDragZone = Ext.extend(Ext.dd.DDProxy, {
  2060.     fly: Ext.Element.fly,
  2061.     
  2062.     constructor : function(grid, hd, hd2){
  2063.         this.grid = grid;
  2064.         this.view = grid.getView();
  2065.         this.proxy = this.view.resizeProxy;
  2066.         Ext.grid.SplitDragZone.superclass.constructor.call(this, hd,
  2067.             "gridSplitters" + this.grid.getGridEl().id, {
  2068.             dragElId : Ext.id(this.proxy.dom), resizeFrame:false
  2069.         });
  2070.         this.setHandleElId(Ext.id(hd));
  2071.         this.setOuterHandleElId(Ext.id(hd2));
  2072.         this.scroll = false;
  2073.     },
  2074.     b4StartDrag : function(x, y){
  2075.         this.view.headersDisabled = true;
  2076.         this.proxy.setHeight(this.view.mainWrap.getHeight());
  2077.         var w = this.cm.getColumnWidth(this.cellIndex);
  2078.         var minw = Math.max(w-this.grid.minColumnWidth, 0);
  2079.         this.resetConstraints();
  2080.         this.setXConstraint(minw, 1000);
  2081.         this.setYConstraint(0, 0);
  2082.         this.minX = x - minw;
  2083.         this.maxX = x + 1000;
  2084.         this.startPos = x;
  2085.         Ext.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
  2086.     },
  2087.     handleMouseDown : function(e){
  2088.         var ev = Ext.EventObject.setEvent(e);
  2089.         var t = this.fly(ev.getTarget());
  2090.         if(t.hasClass("x-grid-split")){
  2091.             this.cellIndex = this.view.getCellIndex(t.dom);
  2092.             this.split = t.dom;
  2093.             this.cm = this.grid.colModel;
  2094.             if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
  2095.                 Ext.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
  2096.             }
  2097.         }
  2098.     },
  2099.     endDrag : function(e){
  2100.         this.view.headersDisabled = false;
  2101.         var endX = Math.max(this.minX, Ext.lib.Event.getPageX(e));
  2102.         var diff = endX - this.startPos;
  2103.         this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
  2104.     },
  2105.     autoOffset : function(){
  2106.         this.setDelta(0,0);
  2107.     }
  2108. });
  2109. Ext.grid.GridDragZone = function(grid, config){
  2110.     this.view = grid.getView();
  2111.     Ext.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
  2112.     this.scroll = false;
  2113.     this.grid = grid;
  2114.     this.ddel = document.createElement('div');
  2115.     this.ddel.className = 'x-grid-dd-wrap';
  2116. };
  2117. Ext.extend(Ext.grid.GridDragZone, Ext.dd.DragZone, {
  2118.     ddGroup : "GridDD",
  2119.     
  2120.     getDragData : function(e){
  2121.         var t = Ext.lib.Event.getTarget(e);
  2122.         var rowIndex = this.view.findRowIndex(t);
  2123.         if(rowIndex !== false){
  2124.             var sm = this.grid.selModel;
  2125.             if(!sm.isSelected(rowIndex) || e.hasModifier()){
  2126.                 sm.handleMouseDown(this.grid, rowIndex, e);
  2127.             }
  2128.             return {grid: this.grid, ddel: this.ddel, rowIndex: rowIndex, selections:sm.getSelections()};
  2129.         }
  2130.         return false;
  2131.     },
  2132.     
  2133.     onInitDrag : function(e){
  2134.         var data = this.dragData;
  2135.         this.ddel.innerHTML = this.grid.getDragDropText();
  2136.         this.proxy.update(this.ddel);
  2137.         
  2138.     },
  2139.     
  2140.     afterRepair : function(){
  2141.         this.dragging = false;
  2142.     },
  2143.     
  2144.     getRepairXY : function(e, data){
  2145.         return false;
  2146.     },
  2147.     onEndDrag : function(data, e){
  2148.         
  2149.     },
  2150.     onValidDrop : function(dd, e, id){
  2151.         
  2152.         this.hideProxy();
  2153.     },
  2154.     beforeInvalidDrop : function(e, id){
  2155.     }
  2156. });
  2157. Ext.grid.ColumnModel = Ext.extend(Ext.util.Observable, {
  2158.     
  2159.     defaultWidth: 100,
  2160.     
  2161.     defaultSortable: false,
  2162.     
  2163.     
  2164.     
  2165.     constructor : function(config){
  2166.         
  2167.     if(config.columns){
  2168.         Ext.apply(this, config);
  2169.         this.setConfig(config.columns, true);
  2170.     }else{
  2171.         this.setConfig(config, true);
  2172.     }
  2173.     this.addEvents(
  2174.         
  2175.         "widthchange",
  2176.         
  2177.         "headerchange",
  2178.         
  2179.         "hiddenchange",
  2180.         
  2181.         "columnmoved",
  2182.         
  2183.         "configchange"
  2184.     );
  2185.     Ext.grid.ColumnModel.superclass.constructor.call(this);
  2186.     },
  2187.     
  2188.     getColumnId : function(index){
  2189.         return this.config[index].id;
  2190.     },
  2191.     getColumnAt : function(index){
  2192.         return this.config[index];
  2193.     },
  2194.     
  2195.     setConfig : function(config, initial){
  2196.         var i, c, len;
  2197.         if(!initial){ 
  2198.             delete this.totalWidth;
  2199.             for(i = 0, len = this.config.length; i < len; i++){
  2200.                 c = this.config[i];
  2201.                 if(c.editor){
  2202.                     c.editor.destroy();
  2203.                 }
  2204.             }
  2205.         }
  2206.         
  2207.         this.defaults = Ext.apply({
  2208.             width: this.defaultWidth,
  2209.             sortable: this.defaultSortable
  2210.         }, this.defaults);
  2211.         this.config = config;
  2212.         this.lookup = {};
  2213.         for(i = 0, len = config.length; i < len; i++){
  2214.             c = Ext.applyIf(config[i], this.defaults);
  2215.             
  2216.             if(typeof c.id == 'undefined'){
  2217.                 c.id = i;
  2218.             }
  2219.             if(!c.isColumn){
  2220.                 var Cls = Ext.grid.Column.types[c.xtype || 'gridcolumn'];
  2221.                 c = new Cls(c);
  2222.                 config[i] = c;
  2223.             }
  2224.             this.lookup[c.id] = c;
  2225.         }
  2226.         if(!initial){
  2227.             this.fireEvent('configchange', this);
  2228.         }
  2229.     },
  2230.     
  2231.     getColumnById : function(id){
  2232.         return this.lookup[id];
  2233.     },
  2234.     
  2235.     getIndexById : function(id){
  2236.         for(var i = 0, len = this.config.length; i < len; i++){
  2237.             if(this.config[i].id == id){
  2238.                 return i;
  2239.             }
  2240.         }
  2241.         return -1;
  2242.     },
  2243.     
  2244.     moveColumn : function(oldIndex, newIndex){
  2245.         var c = this.config[oldIndex];
  2246.         this.config.splice(oldIndex, 1);
  2247.         this.config.splice(newIndex, 0, c);
  2248.         this.dataMap = null;
  2249.         this.fireEvent("columnmoved", this, oldIndex, newIndex);
  2250.     },
  2251.     
  2252.     getColumnCount : function(visibleOnly){
  2253.         if(visibleOnly === true){
  2254.             var c = 0;
  2255.             for(var i = 0, len = this.config.length; i < len; i++){
  2256.                 if(!this.isHidden(i)){
  2257.                     c++;
  2258.                 }
  2259.             }
  2260.             return c;
  2261.         }
  2262.         return this.config.length;
  2263.     },
  2264.     
  2265.     getColumnsBy : function(fn, scope){
  2266.         var r = [];
  2267.         for(var i = 0, len = this.config.length; i < len; i++){
  2268.             var c = this.config[i];
  2269.             if(fn.call(scope||this, c, i) === true){
  2270.                 r[r.length] = c;
  2271.             }
  2272.         }
  2273.         return r;
  2274.     },
  2275.     
  2276.     isSortable : function(col){
  2277.         return !!this.config[col].sortable;
  2278.     },
  2279.     
  2280.     isMenuDisabled : function(col){
  2281.         return !!this.config[col].menuDisabled;
  2282.     },
  2283.     
  2284.     getRenderer : function(col){
  2285.         if(!this.config[col].renderer){
  2286.             return Ext.grid.ColumnModel.defaultRenderer;
  2287.         }
  2288.         return this.config[col].renderer;
  2289.     },
  2290.     
  2291.     getRendererScope : function(col){
  2292.         return this.config[col].scope;
  2293.     },
  2294.     
  2295.     setRenderer : function(col, fn){
  2296.         this.config[col].renderer = fn;
  2297.     },
  2298.     
  2299.     getColumnWidth : function(col){
  2300.         return this.config[col].width;
  2301.     },
  2302.     
  2303.     setColumnWidth : function(col, width, suppressEvent){
  2304.         this.config[col].width = width;
  2305.         this.totalWidth = null;
  2306.         if(!suppressEvent){
  2307.              this.fireEvent("widthchange", this, col, width);
  2308.         }
  2309.     },
  2310.     
  2311.     getTotalWidth : function(includeHidden){
  2312.         if(!this.totalWidth){
  2313.             this.totalWidth = 0;
  2314.             for(var i = 0, len = this.config.length; i < len; i++){
  2315.                 if(includeHidden || !this.isHidden(i)){
  2316.                     this.totalWidth += this.getColumnWidth(i);
  2317.                 }
  2318.             }
  2319.         }
  2320.         return this.totalWidth;
  2321.     },
  2322.     
  2323.     getColumnHeader : function(col){
  2324.         return this.config[col].header;
  2325.     },
  2326.     
  2327.     setColumnHeader : function(col, header){
  2328.         this.config[col].header = header;
  2329.         this.fireEvent("headerchange", this, col, header);
  2330.     },
  2331.     
  2332.     getColumnTooltip : function(col){
  2333.             return this.config[col].tooltip;
  2334.     },
  2335.     
  2336.     setColumnTooltip : function(col, tooltip){
  2337.             this.config[col].tooltip = tooltip;
  2338.     },
  2339.     
  2340.     getDataIndex : function(col){
  2341.         return this.config[col].dataIndex;
  2342.     },
  2343.     
  2344.     setDataIndex : function(col, dataIndex){
  2345.         this.config[col].dataIndex = dataIndex;
  2346.     },
  2347.     
  2348.     findColumnIndex : function(dataIndex){
  2349.         var c = this.config;
  2350.         for(var i = 0, len = c.length; i < len; i++){
  2351.             if(c[i].dataIndex == dataIndex){
  2352.                 return i;
  2353.             }
  2354.         }
  2355.         return -1;
  2356.     },
  2357.     
  2358.     isCellEditable : function(colIndex, rowIndex){
  2359.         return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
  2360.     },
  2361.     
  2362.     getCellEditor : function(colIndex, rowIndex){
  2363.         return this.config[colIndex].getCellEditor(rowIndex);
  2364.     },
  2365.     
  2366.     setEditable : function(col, editable){
  2367.         this.config[col].editable = editable;
  2368.     },
  2369.     
  2370.     isHidden : function(colIndex){
  2371.         return !!this.config[colIndex].hidden; 
  2372.     },
  2373.     
  2374.     isFixed : function(colIndex){
  2375.         return !!this.config[colIndex].fixed;
  2376.     },
  2377.     
  2378.     isResizable : function(colIndex){
  2379.         return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
  2380.     },
  2381.     
  2382.     setHidden : function(colIndex, hidden){
  2383.         var c = this.config[colIndex];
  2384.         if(c.hidden !== hidden){
  2385.             c.hidden = hidden;
  2386.             this.totalWidth = null;
  2387.             this.fireEvent("hiddenchange", this, colIndex, hidden);
  2388.         }
  2389.     },
  2390.     
  2391.     setEditor : function(col, editor){
  2392.         Ext.destroy(this.config[col].editor);
  2393.         this.config[col].editor = editor;
  2394.     },
  2395.     
  2396.     destroy : function(){
  2397.         for(var i = 0, c = this.config, len = c.length; i < len; i++){
  2398.             Ext.destroy(c[i].editor);
  2399.         }
  2400.         this.purgeListeners();
  2401.     }
  2402. });
  2403. Ext.grid.ColumnModel.defaultRenderer = function(value){
  2404.     if(typeof value == "string" && value.length < 1){
  2405.         return "&#160;";
  2406.     }
  2407.     return value;
  2408. };
  2409. Ext.grid.AbstractSelectionModel = Ext.extend(Ext.util.Observable,  {
  2410.     
  2411.     
  2412.     constructor : function(){
  2413.         this.locked = false;
  2414.         Ext.grid.AbstractSelectionModel.superclass.constructor.call(this);
  2415.     },
  2416.     
  2417.     init : function(grid){
  2418.         this.grid = grid;
  2419.         this.initEvents();
  2420.     },
  2421.     
  2422.     lock : function(){
  2423.         this.locked = true;
  2424.     },
  2425.     
  2426.     unlock : function(){
  2427.         this.locked = false;
  2428.     },
  2429.     
  2430.     isLocked : function(){
  2431.         return this.locked;
  2432.     },
  2433.     
  2434.     destroy: function(){
  2435.         this.purgeListeners();
  2436.     }
  2437. });
  2438. Ext.grid.RowSelectionModel = Ext.extend(Ext.grid.AbstractSelectionModel,  {
  2439.     
  2440.     singleSelect : false,
  2441.     
  2442.     constructor : function(config){
  2443.         Ext.apply(this, config);
  2444.         this.selections = new Ext.util.MixedCollection(false, function(o){
  2445.             return o.id;
  2446.         });
  2447.         this.last = false;
  2448.         this.lastActive = false;
  2449.         this.addEvents(
  2450.         
  2451.         'selectionchange',
  2452.         
  2453.         'beforerowselect',
  2454.         
  2455.         'rowselect',
  2456.         
  2457.         'rowdeselect'
  2458.         );
  2459.         Ext.grid.RowSelectionModel.superclass.constructor.call(this);
  2460.     },
  2461.     
  2462.     
  2463.     initEvents : function(){
  2464.         if(!this.grid.enableDragDrop && !this.grid.enableDrag){
  2465.             this.grid.on('rowmousedown', this.handleMouseDown, this);
  2466.         }
  2467.         this.rowNav = new Ext.KeyNav(this.grid.getGridEl(), {
  2468.             'up' : function(e){
  2469.                 if(!e.shiftKey || this.singleSelect){
  2470.                     this.selectPrevious(false);
  2471.                 }else if(this.last !== false && this.lastActive !== false){
  2472.                     var last = this.last;
  2473.                     this.selectRange(this.last,  this.lastActive-1);
  2474.                     this.grid.getView().focusRow(this.lastActive);
  2475.                     if(last !== false){
  2476.                         this.last = last;
  2477.                     }
  2478.                 }else{
  2479.                     this.selectFirstRow();
  2480.                 }
  2481.             },
  2482.             'down' : function(e){
  2483.                 if(!e.shiftKey || this.singleSelect){
  2484.                     this.selectNext(false);
  2485.                 }else if(this.last !== false && this.lastActive !== false){
  2486.                     var last = this.last;
  2487.                     this.selectRange(this.last,  this.lastActive+1);
  2488.                     this.grid.getView().focusRow(this.lastActive);
  2489.                     if(last !== false){
  2490.                         this.last = last;
  2491.                     }
  2492.                 }else{
  2493.                     this.selectFirstRow();
  2494.                 }
  2495.             },
  2496.             scope: this
  2497.         });
  2498.         this.grid.getView().on({
  2499.             scope: this,
  2500.             refresh: this.onRefresh,
  2501.             rowupdated: this.onRowUpdated,
  2502.             rowremoved: this.onRemove
  2503.         });
  2504.     },
  2505.     
  2506.     onRefresh : function(){
  2507.         var ds = this.grid.store, index;
  2508.         var s = this.getSelections();
  2509.         this.clearSelections(true);
  2510.         for(var i = 0, len = s.length; i < len; i++){
  2511.             var r = s[i];
  2512.             if((index = ds.indexOfId(r.id)) != -1){
  2513.                 this.selectRow(index, true);
  2514.             }
  2515.         }
  2516.         if(s.length != this.selections.getCount()){
  2517.             this.fireEvent('selectionchange', this);
  2518.         }
  2519.     },
  2520.     
  2521.     onRemove : function(v, index, r){
  2522.         if(this.selections.remove(r) !== false){
  2523.             this.fireEvent('selectionchange', this);
  2524.         }
  2525.     },
  2526.     
  2527.     onRowUpdated : function(v, index, r){
  2528.         if(this.isSelected(r)){
  2529.             v.onRowSelect(index);
  2530.         }
  2531.     },
  2532.     
  2533.     selectRecords : function(records, keepExisting){
  2534.         if(!keepExisting){
  2535.             this.clearSelections();
  2536.         }
  2537.         var ds = this.grid.store;
  2538.         for(var i = 0, len = records.length; i < len; i++){
  2539.             this.selectRow(ds.indexOf(records[i]), true);
  2540.         }
  2541.     },
  2542.     
  2543.     getCount : function(){
  2544.         return this.selections.length;
  2545.     },
  2546.     
  2547.     selectFirstRow : function(){
  2548.         this.selectRow(0);
  2549.     },
  2550.     
  2551.     selectLastRow : function(keepExisting){
  2552.         this.selectRow(this.grid.store.getCount() - 1, keepExisting);
  2553.     },
  2554.     
  2555.     selectNext : function(keepExisting){
  2556.         if(this.hasNext()){
  2557.             this.selectRow(this.last+1, keepExisting);
  2558.             this.grid.getView().focusRow(this.last);
  2559.             return true;
  2560.         }
  2561.         return false;
  2562.     },
  2563.     
  2564.     selectPrevious : function(keepExisting){
  2565.         if(this.hasPrevious()){
  2566.             this.selectRow(this.last-1, keepExisting);
  2567.             this.grid.getView().focusRow(this.last);
  2568.             return true;
  2569.         }
  2570.         return false;
  2571.     },
  2572.     
  2573.     hasNext : function(){
  2574.         return this.last !== false && (this.last+1) < this.grid.store.getCount();
  2575.     },
  2576.     
  2577.     hasPrevious : function(){
  2578.         return !!this.last;
  2579.     },
  2580.     
  2581.     getSelections : function(){
  2582.         return [].concat(this.selections.items);
  2583.     },
  2584.     
  2585.     getSelected : function(){
  2586.         return this.selections.itemAt(0);
  2587.     },
  2588.     
  2589.     each : function(fn, scope){
  2590.         var s = this.getSelections();
  2591.         for(var i = 0, len = s.length; i < len; i++){
  2592.             if(fn.call(scope || this, s[i], i) === false){
  2593.                 return false;
  2594.             }
  2595.         }
  2596.         return true;
  2597.     },
  2598.     
  2599.     clearSelections : function(fast){
  2600.         if(this.isLocked()){
  2601.             return;
  2602.         }
  2603.         if(fast !== true){
  2604.             var ds = this.grid.store;
  2605.             var s = this.selections;
  2606.             s.each(function(r){
  2607.                 this.deselectRow(ds.indexOfId(r.id));
  2608.             }, this);
  2609.             s.clear();
  2610.         }else{
  2611.             this.selections.clear();
  2612.         }
  2613.         this.last = false;
  2614.     },
  2615.     
  2616.     selectAll : function(){
  2617.         if(this.isLocked()){
  2618.             return;
  2619.         }
  2620.         this.selections.clear();
  2621.         for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
  2622.             this.selectRow(i, true);
  2623.         }
  2624.     },
  2625.     
  2626.     hasSelection : function(){
  2627.         return this.selections.length > 0;
  2628.     },
  2629.     
  2630.     isSelected : function(index){
  2631.         var r = Ext.isNumber(index) ? this.grid.store.getAt(index) : index;
  2632.         return (r && this.selections.key(r.id) ? true : false);
  2633.     },
  2634.     
  2635.     isIdSelected : function(id){
  2636.         return (this.selections.key(id) ? true : false);
  2637.     },
  2638.     
  2639.     handleMouseDown : function(g, rowIndex, e){
  2640.         if(e.button !== 0 || this.isLocked()){
  2641.             return;
  2642.         }
  2643.         var view = this.grid.getView();
  2644.         if(e.shiftKey && !this.singleSelect && this.last !== false){
  2645.             var last = this.last;
  2646.             this.selectRange(last, rowIndex, e.ctrlKey);
  2647.             this.last = last; 
  2648.             view.focusRow(rowIndex);
  2649.         }else{
  2650.             var isSelected = this.isSelected(rowIndex);
  2651.             if(e.ctrlKey && isSelected){
  2652.                 this.deselectRow(rowIndex);
  2653.             }else if(!isSelected || this.getCount() > 1){
  2654.                 this.selectRow(rowIndex, e.ctrlKey || e.shiftKey);
  2655.                 view.focusRow(rowIndex);
  2656.             }
  2657.         }
  2658.     },
  2659.     
  2660.     selectRows : function(rows, keepExisting){
  2661.         if(!keepExisting){
  2662.             this.clearSelections();
  2663.         }
  2664.         for(var i = 0, len = rows.length; i < len; i++){
  2665.             this.selectRow(rows[i], true);
  2666.         }
  2667.     },
  2668.     
  2669.     selectRange : function(startRow, endRow, keepExisting){
  2670.         var i;
  2671.         if(this.isLocked()){
  2672.             return;
  2673.         }
  2674.         if(!keepExisting){
  2675.             this.clearSelections();
  2676.         }
  2677.         if(startRow <= endRow){
  2678.             for(i = startRow; i <= endRow; i++){
  2679.                 this.selectRow(i, true);
  2680.             }
  2681.         }else{
  2682.             for(i = startRow; i >= endRow; i--){
  2683.                 this.selectRow(i, true);
  2684.             }
  2685.         }
  2686.     },
  2687.     
  2688.     deselectRange : function(startRow, endRow, preventViewNotify){
  2689.         if(this.isLocked()){
  2690.             return;
  2691.         }
  2692.         for(var i = startRow; i <= endRow; i++){
  2693.             this.deselectRow(i, preventViewNotify);
  2694.         }
  2695.     },
  2696.     
  2697.     selectRow : function(index, keepExisting, preventViewNotify){
  2698.         if(this.isLocked() || (index < 0 || index >= this.grid.store.getCount()) || (keepExisting && this.isSelected(index))){
  2699.             return;
  2700.         }
  2701.         var r = this.grid.store.getAt(index);
  2702.         if(r && this.fireEvent('beforerowselect', this, index, keepExisting, r) !== false){
  2703.             if(!keepExisting || this.singleSelect){
  2704.                 this.clearSelections();
  2705.             }
  2706.             this.selections.add(r);
  2707.             this.last = this.lastActive = index;
  2708.             if(!preventViewNotify){
  2709.                 this.grid.getView().onRowSelect(index);
  2710.             }
  2711.             this.fireEvent('rowselect', this, index, r);
  2712.             this.fireEvent('selectionchange', this);
  2713.         }
  2714.     },
  2715.     
  2716.     deselectRow : function(index, preventViewNotify){
  2717.         if(this.isLocked()){
  2718.             return;
  2719.         }
  2720.         if(this.last == index){
  2721.             this.last = false;
  2722.         }
  2723.         if(this.lastActive == index){
  2724.             this.lastActive = false;
  2725.         }
  2726.         var r = this.grid.store.getAt(index);
  2727.         if(r){
  2728.             this.selections.remove(r);
  2729.             if(!preventViewNotify){
  2730.                 this.grid.getView().onRowDeselect(index);
  2731.             }
  2732.             this.fireEvent('rowdeselect', this, index, r);
  2733.             this.fireEvent('selectionchange', this);
  2734.         }
  2735.     },
  2736.     
  2737.     restoreLast : function(){
  2738.         if(this._last){
  2739.             this.last = this._last;
  2740.         }
  2741.     },
  2742.     
  2743.     acceptsNav : function(row, col, cm){
  2744.         return !cm.isHidden(col) && cm.isCellEditable(col, row);
  2745.     },
  2746.     
  2747.     onEditorKey : function(field, e){
  2748.         var k = e.getKey(), 
  2749.             newCell, 
  2750.             g = this.grid, 
  2751.             last = g.lastEdit,
  2752.             ed = g.activeEditor,
  2753.             ae, last, r, c;
  2754.         var shift = e.shiftKey;
  2755.         if(k == e.TAB){
  2756.             e.stopEvent();
  2757.             ed.completeEdit();
  2758.             if(shift){
  2759.                 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
  2760.             }else{
  2761.                 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
  2762.             }
  2763.         }else if(k == e.ENTER){
  2764.             if(this.moveEditorOnEnter !== false){
  2765.                 if(shift){
  2766.                     newCell = g.walkCells(last.row - 1, last.col, -1, this.acceptsNav, this);
  2767.                 }else{
  2768.                     newCell = g.walkCells(last.row + 1, last.col, 1, this.acceptsNav, this);
  2769.                 }
  2770.             }
  2771.         }
  2772.         if(newCell){
  2773.             r = newCell[0];
  2774.             c = newCell[1];
  2775.             if(last.row != r){
  2776.                 this.selectRow(r); 
  2777.             }
  2778.             if(g.isEditor && g.editing){ 
  2779.                 ae = g.activeEditor;
  2780.                 if(ae && ae.field.triggerBlur){
  2781.                     
  2782.                     ae.field.triggerBlur();
  2783.                 }
  2784.             }
  2785.             g.startEditing(r, c);
  2786.         }
  2787.     },
  2788.     
  2789.     destroy : function(){
  2790.         if(this.rowNav){
  2791.             this.rowNav.disable();
  2792.             this.rowNav = null;
  2793.         }
  2794.         Ext.grid.RowSelectionModel.superclass.destroy.call(this);
  2795.     }
  2796. });
  2797. Ext.grid.Column = Ext.extend(Object, {
  2798.     
  2799.     
  2800.     
  2801.     
  2802.     
  2803.     
  2804.     
  2805.     
  2806.     
  2807.     
  2808.     
  2809.     
  2810.     
  2811.     
  2812.     
  2813.     
  2814.     
  2815.     
  2816.     
  2817.     
  2818.     
  2819.     
  2820.     
  2821.     isColumn : true,
  2822.     
  2823.     constructor : function(config){
  2824.         Ext.apply(this, config);
  2825.         if(Ext.isString(this.renderer)){
  2826.             this.renderer = Ext.util.Format[this.renderer];
  2827.         }else if(Ext.isObject(this.renderer)){
  2828.             this.scope = this.renderer.scope;
  2829.             this.renderer = this.renderer.fn;
  2830.         }
  2831.         if(!this.scope){
  2832.             this.scope = this;
  2833.         }
  2834.         if(this.editor){
  2835.             this.editor = Ext.create(this.editor, 'textfield');
  2836.         }
  2837.     },
  2838.     
  2839.     renderer : function(value){
  2840.         if(Ext.isString(value) && value.length < 1){
  2841.             return '&#160;';
  2842.         }
  2843.         return value;
  2844.     },
  2845.     
  2846.     getEditor: function(rowIndex){
  2847.         return this.editable !== false ? this.editor : null;
  2848.     },
  2849.     
  2850.     getCellEditor: function(rowIndex){
  2851.         var editor = this.getEditor(rowIndex);
  2852.         if(editor){
  2853.             if(!editor.startEdit){
  2854.                 if(!editor.gridEditor){
  2855.                     editor.gridEditor = new Ext.grid.GridEditor(editor);
  2856.                 }
  2857.                 return editor.gridEditor;
  2858.             }else if(editor.startEdit){
  2859.                 return editor;
  2860.             }
  2861.         }
  2862.         return null;
  2863.     }
  2864. });
  2865. Ext.grid.BooleanColumn = Ext.extend(Ext.grid.Column, {
  2866.     
  2867.     trueText: 'true',
  2868.     
  2869.     falseText: 'false',
  2870.     
  2871.     undefinedText: '&#160;',
  2872.     constructor: function(cfg){
  2873.         Ext.grid.BooleanColumn.superclass.constructor.call(this, cfg);
  2874.         var t = this.trueText, f = this.falseText, u = this.undefinedText;
  2875.         this.renderer = function(v){
  2876.             if(v === undefined){
  2877.                 return u;
  2878.             }
  2879.             if(!v || v === 'false'){
  2880.                 return f;
  2881.             }
  2882.             return t;
  2883.         };
  2884.     }
  2885. });
  2886. Ext.grid.NumberColumn = Ext.extend(Ext.grid.Column, {
  2887.     
  2888.     format : '0,000.00',
  2889.     constructor: function(cfg){
  2890.         Ext.grid.NumberColumn.superclass.constructor.call(this, cfg);
  2891.         this.renderer = Ext.util.Format.numberRenderer(this.format);
  2892.     }
  2893. });
  2894. Ext.grid.DateColumn = Ext.extend(Ext.grid.Column, {
  2895.     
  2896.     format : 'm/d/Y',
  2897.     constructor: function(cfg){
  2898.         Ext.grid.DateColumn.superclass.constructor.call(this, cfg);
  2899.         this.renderer = Ext.util.Format.dateRenderer(this.format);
  2900.     }
  2901. });
  2902. Ext.grid.TemplateColumn = Ext.extend(Ext.grid.Column, {
  2903.     
  2904.     constructor: function(cfg){
  2905.         Ext.grid.TemplateColumn.superclass.constructor.call(this, cfg);
  2906.         var tpl = (!Ext.isPrimitive(this.tpl) && this.tpl.compile) ? this.tpl : new Ext.XTemplate(this.tpl);
  2907.         this.renderer = function(value, p, r){
  2908.             return tpl.apply(r.data);
  2909.         };
  2910.         this.tpl = tpl;
  2911.     }
  2912. });
  2913. Ext.grid.Column.types = {
  2914.     gridcolumn : Ext.grid.Column,
  2915.     booleancolumn: Ext.grid.BooleanColumn,
  2916.     numbercolumn: Ext.grid.NumberColumn,
  2917.     datecolumn: Ext.grid.DateColumn,
  2918.     templatecolumn: Ext.grid.TemplateColumn
  2919. };
  2920. Ext.grid.RowNumberer = Ext.extend(Object, {
  2921.     
  2922.     header: "",
  2923.     
  2924.     width: 23,
  2925.     
  2926.     sortable: false,
  2927.     
  2928.     constructor : function(config){
  2929.         Ext.apply(this, config);
  2930.         if(this.rowspan){
  2931.             this.renderer = this.renderer.createDelegate(this);
  2932.         }
  2933.     },
  2934.     
  2935.     fixed:true,
  2936.     menuDisabled:true,
  2937.     dataIndex: '',
  2938.     id: 'numberer',
  2939.     rowspan: undefined,
  2940.     
  2941.     renderer : function(v, p, record, rowIndex){
  2942.         if(this.rowspan){
  2943.             p.cellAttr = 'rowspan="'+this.rowspan+'"';
  2944.         }
  2945.         return rowIndex+1;
  2946.     }
  2947. });
  2948. Ext.grid.CheckboxSelectionModel = Ext.extend(Ext.grid.RowSelectionModel, {
  2949.     
  2950.     
  2951.     header : '<div class="x-grid3-hd-checker">&#160;</div>',
  2952.     
  2953.     width : 20,
  2954.     
  2955.     sortable : false,
  2956.     
  2957.     menuDisabled : true,
  2958.     fixed : true,
  2959.     dataIndex : '',
  2960.     id : 'checker',
  2961.     constructor : function(){
  2962.         Ext.grid.CheckboxSelectionModel.superclass.constructor.apply(this, arguments);
  2963.         if(this.checkOnly){
  2964.             this.handleMouseDown = Ext.emptyFn;
  2965.         }
  2966.     },
  2967.     
  2968.     initEvents : function(){
  2969.         Ext.grid.CheckboxSelectionModel.superclass.initEvents.call(this);
  2970.         this.grid.on('render', function(){
  2971.             var view = this.grid.getView();
  2972.             view.mainBody.on('mousedown', this.onMouseDown, this);
  2973.             Ext.fly(view.innerHd).on('mousedown', this.onHdMouseDown, this);
  2974.         }, this);
  2975.     },
  2976.     
  2977.     onMouseDown : function(e, t){
  2978.         if(e.button === 0 && t.className == 'x-grid3-row-checker'){ 
  2979.             e.stopEvent();
  2980.             var row = e.getTarget('.x-grid3-row');
  2981.             if(row){
  2982.                 var index = row.rowIndex;
  2983.                 if(this.isSelected(index)){
  2984.                     this.deselectRow(index);
  2985.                 }else{
  2986.                     this.selectRow(index, true);
  2987.                 }
  2988.             }
  2989.         }
  2990.     },
  2991.     
  2992.     onHdMouseDown : function(e, t){
  2993.         if(t.className == 'x-grid3-hd-checker'){
  2994.             e.stopEvent();
  2995.             var hd = Ext.fly(t.parentNode);
  2996.             var isChecked = hd.hasClass('x-grid3-hd-checker-on');
  2997.             if(isChecked){
  2998.                 hd.removeClass('x-grid3-hd-checker-on');
  2999.                 this.clearSelections();
  3000.             }else{
  3001.                 hd.addClass('x-grid3-hd-checker-on');
  3002.                 this.selectAll();
  3003.             }
  3004.         }
  3005.     },
  3006.     
  3007.     renderer : function(v, p, record){
  3008.         return '<div class="x-grid3-row-checker">&#160;</div>';
  3009.     }
  3010. });
  3011. Ext.grid.CellSelectionModel = Ext.extend(Ext.grid.AbstractSelectionModel,  {
  3012.     
  3013.     constructor : function(config){
  3014.         Ext.apply(this, config);
  3015.     this.selection = null;
  3016.     this.addEvents(
  3017.         
  3018.         "beforecellselect",
  3019.         
  3020.         "cellselect",
  3021.         
  3022.         "selectionchange"
  3023.     );
  3024.     Ext.grid.CellSelectionModel.superclass.constructor.call(this);
  3025.     },
  3026.     
  3027.     initEvents : function(){
  3028.         this.grid.on('cellmousedown', this.handleMouseDown, this);
  3029.         this.grid.on(Ext.EventManager.useKeydown ? 'keydown' : 'keypress', this.handleKeyDown, this);
  3030.         this.grid.getView().on({
  3031.             scope: this,
  3032.             refresh: this.onViewChange,
  3033.             rowupdated: this.onRowUpdated,
  3034.             beforerowremoved: this.clearSelections,
  3035.             beforerowsinserted: this.clearSelections
  3036.         });
  3037.         if(this.grid.isEditor){
  3038.             this.grid.on('beforeedit', this.beforeEdit,  this);
  3039.         }
  3040.     },
  3041.     beforeEdit : function(e){
  3042.         this.select(e.row, e.column, false, true, e.record);
  3043.     },
  3044.     onRowUpdated : function(v, index, r){
  3045.         if(this.selection && this.selection.record == r){
  3046.             v.onCellSelect(index, this.selection.cell[1]);
  3047.         }
  3048.     },
  3049.     onViewChange : function(){
  3050.         this.clearSelections(true);
  3051.     },
  3052.     getSelectedCell : function(){
  3053.         return this.selection ? this.selection.cell : null;
  3054.     },
  3055.     
  3056.     clearSelections : function(preventNotify){
  3057.         var s = this.selection;
  3058.         if(s){
  3059.             if(preventNotify !== true){
  3060.                 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
  3061.             }
  3062.             this.selection = null;
  3063.             this.fireEvent("selectionchange", this, null);
  3064.         }
  3065.     },
  3066.     
  3067.     hasSelection : function(){
  3068.         return this.selection ? true : false;
  3069.     },
  3070.     
  3071.     handleMouseDown : function(g, row, cell, e){
  3072.         if(e.button !== 0 || this.isLocked()){
  3073.             return;
  3074.         }
  3075.         this.select(row, cell);
  3076.     },
  3077.     
  3078.     select : function(rowIndex, colIndex, preventViewNotify, preventFocus,  r){
  3079.         if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
  3080.             this.clearSelections();
  3081.             r = r || this.grid.store.getAt(rowIndex);
  3082.             this.selection = {
  3083.                 record : r,
  3084.                 cell : [rowIndex, colIndex]
  3085.             };
  3086.             if(!preventViewNotify){
  3087.                 var v = this.grid.getView();
  3088.                 v.onCellSelect(rowIndex, colIndex);
  3089.                 if(preventFocus !== true){
  3090.                     v.focusCell(rowIndex, colIndex);
  3091.                 }
  3092.             }
  3093.             this.fireEvent("cellselect", this, rowIndex, colIndex);
  3094.             this.fireEvent("selectionchange", this, this.selection);
  3095.         }
  3096.     },
  3097.     isSelectable : function(rowIndex, colIndex, cm){
  3098.         return !cm.isHidden(colIndex);
  3099.     },
  3100.     
  3101.     
  3102.     onEditorKey: function(field, e){
  3103.         if(e.getKey() == e.TAB){
  3104.             this.handleKeyDown(e);
  3105.         }
  3106.     },
  3107.     
  3108.     handleKeyDown : function(e){
  3109.         if(!e.isNavKeyPress()){
  3110.             return;
  3111.         }
  3112.         
  3113.         var k = e.getKey(),
  3114.             g = this.grid,
  3115.             s = this.selection,
  3116.             sm = this,
  3117.             walk = function(row, col, step){
  3118.                 return g.walkCells(
  3119.                     row,
  3120.                     col,
  3121.                     step,
  3122.                     g.isEditor && g.editing ? sm.acceptsNav : sm.isSelectable, 
  3123.                     sm
  3124.                 );
  3125.             },
  3126.             cell, newCell, r, c, ae;
  3127.         switch(k){
  3128.             case e.ESC:
  3129.             case e.PAGE_UP:
  3130.             case e.PAGE_DOWN:
  3131.                 
  3132.                 break;
  3133.             default:
  3134.                 
  3135.                 e.stopEvent();
  3136.                 break;
  3137.         }
  3138.         if(!s){
  3139.             cell = walk(0, 0, 1); 
  3140.             if(cell){
  3141.                 this.select(cell[0], cell[1]);
  3142.             }
  3143.             return;
  3144.         }
  3145.         cell = s.cell;  
  3146.         r = cell[0];    
  3147.         c = cell[1];    
  3148.         
  3149.         switch(k){
  3150.             case e.TAB:
  3151.                 if(e.shiftKey){
  3152.                     newCell = walk(r, c - 1, -1);
  3153.                 }else{
  3154.                     newCell = walk(r, c + 1, 1);
  3155.                 }
  3156.                 break;
  3157.             case e.DOWN:
  3158.                 newCell = walk(r + 1, c, 1);
  3159.                 break;
  3160.             case e.UP:
  3161.                 newCell = walk(r - 1, c, -1);
  3162.                 break;
  3163.             case e.RIGHT:
  3164.                 newCell = walk(r, c + 1, 1);
  3165.                 break;
  3166.             case e.LEFT:
  3167.                 newCell = walk(r, c - 1, -1);
  3168.                 break;
  3169.             case e.ENTER:
  3170.                 if (g.isEditor && !g.editing) {
  3171.                     g.startEditing(r, c);
  3172.                     return;
  3173.                 }
  3174.                 break;
  3175.         }
  3176.         if(newCell){
  3177.             
  3178.             r = newCell[0];
  3179.             c = newCell[1];
  3180.             this.select(r, c); 
  3181.             if(g.isEditor && g.editing){ 
  3182.                 ae = g.activeEditor;
  3183.                 if(ae && ae.field.triggerBlur){
  3184.                     
  3185.                     ae.field.triggerBlur();
  3186.                 }
  3187.                 g.startEditing(r, c);
  3188.             }
  3189.         }
  3190.     },
  3191.     acceptsNav : function(row, col, cm){
  3192.         return !cm.isHidden(col) && cm.isCellEditable(col, row);
  3193.     }
  3194. });
  3195. Ext.grid.EditorGridPanel = Ext.extend(Ext.grid.GridPanel, {
  3196.     
  3197.     clicksToEdit: 2,
  3198.     
  3199.     
  3200.     forceValidation: false,
  3201.     
  3202.     isEditor : true,
  3203.     
  3204.     detectEdit: false,
  3205. autoEncode : false,
  3206.     
  3207.     trackMouseOver: false, 
  3208.     
  3209.     initComponent : function(){
  3210.         Ext.grid.EditorGridPanel.superclass.initComponent.call(this);
  3211.         if(!this.selModel){
  3212.             
  3213.             this.selModel = new Ext.grid.CellSelectionModel();
  3214.         }
  3215.         this.activeEditor = null;
  3216.     this.addEvents(
  3217.             
  3218.             "beforeedit",
  3219.             
  3220.             "afteredit",
  3221.             
  3222.             "validateedit"
  3223.         );
  3224.     },
  3225.     
  3226.     initEvents : function(){
  3227.         Ext.grid.EditorGridPanel.superclass.initEvents.call(this);
  3228.         this.getGridEl().on('mousewheel', this.stopEditing.createDelegate(this, [true]), this);
  3229.         this.on('columnresize', this.stopEditing, this, [true]);
  3230.         if(this.clicksToEdit == 1){
  3231.             this.on("cellclick", this.onCellDblClick, this);
  3232.         }else {
  3233.             var view = this.getView();
  3234.             if(this.clicksToEdit == 'auto' && view.mainBody){
  3235.                 view.mainBody.on('mousedown', this.onAutoEditClick, this);
  3236.             }
  3237.             this.on('celldblclick', this.onCellDblClick, this);
  3238.         }
  3239.     },
  3240.     
  3241.     onResize : function(){
  3242.         Ext.grid.EditorGridPanel.superclass.onResize.apply(this, arguments);
  3243.         var ae = this.activeEditor;
  3244.         if(this.editing && ae){
  3245.             ae.realign(true);
  3246.         }
  3247.     },
  3248.     
  3249.     onCellDblClick : function(g, row, col){
  3250.         this.startEditing(row, col);
  3251.     },
  3252.     
  3253.     onAutoEditClick : function(e, t){
  3254.         if(e.button !== 0){
  3255.             return;
  3256.         }
  3257.         var row = this.view.findRowIndex(t),
  3258.             col = this.view.findCellIndex(t);
  3259.         if(row !== false && col !== false){
  3260.             this.stopEditing();
  3261.             if(this.selModel.getSelectedCell){ 
  3262.                 var sc = this.selModel.getSelectedCell();
  3263.                 if(sc && sc[0] === row && sc[1] === col){
  3264.                     this.startEditing(row, col);
  3265.                 }
  3266.             }else{
  3267.                 if(this.selModel.isSelected(row)){
  3268.                     this.startEditing(row, col);
  3269.                 }
  3270.             }
  3271.         }
  3272.     },
  3273.     
  3274.     onEditComplete : function(ed, value, startValue){
  3275.         this.editing = false;
  3276.         this.activeEditor = null;
  3277.         
  3278. var r = ed.record,
  3279.             field = this.colModel.getDataIndex(ed.col);
  3280.         value = this.postEditValue(value, startValue, r, field);
  3281.         if(this.forceValidation === true || String(value) !== String(startValue)){
  3282.             var e = {
  3283.                 grid: this,
  3284.                 record: r,
  3285.                 field: field,
  3286.                 originalValue: startValue,
  3287.                 value: value,
  3288.                 row: ed.row,
  3289.                 column: ed.col,
  3290.                 cancel:false
  3291.             };
  3292.             if(this.fireEvent("validateedit", e) !== false && !e.cancel && String(value) !== String(startValue)){
  3293.                 r.set(field, e.value);
  3294.                 delete e.cancel;
  3295.                 this.fireEvent("afteredit", e);
  3296.             }
  3297.         }
  3298.         this.view.focusCell(ed.row, ed.col);
  3299.     },
  3300.     
  3301.     startEditing : function(row, col){
  3302.         this.stopEditing();
  3303.         if(this.colModel.isCellEditable(col, row)){
  3304.             this.view.ensureVisible(row, col, true);
  3305.             var r = this.store.getAt(row),
  3306.                 field = this.colModel.getDataIndex(col),
  3307.                 e = {
  3308.                     grid: this,
  3309.                     record: r,
  3310.                     field: field,
  3311.                     value: r.data[field],
  3312.                     row: row,
  3313.                     column: col,
  3314.                     cancel:false
  3315.                 };
  3316.             if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
  3317.                 this.editing = true;
  3318.                 var ed = this.colModel.getCellEditor(col, row);
  3319.                 if(!ed){
  3320.                     return;
  3321.                 }
  3322.                 if(!ed.rendered){
  3323.                     ed.parentEl = this.view.getEditorParent(ed);
  3324.                     ed.on({
  3325.                         scope: this,
  3326.                         render: {
  3327.                             fn: function(c){
  3328.                                 c.field.focus(false, true);
  3329.                             },
  3330.                             single: true,
  3331.                             scope: this
  3332.                         },
  3333.                         specialkey: function(field, e){
  3334.                             this.getSelectionModel().onEditorKey(field, e);
  3335.                         },
  3336.                         complete: this.onEditComplete,
  3337.                         canceledit: this.stopEditing.createDelegate(this, [true])
  3338.                     });
  3339.                 }
  3340.                 Ext.apply(ed, {
  3341.                     row     : row,
  3342.                     col     : col,
  3343.                     record  : r
  3344.                 });
  3345.                 this.lastEdit = {
  3346.                     row: row,
  3347.                     col: col
  3348.                 };
  3349.                 this.activeEditor = ed;
  3350.                 var v = this.preEditValue(r, field);
  3351.                 ed.startEdit(this.view.getCell(row, col).firstChild, Ext.isDefined(v) ? v : '');
  3352.             }
  3353.         }
  3354.     },
  3355.     
  3356.     preEditValue : function(r, field){
  3357.         var value = r.data[field];
  3358.         return this.autoEncode && Ext.isString(value) ? Ext.util.Format.htmlDecode(value) : value;
  3359.     },
  3360.     
  3361. postEditValue : function(value, originalValue, r, field){
  3362. return this.autoEncode && Ext.isString(value) ? Ext.util.Format.htmlEncode(value) : value;
  3363. },
  3364.     
  3365.     stopEditing : function(cancel){
  3366.         if(this.editing){
  3367.             var ae = this.activeEditor;
  3368.             if(ae){
  3369.                 ae[cancel === true ? 'cancelEdit' : 'completeEdit']();
  3370.                 this.view.focusCell(ae.row, ae.col);
  3371.             }
  3372.             this.activeEditor = null;
  3373.         }
  3374.         this.editing = false;
  3375.     }
  3376. });
  3377. Ext.reg('editorgrid', Ext.grid.EditorGridPanel);
  3378. Ext.grid.GridEditor = function(field, config){
  3379.     Ext.grid.GridEditor.superclass.constructor.call(this, field, config);
  3380.     field.monitorTab = false;
  3381. };
  3382. Ext.extend(Ext.grid.GridEditor, Ext.Editor, {
  3383.     alignment: "tl-tl",
  3384.     autoSize: "width",
  3385.     hideEl : false,
  3386.     cls: "x-small-editor x-grid-editor",
  3387.     shim:false,
  3388.     shadow:false
  3389. });
  3390. Ext.grid.PropertyRecord = Ext.data.Record.create([
  3391.     {name:'name',type:'string'}, 'value'
  3392. ]);
  3393. Ext.grid.PropertyStore = Ext.extend(Ext.util.Observable, {
  3394.     
  3395.     constructor : function(grid, source){
  3396.         this.grid = grid;
  3397.         this.store = new Ext.data.Store({
  3398.             recordType : Ext.grid.PropertyRecord
  3399.         });
  3400.         this.store.on('update', this.onUpdate,  this);
  3401.         if(source){
  3402.             this.setSource(source);
  3403.         }
  3404.         Ext.grid.PropertyStore.superclass.constructor.call(this);    
  3405.     },
  3406.     
  3407.     
  3408.     setSource : function(o){
  3409.         this.source = o;
  3410.         this.store.removeAll();
  3411.         var data = [];
  3412.         for(var k in o){
  3413.             if(this.isEditableValue(o[k])){
  3414.                 data.push(new Ext.grid.PropertyRecord({name: k, value: o[k]}, k));
  3415.             }
  3416.         }
  3417.         this.store.loadRecords({records: data}, {}, true);
  3418.     },
  3419.     
  3420.     onUpdate : function(ds, record, type){
  3421.         if(type == Ext.data.Record.EDIT){
  3422.             var v = record.data.value;
  3423.             var oldValue = record.modified.value;
  3424.             if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
  3425.                 this.source[record.id] = v;
  3426.                 record.commit();
  3427.                 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
  3428.             }else{
  3429.                 record.reject();
  3430.             }
  3431.         }
  3432.     },
  3433.     
  3434.     getProperty : function(row){
  3435.        return this.store.getAt(row);
  3436.     },
  3437.     
  3438.     isEditableValue: function(val){
  3439.         return Ext.isPrimitive(val) || Ext.isDate(val);
  3440.     },
  3441.     
  3442.     setValue : function(prop, value){
  3443.         this.source[prop] = value;
  3444.         this.store.getById(prop).set('value', value);
  3445.     },
  3446.     
  3447.     getSource : function(){
  3448.         return this.source;
  3449.     }
  3450. });
  3451. Ext.grid.PropertyColumnModel = Ext.extend(Ext.grid.ColumnModel, {
  3452.     
  3453.     nameText : 'Name',
  3454.     valueText : 'Value',
  3455.     dateFormat : 'm/j/Y',
  3456.     
  3457.     constructor : function(grid, store){
  3458.         var g = Ext.grid,
  3459.         f = Ext.form;
  3460.         
  3461.     this.grid = grid;
  3462.     g.PropertyColumnModel.superclass.constructor.call(this, [
  3463.         {header: this.nameText, width:50, sortable: true, dataIndex:'name', id: 'name', menuDisabled:true},
  3464.         {header: this.valueText, width:50, resizable:false, dataIndex: 'value', id: 'value', menuDisabled:true}
  3465.     ]);
  3466.     this.store = store;
  3467.     var bfield = new f.Field({
  3468.         autoCreate: {tag: 'select', children: [
  3469.             {tag: 'option', value: 'true', html: 'true'},
  3470.             {tag: 'option', value: 'false', html: 'false'}
  3471.         ]},
  3472.         getValue : function(){
  3473.             return this.el.dom.value == 'true';
  3474.         }
  3475.     });
  3476.     this.editors = {
  3477.         'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
  3478.         'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
  3479.         'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
  3480.         'boolean' : new g.GridEditor(bfield, {
  3481.             autoSize: 'both'
  3482.         })
  3483.     };
  3484.     this.renderCellDelegate = this.renderCell.createDelegate(this);
  3485.     this.renderPropDelegate = this.renderProp.createDelegate(this);
  3486.     },
  3487.     
  3488.     renderDate : function(dateVal){
  3489.         return dateVal.dateFormat(this.dateFormat);
  3490.     },
  3491.     
  3492.     renderBool : function(bVal){
  3493.         return bVal ? 'true' : 'false';
  3494.     },
  3495.     
  3496.     isCellEditable : function(colIndex, rowIndex){
  3497.         return colIndex == 1;
  3498.     },
  3499.     
  3500.     getRenderer : function(col){
  3501.         return col == 1 ?
  3502.             this.renderCellDelegate : this.renderPropDelegate;
  3503.     },
  3504.     
  3505.     renderProp : function(v){
  3506.         return this.getPropertyName(v);
  3507.     },
  3508.     
  3509.     renderCell : function(val){
  3510.         var rv = val;
  3511.         if(Ext.isDate(val)){
  3512.             rv = this.renderDate(val);
  3513.         }else if(typeof val == 'boolean'){
  3514.             rv = this.renderBool(val);
  3515.         }
  3516.         return Ext.util.Format.htmlEncode(rv);
  3517.     },
  3518.     
  3519.     getPropertyName : function(name){
  3520.         var pn = this.grid.propertyNames;
  3521.         return pn && pn[name] ? pn[name] : name;
  3522.     },
  3523.     
  3524.     getCellEditor : function(colIndex, rowIndex){
  3525.         var p = this.store.getProperty(rowIndex),
  3526.             n = p.data.name, 
  3527.             val = p.data.value;
  3528.         if(this.grid.customEditors[n]){
  3529.             return this.grid.customEditors[n];
  3530.         }
  3531.         if(Ext.isDate(val)){
  3532.             return this.editors.date;
  3533.         }else if(typeof val == 'number'){
  3534.             return this.editors.number;
  3535.         }else if(typeof val == 'boolean'){
  3536.             return this.editors['boolean'];
  3537.         }else{
  3538.             return this.editors.string;
  3539.         }
  3540.     },
  3541.     
  3542.     destroy : function(){
  3543.         Ext.grid.PropertyColumnModel.superclass.destroy.call(this);
  3544.         for(var ed in this.editors){
  3545.             Ext.destroy(this.editors[ed]);
  3546.         }
  3547.     }
  3548. });
  3549. Ext.grid.PropertyGrid = Ext.extend(Ext.grid.EditorGridPanel, {
  3550.     
  3551.     
  3552.     
  3553.     
  3554.     enableColumnMove:false,
  3555.     stripeRows:false,
  3556.     trackMouseOver: false,
  3557.     clicksToEdit:1,
  3558.     enableHdMenu : false,
  3559.     viewConfig : {
  3560.         forceFit:true
  3561.     },
  3562.     
  3563.     initComponent : function(){
  3564.         this.customEditors = this.customEditors || {};
  3565.         this.lastEditRow = null;
  3566.         var store = new Ext.grid.PropertyStore(this);
  3567.         this.propStore = store;
  3568.         var cm = new Ext.grid.PropertyColumnModel(this, store);
  3569.         store.store.sort('name', 'ASC');
  3570.         this.addEvents(
  3571.             
  3572.             'beforepropertychange',
  3573.             
  3574.             'propertychange'
  3575.         );
  3576.         this.cm = cm;
  3577.         this.ds = store.store;
  3578.         Ext.grid.PropertyGrid.superclass.initComponent.call(this);
  3579. this.mon(this.selModel, 'beforecellselect', function(sm, rowIndex, colIndex){
  3580.             if(colIndex === 0){
  3581.                 this.startEditing.defer(200, this, [rowIndex, 1]);
  3582.                 return false;
  3583.             }
  3584.         }, this);
  3585.     },
  3586.     
  3587.     onRender : function(){
  3588.         Ext.grid.PropertyGrid.superclass.onRender.apply(this, arguments);
  3589.         this.getGridEl().addClass('x-props-grid');
  3590.     },
  3591.     
  3592.     afterRender: function(){
  3593.         Ext.grid.PropertyGrid.superclass.afterRender.apply(this, arguments);
  3594.         if(this.source){
  3595.             this.setSource(this.source);
  3596.         }
  3597.     },
  3598.     
  3599.     setSource : function(source){
  3600.         this.propStore.setSource(source);
  3601.     },
  3602.     
  3603.     getSource : function(){
  3604.         return this.propStore.getSource();
  3605.     }
  3606.     
  3607.     
  3608.     
  3609.     
  3610. });
  3611. Ext.reg("propertygrid", Ext.grid.PropertyGrid);
  3612. Ext.grid.GroupingView = Ext.extend(Ext.grid.GridView, {
  3613.     
  3614.     groupByText : 'Group By This Field',
  3615.     
  3616.     showGroupsText : 'Show in Groups',
  3617.     
  3618.     hideGroupedColumn : false,
  3619.     
  3620.     showGroupName : true,
  3621.     
  3622.     startCollapsed : false,
  3623.     
  3624.     enableGrouping : true,
  3625.     
  3626.     enableGroupingMenu : true,
  3627.     
  3628.     enableNoGroups : true,
  3629.     
  3630.     emptyGroupText : '(None)',
  3631.     
  3632.     ignoreAdd : false,
  3633.     
  3634.     groupTextTpl : '{text}',
  3635.     
  3636.     groupMode: 'value',
  3637.     
  3638.     
  3639.     gidSeed : 1000,
  3640.     
  3641.     initTemplates : function(){
  3642.         Ext.grid.GroupingView.superclass.initTemplates.call(this);
  3643.         this.state = {};
  3644.         var sm = this.grid.getSelectionModel();
  3645.         sm.on(sm.selectRow ? 'beforerowselect' : 'beforecellselect',
  3646.                 this.onBeforeRowSelect, this);
  3647.         if(!this.startGroup){
  3648.             this.startGroup = new Ext.XTemplate(
  3649.                 '<div id="{groupId}" class="x-grid-group {cls}">',
  3650.                     '<div id="{groupId}-hd" class="x-grid-group-hd" style="{style}"><div class="x-grid-group-title">', this.groupTextTpl ,'</div></div>',
  3651.                     '<div id="{groupId}-bd" class="x-grid-group-body">'
  3652.             );
  3653.         }
  3654.         this.startGroup.compile();
  3655.         if(!this.endGroup){
  3656.             this.endGroup = '</div></div>';
  3657.         }
  3658.         this.endGroup = '</div></div>';
  3659.     },
  3660.     
  3661.     findGroup : function(el){
  3662.         return Ext.fly(el).up('.x-grid-group', this.mainBody.dom);
  3663.     },
  3664.     
  3665.     getGroups : function(){
  3666.         return this.hasRows() ? this.mainBody.dom.childNodes : [];
  3667.     },
  3668.     
  3669.     onAdd : function(){
  3670.         if(this.enableGrouping && !this.ignoreAdd){
  3671.             var ss = this.getScrollState();
  3672.             this.refresh();
  3673.             this.restoreScroll(ss);
  3674.         }else if(!this.enableGrouping){
  3675.             Ext.grid.GroupingView.superclass.onAdd.apply(this, arguments);
  3676.         }
  3677.     },
  3678.     
  3679.     onRemove : function(ds, record, index, isUpdate){
  3680.         Ext.grid.GroupingView.superclass.onRemove.apply(this, arguments);
  3681.         var g = document.getElementById(record._groupId);
  3682.         if(g && g.childNodes[1].childNodes.length < 1){
  3683.             Ext.removeNode(g);
  3684.         }
  3685.         this.applyEmptyText();
  3686.     },
  3687.     
  3688.     refreshRow : function(record){
  3689.         if(this.ds.getCount()==1){
  3690.             this.refresh();
  3691.         }else{
  3692.             this.isUpdating = true;
  3693.             Ext.grid.GroupingView.superclass.refreshRow.apply(this, arguments);
  3694.             this.isUpdating = false;
  3695.         }
  3696.     },
  3697.     
  3698.     beforeMenuShow : function(){
  3699.         var item, items = this.hmenu.items, disabled = this.cm.config[this.hdCtxIndex].groupable === false;
  3700.         if((item = items.get('groupBy'))){
  3701.             item.setDisabled(disabled);
  3702.         }
  3703.         if((item = items.get('showGroups'))){
  3704.             item.setDisabled(disabled);
  3705.         item.setChecked(this.enableGrouping, true);
  3706.         }
  3707.     },
  3708.     
  3709.     renderUI : function(){
  3710.         Ext.grid.GroupingView.superclass.renderUI.call(this);
  3711.         this.mainBody.on('mousedown', this.interceptMouse, this);
  3712.         if(this.enableGroupingMenu && this.hmenu){
  3713.             this.hmenu.add('-',{
  3714.                 itemId:'groupBy',
  3715.                 text: this.groupByText,
  3716.                 handler: this.onGroupByClick,
  3717.                 scope: this,
  3718.                 iconCls:'x-group-by-icon'
  3719.             });
  3720.             if(this.enableNoGroups){
  3721.                 this.hmenu.add({
  3722.                     itemId:'showGroups',
  3723.                     text: this.showGroupsText,
  3724.             checked: true,
  3725.                     checkHandler: this.onShowGroupsClick,
  3726.                     scope: this
  3727.                 });
  3728.             }
  3729.             this.hmenu.on('beforeshow', this.beforeMenuShow, this);
  3730.         }
  3731.     },
  3732.     processEvent: function(name, e){
  3733.         var hd = e.getTarget('.x-grid-group-hd', this.mainBody);
  3734.         if(hd){
  3735.             
  3736.             var field = this.getGroupField(),
  3737.                 prefix = this.getPrefix(field),
  3738.                 groupValue = hd.id.substring(prefix.length);
  3739.             
  3740.             groupValue = groupValue.substr(0, groupValue.length - 3);
  3741.             if(groupValue){
  3742.                 this.grid.fireEvent('group' + name, this.grid, field, groupValue, e);
  3743.             }
  3744.         }
  3745.     },
  3746.     
  3747.     onGroupByClick : function(){
  3748.     this.enableGrouping = true;
  3749.         this.grid.store.groupBy(this.cm.getDataIndex(this.hdCtxIndex));
  3750.         this.beforeMenuShow(); 
  3751.     this.refresh();
  3752.     },
  3753.     
  3754.     onShowGroupsClick : function(mi, checked){
  3755.     this.enableGrouping = checked;
  3756.         if(checked){
  3757.             this.onGroupByClick();
  3758.         }else{
  3759.             this.grid.store.clearGrouping();
  3760.         }
  3761.     },
  3762.     
  3763.     toggleRowIndex : function(rowIndex, expanded){
  3764.         if(!this.enableGrouping){
  3765.             return;
  3766.         }
  3767.         var row = this.getRow(rowIndex);
  3768.         if(row){
  3769.             this.toggleGroup(this.findGroup(row), expanded);
  3770.         }
  3771.     },
  3772.     
  3773.     toggleGroup : function(group, expanded){
  3774.         var gel = Ext.get(group);
  3775.         expanded = Ext.isDefined(expanded) ? expanded : gel.hasClass('x-grid-group-collapsed');
  3776.         if(this.state[gel.id] !== expanded){
  3777.             this.grid.stopEditing(true);
  3778.             this.state[gel.id] = expanded;
  3779.             gel[expanded ? 'removeClass' : 'addClass']('x-grid-group-collapsed');
  3780.         }
  3781.     },
  3782.     
  3783.     toggleAllGroups : function(expanded){
  3784.         var groups = this.getGroups();
  3785.         for(var i = 0, len = groups.length; i < len; i++){
  3786.             this.toggleGroup(groups[i], expanded);
  3787.         }
  3788.     },
  3789.     
  3790.     expandAllGroups : function(){
  3791.         this.toggleAllGroups(true);
  3792.     },
  3793.     
  3794.     collapseAllGroups : function(){
  3795.         this.toggleAllGroups(false);
  3796.     },
  3797.     
  3798.     interceptMouse : function(e){
  3799.         var hd = e.getTarget('.x-grid-group-hd', this.mainBody);
  3800.         if(hd){
  3801.             e.stopEvent();
  3802.             this.toggleGroup(hd.parentNode);
  3803.         }
  3804.     },
  3805.     
  3806.     getGroup : function(v, r, groupRenderer, rowIndex, colIndex, ds){
  3807.         var g = groupRenderer ? groupRenderer(v, {}, r, rowIndex, colIndex, ds) : String(v);
  3808.         if(g === '' || g === '&#160;'){
  3809.             g = this.cm.config[colIndex].emptyGroupText || this.emptyGroupText;
  3810.         }
  3811.         return g;
  3812.     },
  3813.     
  3814.     getGroupField : function(){
  3815.         return this.grid.store.getGroupState();
  3816.     },
  3817.     
  3818.     afterRender : function(){
  3819.         Ext.grid.GroupingView.superclass.afterRender.call(this);
  3820.         if(this.grid.deferRowRender){
  3821.             this.updateGroupWidths();
  3822.         }
  3823.     },
  3824.     
  3825.     renderRows : function(){
  3826.         var groupField = this.getGroupField();
  3827.         var eg = !!groupField;
  3828.         
  3829.         if(this.hideGroupedColumn) {
  3830.             var colIndex = this.cm.findColumnIndex(groupField),
  3831.                 hasLastGroupField = Ext.isDefined(this.lastGroupField);
  3832.             if(!eg && hasLastGroupField){
  3833.                 this.mainBody.update('');
  3834.                 this.cm.setHidden(this.cm.findColumnIndex(this.lastGroupField), false);
  3835.                 delete this.lastGroupField;
  3836.             }else if (eg && !hasLastGroupField){
  3837.                 this.lastGroupField = groupField;
  3838.                 this.cm.setHidden(colIndex, true);
  3839.             }else if (eg && hasLastGroupField && groupField !== this.lastGroupField) {
  3840.                 this.mainBody.update('');
  3841.                 var oldIndex = this.cm.findColumnIndex(this.lastGroupField);
  3842.                 this.cm.setHidden(oldIndex, false);
  3843.                 this.lastGroupField = groupField;
  3844.                 this.cm.setHidden(colIndex, true);
  3845.             }
  3846.         }
  3847.         return Ext.grid.GroupingView.superclass.renderRows.apply(
  3848.                     this, arguments);
  3849.     },
  3850.     
  3851.     doRender : function(cs, rs, ds, startRow, colCount, stripe){
  3852.         if(rs.length < 1){
  3853.             return '';
  3854.         }
  3855.         var groupField = this.getGroupField(),
  3856.             colIndex = this.cm.findColumnIndex(groupField),
  3857.             g;
  3858.         this.enableGrouping = (this.enableGrouping === false) ? false : !!groupField;
  3859.         if(!this.enableGrouping || this.isUpdating){
  3860.             return Ext.grid.GroupingView.superclass.doRender.apply(
  3861.                     this, arguments);
  3862.         }
  3863.         var gstyle = 'width:' + this.getTotalWidth() + ';',
  3864.             cfg = this.cm.config[colIndex],
  3865.             groupRenderer = cfg.groupRenderer || cfg.renderer,
  3866.             prefix = this.showGroupName ? (cfg.groupName || cfg.header)+': ' : '',
  3867.             groups = [],
  3868.             curGroup, i, len, gid;
  3869.         for(i = 0, len = rs.length; i < len; i++){
  3870.             var rowIndex = startRow + i,
  3871.                 r = rs[i],
  3872.                 gvalue = r.data[groupField];
  3873.                 g = this.getGroup(gvalue, r, groupRenderer, rowIndex, colIndex, ds);
  3874.             if(!curGroup || curGroup.group != g){
  3875.                 gid = this.constructId(gvalue, groupField, colIndex);
  3876.                 
  3877.                 
  3878.                 this.state[gid] = !(Ext.isDefined(this.state[gid]) ? !this.state[gid] : this.startCollapsed);
  3879.                 curGroup = {
  3880.                     group: g,
  3881.                     gvalue: gvalue,
  3882.                     text: prefix + g,
  3883.                     groupId: gid,
  3884.                     startRow: rowIndex,
  3885.                     rs: [r],
  3886.                     cls: this.state[gid] ? '' : 'x-grid-group-collapsed',
  3887.                     style: gstyle
  3888.                 };
  3889.                 groups.push(curGroup);
  3890.             }else{
  3891.                 curGroup.rs.push(r);
  3892.             }
  3893.             r._groupId = gid;
  3894.         }
  3895.         var buf = [];
  3896.         for(i = 0, len = groups.length; i < len; i++){
  3897.             g = groups[i];
  3898.             this.doGroupStart(buf, g, cs, ds, colCount);
  3899.             buf[buf.length] = Ext.grid.GroupingView.superclass.doRender.call(
  3900.                     this, cs, g.rs, ds, g.startRow, colCount, stripe);
  3901.             this.doGroupEnd(buf, g, cs, ds, colCount);
  3902.         }
  3903.         return buf.join('');
  3904.     },
  3905.     
  3906.     getGroupId : function(value){
  3907.         var field = this.getGroupField();
  3908.         return this.constructId(value, field, this.cm.findColumnIndex(field));
  3909.     },
  3910.     
  3911.     constructId : function(value, field, idx){
  3912.         var cfg = this.cm.config[idx],
  3913.             groupRenderer = cfg.groupRenderer || cfg.renderer,
  3914.             val = (this.groupMode == 'value') ? value : this.getGroup(value, {data:{}}, groupRenderer, 0, idx, this.ds);
  3915.         return this.getPrefix(field) + Ext.util.Format.htmlEncode(val);
  3916.     },
  3917.     
  3918.     getPrefix: function(field){
  3919.         return this.grid.getGridEl().id + '-gp-' + field + '-';
  3920.     },
  3921.     
  3922.     doGroupStart : function(buf, g, cs, ds, colCount){
  3923.         buf[buf.length] = this.startGroup.apply(g);
  3924.     },
  3925.     
  3926.     doGroupEnd : function(buf, g, cs, ds, colCount){
  3927.         buf[buf.length] = this.endGroup;
  3928.     },
  3929.     
  3930.     getRows : function(){
  3931.         if(!this.enableGrouping){
  3932.             return Ext.grid.GroupingView.superclass.getRows.call(this);
  3933.         }
  3934.         var r = [];
  3935.         var g, gs = this.getGroups();
  3936.         for(var i = 0, len = gs.length; i < len; i++){
  3937.             g = gs[i].childNodes[1].childNodes;
  3938.             for(var j = 0, jlen = g.length; j < jlen; j++){
  3939.                 r[r.length] = g[j];
  3940.             }
  3941.         }
  3942.         return r;
  3943.     },
  3944.     
  3945.     updateGroupWidths : function(){
  3946.         if(!this.enableGrouping || !this.hasRows()){
  3947.             return;
  3948.         }
  3949.         var tw = Math.max(this.cm.getTotalWidth(), this.el.dom.offsetWidth-this.getScrollOffset()) +'px';
  3950.         var gs = this.getGroups();
  3951.         for(var i = 0, len = gs.length; i < len; i++){
  3952.             gs[i].firstChild.style.width = tw;
  3953.         }
  3954.     },
  3955.     
  3956.     onColumnWidthUpdated : function(col, w, tw){
  3957.         Ext.grid.GroupingView.superclass.onColumnWidthUpdated.call(this, col, w, tw);
  3958.         this.updateGroupWidths();
  3959.     },
  3960.     
  3961.     onAllColumnWidthsUpdated : function(ws, tw){
  3962.         Ext.grid.GroupingView.superclass.onAllColumnWidthsUpdated.call(this, ws, tw);
  3963.         this.updateGroupWidths();
  3964.     },
  3965.     
  3966.     onColumnHiddenUpdated : function(col, hidden, tw){
  3967.         Ext.grid.GroupingView.superclass.onColumnHiddenUpdated.call(this, col, hidden, tw);
  3968.         this.updateGroupWidths();
  3969.     },
  3970.     
  3971.     onLayout : function(){
  3972.         this.updateGroupWidths();
  3973.     },
  3974.     
  3975.     onBeforeRowSelect : function(sm, rowIndex){
  3976.         this.toggleRowIndex(rowIndex, true);
  3977.     }
  3978. });
  3979. Ext.grid.GroupingView.GROUP_ID = 1000;