Roo.data.Store @config multisort - enables multiple sort columns, based on the order...
authorAlan Knowles <alan@akbkhome.com>
Wed, 29 Jun 2011 07:32:42 +0000 (07:32 +0000)
committerAlan Knowles <alan@akbkhome.com>
Wed, 7 Sep 2011 02:03:10 +0000 (10:03 +0800)
Roo/data/Store.js
Roo/grid/Grid.js
Roo/grid/GridView.js
Roo/grid/HeaderDropZone.js
examples/grid/edit-grid.js
roojs-all.js
roojs-debug.js
roojs-ui-debug.js
roojs-ui.js

index af4eb59..8f300a6 100644 (file)
@@ -38,7 +38,8 @@ Roo.data.Store = function(config){
         "start" : "start",
         "limit" : "limit",
         "sort" : "sort",
-        "dir" : "dir"
+        "dir" : "dir",
+        "multisort" : "_multisort"
     };
 
     if(config && config.data){
@@ -150,6 +151,7 @@ Roo.data.Store = function(config){
         this.relayEvents(this.proxy,  ["loadexception"]);
     }
     this.sortToggle = {};
+    this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
 
     Roo.data.Store.superclass.constructor.call(this);
 
@@ -182,6 +184,10 @@ Roo.extend(Roo.data.Store, Roo.util.Observable, {
     * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
     */
     /**
+    * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
+    */
+    multiSort: false,
+    /**
     * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
     * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
     */
@@ -338,6 +344,11 @@ Roo.extend(Roo.data.Store, Roo.util.Observable, {
                 p[pn["sort"]] = this.sortInfo.field;
                 p[pn["dir"]] = this.sortInfo.direction;
             }
+            if (this.multiSort) {
+                var pn = this.paramNames;
+                p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
+            }
+            
             this.proxy.load(p, this.reader, this.loadRecords, this, options);
         }
     },
@@ -476,7 +487,9 @@ Roo.extend(Roo.data.Store, Roo.util.Observable, {
     sort : function(fieldName, dir){
         var f = this.fields.get(fieldName);
         if(!dir){
-            if(this.sortInfo && this.sortInfo.field == f.name){ // toggle sort dir
+            this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
+            
+            if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
                 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
             }else{
                 dir = f.sortDir;
index ee77dcf..8bb4697 100644 (file)
@@ -77,7 +77,7 @@ Roo.grid.Grid = function(container, config){
         this.dataSource= Roo.factory(this.dataSource, Roo.data);
         this.ds = this.dataSource;
         this.ds.xmodule = this.xmodule || false;
-        
+         
     }
     
     
@@ -418,6 +418,8 @@ Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
     */
     dropTarget: false,
     
+   
+    
     // private
     rendered : false,
 
index 42617f4..0e6f208 100644 (file)
@@ -1013,6 +1013,26 @@ Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
         if(this.enableMoveAnim && Roo.enableFx){
             this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
         }
+        // if multisort - fix sortOrder, and reload..
+        if (this.grid.dataSource.multiSort) {
+            // the we can call sort again..
+            var dm = this.grid.dataSource;
+            var cm = this.grid.colModel;
+            var so = [];
+            for(var i = 0; i < cm.config.length; i++ ) {
+                
+                if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
+                    continue; // dont' bother, it's not in sort list or being set.
+                }
+                
+                so.push(cm.config[i].dataIndex);
+            };
+            dm.sortOrder = so;
+            dm.load(dm.lastOptions);
+            
+            
+        }
+        
     },
 
     updateCell : function(dm, rowIndex, dataIndex){
@@ -1159,20 +1179,43 @@ Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
     },
 
     updateHeaderSortState : function(){
-        var state = this.ds.getSortState();
-        if(!state){
-            return;
-        }
-        this.sortState = state;
-        var sortColumn = this.cm.findColumnIndex(state.field);
-        if(sortColumn != -1){
-            var sortDir = state.direction;
-            var sc = this.sortClasses;
-            var hds = this.el.select(this.headerSelector).removeClass(sc);
-            hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
+        
+        // sort state can be single { field: xxx, direction : yyy}
+        // or   { xxx=>ASC , yyy : DESC ..... }
+        
+        var mstate = {};
+        if (!this.ds.multiSort) { 
+            var state = this.ds.getSortState();
+            if(!state){
+                return;
+            }
+            mstate[state.field] = state.direction;
+            // FIXME... - this is not used here.. but might be elsewhere..
+            this.sortState = state;
+            
+        } else {
+            mstate = this.ds.sortToggle;
+        }
+        //remove existing sort classes..
+        
+        var sc = this.sortClasses;
+        var hds = this.el.select(this.headerSelector).removeClass(sc);
+        
+        for(var f in mstate) {
+        
+            var sortColumn = this.cm.findColumnIndex(f);
+            
+            if(sortColumn != -1){
+                var sortDir = mstate[f];        
+                hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
+            }
         }
+        
+         
+        
     },
 
+
     handleHeaderClick : function(g, index){
         if(this.headersDisabled){
             return;
@@ -1182,6 +1225,22 @@ Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
             return;
         }
         g.stopEditing();
+        
+        if (dm.multiSort) {
+            // update the sortOrder
+            var so = [];
+            for(var i = 0; i < cm.config.length; i++ ) {
+                
+                if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
+                    continue; // dont' bother, it's not in sort list or being set.
+                }
+                
+                so.push(cm.config[i].dataIndex);
+            };
+            dm.sortOrder = so;
+        }
+        
+        
         dm.sort(cm.getDataIndex(index));
     },
 
index 12b1028..3bc5694 100644 (file)
@@ -39,6 +39,7 @@ Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
         if(cindex !== false){
             return this.view.getHeaderCell(cindex);
         }
+        return null;
     },
 
     nextVisible : function(h){
index 46a4a75..36e3812 100644 (file)
  */
 
 Roo.BLANK_IMAGE_URL  = "../../images/default/s.gif";
\r
-Roo.onReady(function(){\r
-    Roo.QuickTips.init();\r
-    function formatBoolean(value){\r
-        return value ? 'Yes' : 'No';  \r
-    };\r
-    \r
-    function formatDate(value){\r
-        return value ? value.dateFormat('M d, Y') : '';\r
-    };\r
-    // shorthand alias\r
-    var fm = Roo.form, Ed = Roo.grid.GridEditor;\r
-\r
-    // the column model has information about grid columns\r
-    // dataIndex maps the column to the specific data field in\r
-    // the data store (created below)\r
-    var cm = new Roo.grid.ColumnModel([{\r
-           header: "Common Name",\r
-           dataIndex: 'common',\r
-           width: 220,\r
-           editor: new Ed(new fm.TextField({\r
-               allowBlank: false\r
-           }))\r
-        },{\r
-           header: "Light",\r
-           dataIndex: 'light',\r
-           width: 130,\r
-           editor: new Ed(new Roo.form.ComboBox({\r
-               typeAhead: true,\r
-               triggerAction: 'all',\r
-               transform:'light',\r
-               lazyRender:true\r
-            }))\r
-        },{\r
-           header: "Price",\r
-           dataIndex: 'price',\r
-           width: 70,\r
-           align: 'right',\r
-           renderer: 'usMoney',\r
-           editor: new Ed(new fm.NumberField({\r
-               allowBlank: false,\r
-               allowNegative: false,\r
-               maxValue: 10\r
-           }))\r
-        },{\r
-           header: "Available",\r
-           dataIndex: 'availDate',\r
-           width: 95,\r
-           renderer: formatDate,\r
-           editor: new Ed(new fm.DateField({\r
-                format: 'm/d/y',\r
-                minValue: '01/01/06',\r
-                disabledDays: [0, 6],\r
-                disabledDaysText: 'Plants are not available on the weekends'\r
-            }))\r
-        },{\r
-           header: "Indoor?",\r
-           dataIndex: 'indoor',\r
-           width: 55,\r
-           renderer: formatBoolean,\r
-           editor: new Ed(new fm.Checkbox())\r
-        }]);\r
-\r
-    // by default columns are sortable\r
-    cm.defaultSortable = true;\r
-\r
-    // this could be inline, but we want to define the Plant record\r
-    // type so we can add records dynamically\r
-    var Plant = Roo.data.Record.create([\r
-           // the "name" below matches the tag name to read, except "availDate"\r
-           // which is mapped to the tag "availability"\r
-           {name: 'common', type: 'string'},\r
-           {name: 'botanical', type: 'string'},\r
-           {name: 'light'},\r
-           {name: 'price', type: 'float'},             // automatic date conversions\r
-           {name: 'availDate', mapping: 'availability', type: 'date', dateFormat: 'm/d/Y'},\r
-           {name: 'indoor', type: 'bool'}\r
-      ]);\r
-\r
-    // create the Data Store\r
-    var ds = new Roo.data.Store({\r
-        // load using HTTP\r
-        proxy: new Roo.data.HttpProxy({url: 'plants.xml'}),\r
-\r
-        // the return will be XML, so lets set up a reader\r
-        reader: new Roo.data.XmlReader({\r
-               // records will have a "plant" tag\r
-               record: 'plant'\r
-           }, Plant)\r
-    });\r
-\r
-    // create the editor grid\r
-    var grid = new Roo.grid.EditorGrid('editor-grid', {\r
-        ds: ds,\r
-        cm: cm,\r
-        enableColLock:false\r
-    });\r
-\r
-    var layout = Roo.BorderLayout.create({\r
-        center: {\r
-            margins:{left:3,top:3,right:3,bottom:3},\r
-            panels: [new Roo.GridPanel(grid)]\r
-        }\r
-    }, 'grid-panel');\r
-\r
-\r
-    // render it\r
-    grid.render();\r
-\r
-    \r
-    var gridHead = grid.getView().getHeaderPanel(true);\r
-    var tb = new Roo.Toolbar(gridHead, [{\r
-        text: 'Add Plant',\r
-        handler : function(){\r
-            var p = new Plant({\r
-                common: 'New Plant 1',\r
-                light: 'Mostly Shade',\r
-                price: 0,\r
-                availDate: new Date(),\r
-                indoor: false\r
-            });\r
-            grid.stopEditing();\r
-            ds.insert(0, p);\r
-            grid.startEditing(0, 0);\r
-        }\r
-    }]);\r
-\r
-    // trigger the data store load\r
-    ds.load();\r
+
+var grid = false;
+
+Roo.onReady(function(){
+    Roo.QuickTips.init();
+    function formatBoolean(value){
+        return value ? 'Yes' : 'No';  
+    };
+    
+    function formatDate(value){
+        return value ? value.dateFormat('M d, Y') : '';
+    };
+    // shorthand alias
+    var fm = Roo.form, Ed = Roo.grid.GridEditor;
+
+    // the column model has information about grid columns
+    // dataIndex maps the column to the specific data field in
+    // the data store (created below)
+    var cm = new Roo.grid.ColumnModel([{
+           header: "Common Name",
+           dataIndex: 'common',
+           width: 220,
+           editor: new Ed(new fm.TextField({
+               allowBlank: false
+           }))
+        },{
+           header: "Light",
+           dataIndex: 'light',
+           width: 130,
+           editor: new Ed(new Roo.form.ComboBox({
+               typeAhead: true,
+               triggerAction: 'all',
+               transform:'light',
+               lazyRender:true
+            }))
+        },{
+           header: "Price",
+           dataIndex: 'price',
+           width: 70,
+           align: 'right',
+           renderer: 'usMoney',
+           editor: new Ed(new fm.NumberField({
+               allowBlank: false,
+               allowNegative: false,
+               maxValue: 10
+           }))
+        },{
+           header: "Available",
+           dataIndex: 'availDate',
+           width: 95,
+           renderer: formatDate,
+           editor: new Ed(new fm.DateField({
+                format: 'm/d/y',
+                minValue: '01/01/06',
+                disabledDays: [0, 6],
+                disabledDaysText: 'Plants are not available on the weekends'
+            }))
+        },{
+           header: "Indoor?",
+           dataIndex: 'indoor',
+           width: 55,
+           renderer: formatBoolean,
+           editor: new Ed(new fm.Checkbox())
+        }]);
+
+    // by default columns are sortable
+    cm.defaultSortable = true;
+
+    // this could be inline, but we want to define the Plant record
+    // type so we can add records dynamically
+    var Plant = Roo.data.Record.create([
+           // the "name" below matches the tag name to read, except "availDate"
+           // which is mapped to the tag "availability"
+           {name: 'common', type: 'string'},
+           {name: 'botanical', type: 'string'},
+           {name: 'light'},
+           {name: 'price', type: 'float'},             // automatic date conversions
+           {name: 'availDate', mapping: 'availability', type: 'date', dateFormat: 'm/d/Y'},
+           {name: 'indoor', type: 'bool'}
+      ]);
+
+    // create the Data Store
+    var ds = new Roo.data.Store({
+        // load using HTTP
+        proxy: new Roo.data.HttpProxy({url: 'plants.xml'}),
+        remoteSort : true,
+        
+        // the return will be XML, so lets set up a reader
+        reader: new Roo.data.XmlReader({
+               // records will have a "plant" tag
+               record: 'plant'
+           }, Plant)
+    });
+
+    // create the editor grid
+    grid = new Roo.grid.EditorGrid('editor-grid', {
+        ds: ds,
+        cm: cm,
+        enableColLock:false,
+        multiSort : true
+    });
+
+    var layout = Roo.BorderLayout.create({
+        center: {
+            margins:{left:3,top:3,right:3,bottom:3},
+            panels: [new Roo.GridPanel(grid)]
+        }
+    }, 'grid-panel');
+
+
+    // render it
+    grid.render();
+
+    
+    var gridHead = grid.getView().getHeaderPanel(true);
+    var tb = new Roo.Toolbar(gridHead, [{
+        text: 'Add Plant',
+        handler : function(){
+            var p = new Plant({
+                common: 'New Plant 1',
+                light: 'Mostly Shade',
+                price: 0,
+                availDate: new Date(),
+                indoor: false
+            });
+            grid.stopEditing();
+            ds.insert(0, p);
+            grid.startEditing(0, 0);
+        }
+    }]);
+
+    // trigger the data store load
+    ds.load();
 });
\ No newline at end of file
index c61e772..b98ada1 100644 (file)
@@ -305,16 +305,16 @@ f.getField=function(B){return p.fields.get(B);};return f;};Roo.data.Record.AUTO_
 this.dirty=true;if(!this.modified){this.modified={};}if(typeof this.modified[A]=='undefined'){this.modified[A]=this.data[A];}
 this.data[A]=B;if(!this.editing){this.store.afterEdit(this);}},get:function(A){return this.data[A];},beginEdit:function(){this.editing=true;this.modified={};},cancelEdit:function(){this.editing=false;delete this.modified;},endEdit:function(){this.editing=false;if(this.dirty&&this.store){this.store.afterEdit(this);}},reject:function(){var m=this.modified;for(var n in m){if(typeof m[n]!="function"){this.data[n]=m[n];}}
 this.dirty=false;delete this.modified;this.editing=false;if(this.store){this.store.afterReject(this);}},commit:function(){this.dirty=false;delete this.modified;this.editing=false;if(this.store){this.store.afterCommit(this);}},hasError:function(){return this.error!=null;},clearError:function(){this.error=null;},copy:function(A){return new this.constructor(Roo.apply({},this.data),A||this.id);}};
-Roo.data.Store=function(A){this.data=new Roo.util.MixedCollection(false);this.data.getKey=function(o){return o.id;};this.baseParams={};this.paramNames={"start":"start","limit":"limit","sort":"sort","dir":"dir"};if(A&&A.data){this.inlineData=A.data;delete A.data;}
+Roo.data.Store=function(A){this.data=new Roo.util.MixedCollection(false);this.data.getKey=function(o){return o.id;};this.baseParams={};this.paramNames={"start":"start","limit":"limit","sort":"sort","dir":"dir","multisort":"_multisort"};if(A&&A.data){this.inlineData=A.data;delete A.data;}
 Roo.apply(this,A);if(this.reader){this.reader=Roo.factory(this.reader,Roo.data);this.reader.xmodule=this.xmodule||false;if(!this.recordType){this.recordType=this.reader.recordType;}if(this.reader.onMetaChange){this.reader.onMetaChange=this.onMetaChange.createDelegate(this);}}if(this.recordType){this.fields=this.recordType.prototype.fields;}
 this.modified=[];this.addEvents({datachanged:true,metachange:true,add:true,remove:true,update:true,clear:true,beforeload:true,load:true,loadexception:true});if(this.proxy){this.proxy=Roo.factory(this.proxy,Roo.data);this.proxy.xmodule=this.xmodule||false;this.relayEvents(this.proxy,["loadexception"]);}
-this.sortToggle={};Roo.data.Store.superclass.constructor.call(this);if(this.inlineData){this.loadData(this.inlineData);delete this.inlineData;}};Roo.extend(Roo.data.Store,Roo.util.Observable,{remoteSort:false,pruneModifiedRecords:false,lastOptions:null,add:function(A){A=[].concat(A);for(var i=0,B=A.length;i<B;i++){A[i].join(this);}var C=this.data.length;this.data.addAll(A);this.fireEvent("add",this,A,C);},remove:function(A){var B=this.data.indexOf(A);this.data.removeAt(B);if(this.pruneModifiedRecords){this.modified.remove(A);}
+this.sortToggle={};this.sortOrder=[];Roo.data.Store.superclass.constructor.call(this);if(this.inlineData){this.loadData(this.inlineData);delete this.inlineData;}};Roo.extend(Roo.data.Store,Roo.util.Observable,{multiSort:false,remoteSort:false,pruneModifiedRecords:false,lastOptions:null,add:function(A){A=[].concat(A);for(var i=0,B=A.length;i<B;i++){A[i].join(this);}var C=this.data.length;this.data.addAll(A);this.fireEvent("add",this,A,C);},remove:function(A){var B=this.data.indexOf(A);this.data.removeAt(B);if(this.pruneModifiedRecords){this.modified.remove(A);}
 this.fireEvent("remove",this,A,B);},removeAll:function(){this.data.clear();if(this.pruneModifiedRecords){this.modified=[];}
 this.fireEvent("clear",this);},insert:function(A,B){B=[].concat(B);for(var i=0,C=B.length;i<C;i++){this.data.insert(A,B[i]);B[i].join(this);}
-this.fireEvent("add",this,B,A);},indexOf:function(A){return this.data.indexOf(A);},indexOfId:function(id){return this.data.indexOfKey(id);},getById:function(id){return this.data.key(id);},getAt:function(A){return this.data.itemAt(A);},getRange:function(A,B){return this.data.getRange(A,B);},storeOptions:function(o){o=Roo.apply({},o);delete o.callback;delete o.scope;this.lastOptions=o;},load:function(A){A=A||{};if(this.fireEvent("beforeload",this,A)!==false){this.storeOptions(A);var p=Roo.apply(A.params||{},this.baseParams);if(!this.reader.metaFromRemote){p._requestMeta=1;}if(this.sortInfo&&this.remoteSort){var pn=this.paramNames;p[pn["sort"]]=this.sortInfo.field;p[pn["dir"]]=this.sortInfo.direction;}
+this.fireEvent("add",this,B,A);},indexOf:function(A){return this.data.indexOf(A);},indexOfId:function(id){return this.data.indexOfKey(id);},getById:function(id){return this.data.key(id);},getAt:function(A){return this.data.itemAt(A);},getRange:function(A,B){return this.data.getRange(A,B);},storeOptions:function(o){o=Roo.apply({},o);delete o.callback;delete o.scope;this.lastOptions=o;},load:function(A){A=A||{};if(this.fireEvent("beforeload",this,A)!==false){this.storeOptions(A);var p=Roo.apply(A.params||{},this.baseParams);if(!this.reader.metaFromRemote){p._requestMeta=1;}if(this.sortInfo&&this.remoteSort){var pn=this.paramNames;p[pn["sort"]]=this.sortInfo.field;p[pn["dir"]]=this.sortInfo.direction;}if(this.multiSort){var pn=this.paramNames;p[pn["multisort"]]=Roo.encode({sort:this.sortToggle,order:this.sortOrder});}
 this.proxy.load(p,this.reader,this.loadRecords,this,A);}},reload:function(A){this.load(Roo.applyIf(A||{},this.lastOptions));},loadRecords:function(o,A,B){if(!o||B===false){if(B!==false){this.fireEvent("load",this,[],A);}if(A.callback){A.callback.call(A.scope||this,[],A,false);}return;}if(o.success===false){this.fireEvent("loadexception",this,o,A,this.reader.jsonData);return;}var r=o.records,t=o.totalRecords||r.length;if(!A||A.add!==true){if(this.pruneModifiedRecords){this.modified=[];}for(var i=0,C=r.length;i<C;i++){r[i].join(this);}if(this.snapshot){this.data=this.snapshot;delete this.snapshot;}
 this.data.clear();this.data.addAll(r);this.totalLength=t;this.applySort();this.fireEvent("datachanged",this);}else {this.totalLength=Math.max(t,this.data.length+r.length);this.add(r);}
-this.fireEvent("load",this,r,A);if(A.callback){A.callback.call(A.scope||this,r,A,true);}},loadData:function(o,A){var r=this.reader.readRecords(o);this.loadRecords(r,{add:A},true);},getCount:function(){return this.data.length||0;},getTotalCount:function(){return this.totalLength||0;},getSortState:function(){return this.sortInfo;},applySort:function(){if(this.sortInfo&&!this.remoteSort){var s=this.sortInfo,f=s.field;var st=this.fields.get(f).sortType;var fn=function(r1,r2){var v1=st(r1.data[f]),v2=st(r2.data[f]);return v1>v2?1:(v1<v2?-1:0);};this.data.sort(s.direction,fn);if(this.snapshot&&this.snapshot!=this.data){this.snapshot.sort(s.direction,fn);}}},setDefaultSort:function(A,B){this.sortInfo={field:A,direction:B?B.toUpperCase():"ASC"};},sort:function(A,B){var f=this.fields.get(A);if(!B){if(this.sortInfo&&this.sortInfo.field==f.name){B=(this.sortToggle[f.name]||"ASC").toggle("ASC","DESC");}else {B=f.sortDir;}}
+this.fireEvent("load",this,r,A);if(A.callback){A.callback.call(A.scope||this,r,A,true);}},loadData:function(o,A){var r=this.reader.readRecords(o);this.loadRecords(r,{add:A},true);},getCount:function(){return this.data.length||0;},getTotalCount:function(){return this.totalLength||0;},getSortState:function(){return this.sortInfo;},applySort:function(){if(this.sortInfo&&!this.remoteSort){var s=this.sortInfo,f=s.field;var st=this.fields.get(f).sortType;var fn=function(r1,r2){var v1=st(r1.data[f]),v2=st(r2.data[f]);return v1>v2?1:(v1<v2?-1:0);};this.data.sort(s.direction,fn);if(this.snapshot&&this.snapshot!=this.data){this.snapshot.sort(s.direction,fn);}}},setDefaultSort:function(A,B){this.sortInfo={field:A,direction:B?B.toUpperCase():"ASC"};},sort:function(A,B){var f=this.fields.get(A);if(!B){this.sortToggle[f.name]=this.sortToggle[f.name]||f.sortDir;if(this.multiSort||(this.sortInfo&&this.sortInfo.field==f.name)){B=(this.sortToggle[f.name]||"ASC").toggle("ASC","DESC");}else {B=f.sortDir;}}
 this.sortToggle[f.name]=B;this.sortInfo={field:f.name,direction:B};if(!this.remoteSort){this.applySort();this.fireEvent("datachanged",this);}else {this.load(this.lastOptions);}},each:function(fn,A){this.data.each(fn,A);},getModifiedRecords:function(){return this.modified;},createFilterFn:function(A,B,C){if(!B.exec){B=String(B);if(B.length==0){return false;}
 B=new RegExp((C===true?'':'^')+Roo.escapeRe(B),"i");}return function(r){return B.test(r.data[A]);};},sum:function(A,B,C){var rs=this.data.items,v=0;B=B||0;C=(C||C===0)?C:rs.length-1;for(var i=B;i<=C;i++){v+=(rs[i].data[A]||0);}return v;},filter:function(A,B,C){var fn=this.createFilterFn(A,B,C);return fn?this.filterBy(fn):this.clearFilter();},filterBy:function(fn,A){this.snapshot=this.snapshot||this.data;this.data=this.queryBy(fn,A||this);this.fireEvent("datachanged",this);},query:function(A,B,C){var fn=this.createFilterFn(A,B,C);return fn?this.queryBy(fn):this.data.clone();},queryBy:function(fn,A){var B=this.snapshot||this.data;return B.filterBy(fn,A||this);},collect:function(A,B,C){var d=(C===true&&this.snapshot)?this.snapshot.items:this.data.items;var v,sv,r=[],l={};for(var i=0,D=d.length;i<D;i++){v=d[i].data[A];sv=String(v);if((B||!Roo.isEmpty(v))&&!l[sv]){l[sv]=true;r[r.length]=v;}}return r;},clearFilter:function(A){if(this.snapshot&&this.snapshot!=this.data){this.data=this.snapshot;delete this.snapshot;if(A!==true){this.fireEvent("datachanged",this);}}},afterEdit:function(A){if(this.modified.indexOf(A)==-1){this.modified.push(A);}
 this.fireEvent("update",this,A,Roo.data.Record.EDIT);},afterReject:function(A){this.modified.remove(A);this.fireEvent("update",this,A,Roo.data.Record.REJECT);},afterCommit:function(A){this.modified.remove(A);this.fireEvent("update",this,A,Roo.data.Record.COMMIT);},commitChanges:function(){var m=this.modified.slice(0);this.modified=[];for(var i=0,A=m.length;i<A;i++){m[i].commit();}},rejectChanges:function(){var m=this.modified.slice(0);this.modified=[];for(var i=0,A=m.length;i<A;i++){m[i].reject();}},onMetaChange:function(A,B,o){this.recordType=B;this.fields=B.prototype.fields;delete this.snapshot;this.sortInfo=A.sortInfo||this.sortInfo;this.modified=[];this.fireEvent('metachange',this,this.reader.meta);}});
@@ -869,7 +869,7 @@ A++;}}return null;},getSelections:function(){return this.selModel.getSelections(
 Roo.grid.AbstractGridView=function(){this.grid=null;this.events={"beforerowremoved":true,"beforerowsinserted":true,"beforerefresh":true,"rowremoved":true,"rowsinserted":true,"rowupdated":true,"refresh":true};Roo.grid.AbstractGridView.superclass.constructor.call(this);};Roo.extend(Roo.grid.AbstractGridView,Roo.util.Observable,{rowClass:"x-grid-row",cellClass:"x-grid-cell",tdClass:"x-grid-td",hdClass:"x-grid-hd",splitClass:"x-grid-hd-split",init:function(A){this.grid=A;var B=this.grid.getGridEl().id;this.colSelector="#"+B+" ."+this.cellClass+"-";this.tdSelector="#"+B+" ."+this.tdClass+"-";this.hdSelector="#"+B+" ."+this.hdClass+"-";this.splitSelector="#"+B+" ."+this.splitClass+"-";},getColumnRenderers:function(){var A=[];var cm=this.grid.colModel;var B=cm.getColumnCount();for(var i=0;i<B;i++){A[i]=cm.getRenderer(i);}return A;},getColumnIds:function(){var A=[];var cm=this.grid.colModel;var B=cm.getColumnCount();for(var i=0;i<B;i++){A[i]=cm.getColumnId(i);}return A;},getDataIndexes:function(){if(!this.indexMap){this.indexMap=this.buildIndexMap();}return this.indexMap.colToData;},getColumnIndexByDataIndex:function(A){if(!this.indexMap){this.indexMap=this.buildIndexMap();}return this.indexMap.dataToCol[A];},setCSSStyle:function(A,B,C){var D="#"+this.grid.id+" .x-grid-col-"+A;Roo.util.CSS.updateRule(D,B,C);},generateRules:function(cm){var A=[],B=this.grid.id+'-cssrules';Roo.util.CSS.removeStyleSheet(B);for(var i=0,C=cm.getColumnCount();i<C;i++){var D=cm.getColumnId(i);A.push(this.colSelector,D," {\n",cm.config[i].css,"}\n",this.tdSelector,D," {\n}\n",this.hdSelector,D," {\n}\n",this.splitSelector,D," {\n}\n");}return Roo.util.CSS.createStyleSheet(A.join(""),B);}});
 Roo.grid.HeaderDragZone=function(A,hd,B){this.grid=A;this.view=A.getView();this.ddGroup="gridHeader"+this.grid.getGridEl().id;Roo.grid.HeaderDragZone.superclass.constructor.call(this,hd);if(B){this.setHandleElId(Roo.id(hd));this.setOuterHandleElId(Roo.id(B));}
 this.scroll=false;};Roo.extend(Roo.grid.HeaderDragZone,Roo.dd.DragZone,{maxDragWidth:120,getDragData:function(e){var t=Roo.lib.Event.getTarget(e);var h=this.view.findHeaderCell(t);if(h){return {ddel:h.firstChild,header:h};}return false;},onInitDrag:function(e){this.view.headersDisabled=true;var A=this.dragData.ddel.cloneNode(true);A.id=Roo.id();A.style.width=Math.min(this.dragData.header.offsetWidth,this.maxDragWidth)+"px";this.proxy.update(A);return true;},afterValidDrop:function(){var v=this.view;setTimeout(function(){v.headersDisabled=false;},50);},afterInvalidDrop:function(){var v=this.view;setTimeout(function(){v.headersDisabled=false;},50);}});
-Roo.grid.HeaderDropZone=function(A,hd,B){this.grid=A;this.view=A.getView();this.proxyTop=Roo.DomHelper.append(document.body,{cls:"col-move-top",html:"&#160;"},true);this.proxyBottom=Roo.DomHelper.append(document.body,{cls:"col-move-bottom",html:"&#160;"},true);this.proxyTop.hide=this.proxyBottom.hide=function(){this.setLeftTop(-100,-100);this.setStyle("visibility","hidden");};this.ddGroup="gridHeader"+this.grid.getGridEl().id;Roo.grid.HeaderDropZone.superclass.constructor.call(this,A.getGridEl().dom);};Roo.extend(Roo.grid.HeaderDropZone,Roo.dd.DropZone,{proxyOffsets:[-4,-9],fly:Roo.Element.fly,getTargetFromEvent:function(e){var t=Roo.lib.Event.getTarget(e);var A=this.view.findCellIndex(t);if(A!==false){return this.view.getHeaderCell(A);}},nextVisible:function(h){var v=this.view,cm=this.grid.colModel;h=h.nextSibling;while(h){if(!cm.isHidden(v.getCellIndex(h))){return h;}
+Roo.grid.HeaderDropZone=function(A,hd,B){this.grid=A;this.view=A.getView();this.proxyTop=Roo.DomHelper.append(document.body,{cls:"col-move-top",html:"&#160;"},true);this.proxyBottom=Roo.DomHelper.append(document.body,{cls:"col-move-bottom",html:"&#160;"},true);this.proxyTop.hide=this.proxyBottom.hide=function(){this.setLeftTop(-100,-100);this.setStyle("visibility","hidden");};this.ddGroup="gridHeader"+this.grid.getGridEl().id;Roo.grid.HeaderDropZone.superclass.constructor.call(this,A.getGridEl().dom);};Roo.extend(Roo.grid.HeaderDropZone,Roo.dd.DropZone,{proxyOffsets:[-4,-9],fly:Roo.Element.fly,getTargetFromEvent:function(e){var t=Roo.lib.Event.getTarget(e);var A=this.view.findCellIndex(t);if(A!==false){return this.view.getHeaderCell(A);}return null;},nextVisible:function(h){var v=this.view,cm=this.grid.colModel;h=h.nextSibling;while(h){if(!cm.isHidden(v.getCellIndex(h))){return h;}
 h=h.nextSibling;}return null;},prevVisible:function(h){var v=this.view,cm=this.grid.colModel;h=h.prevSibling;while(h){if(!cm.isHidden(v.getCellIndex(h))){return h;}
 h=h.prevSibling;}return null;},positionIndicator:function(h,n,e){var x=Roo.lib.Event.getPageX(e);var r=Roo.lib.Dom.getRegion(n.firstChild);var px,pt,py=r.top+this.proxyOffsets[1];if((r.right-x)<=(r.right-r.left)/2){px=r.right+this.view.borderWidth;pt="after";}else {px=r.left;pt="before";}var A=this.view.getCellIndex(h);var B=this.view.getCellIndex(n);if(this.grid.colModel.isFixed(B)){return false;}var C=this.grid.colModel.isLocked(B);if(pt=="after"){B++;}if(A<B){B--;}if(A==B&&(C==this.grid.colModel.isLocked(A))){return false;}
 px+=this.proxyOffsets[0];this.proxyTop.setLeftTop(px,py);this.proxyTop.show();if(!this.bottomOffset){this.bottomOffset=this.view.mainHd.getHeight();}
@@ -904,10 +904,13 @@ rp.alt=L.join(" ");E+=rt.apply(rp);rp.cells=cb;D+=rt.apply(rp);}return [E,D];}:f
 rp.cells=F;if(this.getRowClass){L.push(this.getRowClass(r,G));}if(H){I={record:r,rowIndex:G,rowClass:''}
 this.grid.fireEvent('rowclass',this,I);L.push(I.rowClass);}
 rp.alt=L.join(" ");rp.cells=F.join("");E[E.length]=rt.apply(rp);rp.cells=cb.join("");D[D.length]=rt.apply(rp);}return [E.join(""),D.join("")];},renderBody:function(){var A=this.renderRows();var bt=this.templates.body;return [bt.apply({rows:A[0]}),bt.apply({rows:A[1]})];},refresh:function(A){this.fireEvent("beforerefresh",this);this.grid.stopEditing();var B=this.renderBody();this.lockedBody.update(B[0]);this.mainBody.update(B[1]);if(A===true){this.updateHeaders();this.updateColumns();this.updateSplitters();this.updateHeaderSortState();}
-this.syncRowHeights();this.layout();this.fireEvent("refresh",this);},handleColumnMove:function(cm,A,B){this.indexMap=null;var s=this.getScrollState();this.refresh(true);this.restoreScroll(s);this.afterMove(B);},afterMove:function(A){if(this.enableMoveAnim&&Roo.enableFx){this.fly(this.getHeaderCell(A).firstChild).highlight(this.hlColor);}},updateCell:function(dm,A,B){var C=this.getColumnIndexByDataIndex(B);if(typeof C=="undefined"){return;}var cm=this.grid.colModel;var D=this.getCell(A,C);var E=this.getCellText(A,C);var p={cellId:"x-grid-cell-"+A+"-"+C,id:cm.getColumnId(C),css:C==cm.getColumnCount()-1?"x-grid-col-last":""};var F=cm.getRenderer(C);var G=F(dm.getValueAt(A,B),p,A,C,dm);if(typeof G=="undefined"||G==="")G="&#160;";E.innerHTML=G;D.className=this.cellClass+" "+this.idToCssName(p.cellId)+" "+p.css;this.syncRowHeights(A,A);},calcColumnWidth:function(A,B){var C=0;if(this.grid.autoSizeHeaders){var h=this.getHeaderCellMeasure(A);C=Math.max(C,h.scrollWidth);}var tb,D;if(this.cm.isLocked(A)){tb=this.getLockedTable();D=A;}else {tb=this.getBodyTable();D=A-this.cm.getLockedCount();}if(tb&&tb.rows){var E=tb.rows;var F=Math.min(B||E.length,E.length);for(var i=0;i<F;i++){var G=E[i].childNodes[D].firstChild;C=Math.max(C,G.scrollWidth);}}return C+5;},autoSizeColumn:function(A,B,C){if(this.cm.isHidden(A)){return;}if(B){var D=this.cm.getColumnId(A);this.css.updateRule(this.colSelector+this.idToCssName(D),"width",this.grid.minColumnWidth+"px");if(this.grid.autoSizeHeaders){this.css.updateRule(this.hdSelector+this.idToCssName(D),"width",this.grid.minColumnWidth+"px");}}var E=this.calcColumnWidth(A);this.cm.setColumnWidth(A,Math.max(this.grid.minColumnWidth,E),C);if(!C){this.grid.fireEvent("columnresize",A,E);}},autoSizeColumns:function(){var cm=this.grid.colModel;var A=cm.getColumnCount();for(var i=0;i<A;i++){this.autoSizeColumn(i,true,true);}if(cm.getTotalWidth()<this.scroller.dom.clientWidth){this.fitColumns();}else {this.updateColumns();this.layout();}},fitColumns:function(A){var cm=this.grid.colModel;var B=cm.getColumnCount();var C=[];var D=0;var i,w;for(i=0;i<B;i++){if(!cm.isHidden(i)&&!cm.isFixed(i)){w=cm.getColumnWidth(i);C.push(i);C.push(w);D+=w;}}var E=Math.min(this.scroller.dom.clientWidth,this.el.getWidth());if(A){E-=17;}var F=(E-cm.getTotalWidth())/D;while(C.length){w=C.pop();i=C.pop();cm.setColumnWidth(i,Math.floor(w+w*F),true);}
-this.updateColumns();this.layout();},onRowSelect:function(A){var B=this.getRowComposite(A);B.addClass("x-grid-row-selected");},onRowDeselect:function(A){var B=this.getRowComposite(A);B.removeClass("x-grid-row-selected");},onCellSelect:function(A,B){var C=this.getCell(A,B);if(C){Roo.fly(C).addClass("x-grid-cell-selected");}},onCellDeselect:function(A,B){var C=this.getCell(A,B);if(C){Roo.fly(C).removeClass("x-grid-cell-selected");}},updateHeaderSortState:function(){var A=this.ds.getSortState();if(!A){return;}
-this.sortState=A;var B=this.cm.findColumnIndex(A.field);if(B!=-1){var C=A.direction;var sc=this.sortClasses;var D=this.el.select(this.headerSelector).removeClass(sc);D.item(B).addClass(sc[C=="DESC"?1:0]);}},handleHeaderClick:function(g,A){if(this.headersDisabled){return;}var dm=g.dataSource,cm=g.colModel;if(!cm.isSortable(A)){return;}
-g.stopEditing();dm.sort(cm.getDataIndex(A));},destroy:function(){if(this.colMenu){this.colMenu.removeAll();Roo.menu.MenuMgr.unregister(this.colMenu);this.colMenu.getEl().remove();delete this.colMenu;}if(this.hmenu){this.hmenu.removeAll();Roo.menu.MenuMgr.unregister(this.hmenu);this.hmenu.getEl().remove();delete this.hmenu;}if(this.grid.enableColumnMove){var A=Roo.dd.DDM.ids['gridHeader'+this.grid.getGridEl().id];if(A){for(var dd in A){if(!A[dd].config.isTarget&&A[dd].dragElId){var B=A[dd].dragElId;A[dd].unreg();Roo.get(B).remove();}else if(A[dd].config.isTarget){A[dd].proxyTop.remove();A[dd].proxyBottom.remove();A[dd].unreg();}if(Roo.dd.DDM.locationCache[dd]){delete Roo.dd.DDM.locationCache[dd];}}delete Roo.dd.DDM.ids['gridHeader'+this.grid.getGridEl().id];}}
+this.syncRowHeights();this.layout();this.fireEvent("refresh",this);},handleColumnMove:function(cm,A,B){this.indexMap=null;var s=this.getScrollState();this.refresh(true);this.restoreScroll(s);this.afterMove(B);},afterMove:function(A){if(this.enableMoveAnim&&Roo.enableFx){this.fly(this.getHeaderCell(A).firstChild).highlight(this.hlColor);}if(this.grid.dataSource.multiSort){var dm=this.grid.dataSource;var cm=this.grid.colModel;var so=[];for(var i=0;i<cm.config.length;i++){if((typeof(dm.sortToggle[cm.config[i].dataIndex])=='undefined')){continue;}
+so.push(cm.config[i].dataIndex);};dm.sortOrder=so;dm.load(dm.lastOptions);}},updateCell:function(dm,A,B){var C=this.getColumnIndexByDataIndex(B);if(typeof C=="undefined"){return;}var cm=this.grid.colModel;var D=this.getCell(A,C);var E=this.getCellText(A,C);var p={cellId:"x-grid-cell-"+A+"-"+C,id:cm.getColumnId(C),css:C==cm.getColumnCount()-1?"x-grid-col-last":""};var F=cm.getRenderer(C);var G=F(dm.getValueAt(A,B),p,A,C,dm);if(typeof G=="undefined"||G==="")G="&#160;";E.innerHTML=G;D.className=this.cellClass+" "+this.idToCssName(p.cellId)+" "+p.css;this.syncRowHeights(A,A);},calcColumnWidth:function(A,B){var C=0;if(this.grid.autoSizeHeaders){var h=this.getHeaderCellMeasure(A);C=Math.max(C,h.scrollWidth);}var tb,D;if(this.cm.isLocked(A)){tb=this.getLockedTable();D=A;}else {tb=this.getBodyTable();D=A-this.cm.getLockedCount();}if(tb&&tb.rows){var E=tb.rows;var F=Math.min(B||E.length,E.length);for(var i=0;i<F;i++){var G=E[i].childNodes[D].firstChild;C=Math.max(C,G.scrollWidth);}}return C+5;},autoSizeColumn:function(A,B,C){if(this.cm.isHidden(A)){return;}if(B){var D=this.cm.getColumnId(A);this.css.updateRule(this.colSelector+this.idToCssName(D),"width",this.grid.minColumnWidth+"px");if(this.grid.autoSizeHeaders){this.css.updateRule(this.hdSelector+this.idToCssName(D),"width",this.grid.minColumnWidth+"px");}}var E=this.calcColumnWidth(A);this.cm.setColumnWidth(A,Math.max(this.grid.minColumnWidth,E),C);if(!C){this.grid.fireEvent("columnresize",A,E);}},autoSizeColumns:function(){var cm=this.grid.colModel;var A=cm.getColumnCount();for(var i=0;i<A;i++){this.autoSizeColumn(i,true,true);}if(cm.getTotalWidth()<this.scroller.dom.clientWidth){this.fitColumns();}else {this.updateColumns();this.layout();}},fitColumns:function(A){var cm=this.grid.colModel;var B=cm.getColumnCount();var C=[];var D=0;var i,w;for(i=0;i<B;i++){if(!cm.isHidden(i)&&!cm.isFixed(i)){w=cm.getColumnWidth(i);C.push(i);C.push(w);D+=w;}}var E=Math.min(this.scroller.dom.clientWidth,this.el.getWidth());if(A){E-=17;}var F=(E-cm.getTotalWidth())/D;while(C.length){w=C.pop();i=C.pop();cm.setColumnWidth(i,Math.floor(w+w*F),true);}
+this.updateColumns();this.layout();},onRowSelect:function(A){var B=this.getRowComposite(A);B.addClass("x-grid-row-selected");},onRowDeselect:function(A){var B=this.getRowComposite(A);B.removeClass("x-grid-row-selected");},onCellSelect:function(A,B){var C=this.getCell(A,B);if(C){Roo.fly(C).addClass("x-grid-cell-selected");}},onCellDeselect:function(A,B){var C=this.getCell(A,B);if(C){Roo.fly(C).removeClass("x-grid-cell-selected");}},updateHeaderSortState:function(){var A={};if(!this.ds.multiSort){var B=this.ds.getSortState();if(!B){return;}
+A[B.field]=B.direction;this.sortState=B;}else {A=this.ds.sortToggle;}var sc=this.sortClasses;var C=this.el.select(this.headerSelector).removeClass(sc);for(var f in A){var D=this.cm.findColumnIndex(f);if(D!=-1){var E=A[f];C.item(D).addClass(sc[E=="DESC"?1:0]);}}},handleHeaderClick:function(g,A){if(this.headersDisabled){return;}var dm=g.dataSource,cm=g.colModel;if(!cm.isSortable(A)){return;}
+g.stopEditing();if(dm.multiSort){var so=[];for(var i=0;i<cm.config.length;i++){if((typeof(dm.sortToggle[cm.config[i].dataIndex])=='undefined')&&(A!=i)){continue;}
+so.push(cm.config[i].dataIndex);};dm.sortOrder=so;}
+dm.sort(cm.getDataIndex(A));},destroy:function(){if(this.colMenu){this.colMenu.removeAll();Roo.menu.MenuMgr.unregister(this.colMenu);this.colMenu.getEl().remove();delete this.colMenu;}if(this.hmenu){this.hmenu.removeAll();Roo.menu.MenuMgr.unregister(this.hmenu);this.hmenu.getEl().remove();delete this.hmenu;}if(this.grid.enableColumnMove){var A=Roo.dd.DDM.ids['gridHeader'+this.grid.getGridEl().id];if(A){for(var dd in A){if(!A[dd].config.isTarget&&A[dd].dragElId){var B=A[dd].dragElId;A[dd].unreg();Roo.get(B).remove();}else if(A[dd].config.isTarget){A[dd].proxyTop.remove();A[dd].proxyBottom.remove();A[dd].unreg();}if(Roo.dd.DDM.locationCache[dd]){delete Roo.dd.DDM.locationCache[dd];}}delete Roo.dd.DDM.ids['gridHeader'+this.grid.getGridEl().id];}}
 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id)+'-cssrules');this.bind(null,null);Roo.EventManager.removeResizeListener(this.onWindowResize,this);},handleLockChange:function(){this.refresh(true);},onDenyColumnLock:function(){},onDenyColumnHide:function(){},handleHdMenuClick:function(A){var B=this.hdCtxIndex;var cm=this.cm,ds=this.ds;switch(A.id){case "asc":ds.sort(cm.getDataIndex(B),"ASC");break;case "desc":ds.sort(cm.getDataIndex(B),"DESC");break;case "lock":var lc=cm.getLockedCount();if(cm.getColumnCount(true)<=lc+1){this.onDenyColumnLock();return;}if(lc!=B){cm.setLocked(B,true,true);cm.moveColumn(B,lc);this.grid.fireEvent("columnmove",B,lc);}else {cm.setLocked(B,true);}break;case "unlock":var lc=cm.getLockedCount();if((lc-1)!=B){cm.setLocked(B,false,true);cm.moveColumn(B,lc-1);this.grid.fireEvent("columnmove",B,lc-1);}else {cm.setLocked(B,false);}break;default:B=cm.getIndexById(A.id.substr(4));if(B!=-1){if(A.checked&&cm.getColumnCount(true)<=1){this.onDenyColumnHide();return false;}
 cm.setHidden(B,A.checked);}}return true;},beforeColMenuShow:function(){var cm=this.cm,A=cm.getColumnCount();this.colMenu.removeAll();for(var i=0;i<A;i++){this.colMenu.add(new Roo.menu.CheckItem({id:"col-"+cm.getColumnId(i),text:cm.getColumnHeader(i),checked:!cm.isHidden(i),hideOnClick:false}));}},handleHdCtx:function(g,A,e){e.stopEvent();var hd=this.getHeaderCell(A);this.hdCtxIndex=A;var ms=this.hmenu.items,cm=this.cm;ms.get("asc").setDisabled(!cm.isSortable(A));ms.get("desc").setDisabled(!cm.isSortable(A));if(this.grid.enableColLock!==false){ms.get("lock").setDisabled(cm.isLocked(A));ms.get("unlock").setDisabled(!cm.isLocked(A));}
 this.hmenu.show(hd,"tl-bl");},handleHdOver:function(e){var hd=this.findHeaderCell(e.getTarget());if(hd&&!this.headersDisabled){if(this.grid.colModel.isSortable(this.getCellIndex(hd))){this.fly(hd).addClass("x-grid-hd-over");}}},handleHdOut:function(e){var hd=this.findHeaderCell(e.getTarget());if(hd){this.fly(hd).removeClass("x-grid-hd-over");}},handleSplitDblClick:function(e,t){var i=this.getCellIndex(t);if(this.grid.enableColumnResize!==false&&this.cm.isResizable(i)&&!this.cm.isFixed(i)){this.autoSizeColumn(i,true);this.layout();}},render:function(){var cm=this.cm;var A=cm.getColumnCount();if(this.grid.monitorWindowResize===true){Roo.EventManager.onWindowResize(this.onWindowResize,this,true);}var B=this.renderHeaders();var C=this.templates.body.apply({rows:""});var D=this.templates.master.apply({lockedBody:C,body:C,lockedHeader:B[0],header:B[1]});this.grid.getGridEl().dom.innerHTML=D;this.initElements();this.el.on("scroll",function(){this.el.dom.scrollTop=0;},this);this.scroller.on("scroll",this.handleScroll,this);this.lockedBody.on("mousewheel",this.handleWheel,this);this.mainBody.on("mousewheel",this.handleWheel,this);this.mainHd.on("mouseover",this.handleHdOver,this);this.mainHd.on("mouseout",this.handleHdOut,this);this.mainHd.on("dblclick",this.handleSplitDblClick,this,{delegate:"."+this.splitClass});this.lockedHd.on("mouseover",this.handleHdOver,this);this.lockedHd.on("mouseout",this.handleHdOut,this);this.lockedHd.on("dblclick",this.handleSplitDblClick,this,{delegate:"."+this.splitClass});if(this.grid.enableColumnResize!==false&&Roo.grid.SplitDragZone){new Roo.grid.SplitDragZone(this.grid,this.lockedHd.dom,this.mainHd.dom);}
index 62e7fa1..14cd3e4 100644 (file)
@@ -19165,7 +19165,8 @@ Roo.data.Store = function(config){
         "start" : "start",
         "limit" : "limit",
         "sort" : "sort",
-        "dir" : "dir"
+        "dir" : "dir",
+        "multisort" : "_multisort"
     };
 
     if(config && config.data){
@@ -19277,6 +19278,7 @@ Roo.data.Store = function(config){
         this.relayEvents(this.proxy,  ["loadexception"]);
     }
     this.sortToggle = {};
+    this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
 
     Roo.data.Store.superclass.constructor.call(this);
 
@@ -19309,6 +19311,10 @@ Roo.extend(Roo.data.Store, Roo.util.Observable, {
     * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
     */
     /**
+    * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
+    */
+    multiSort: false,
+    /**
     * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
     * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
     */
@@ -19465,6 +19471,11 @@ Roo.extend(Roo.data.Store, Roo.util.Observable, {
                 p[pn["sort"]] = this.sortInfo.field;
                 p[pn["dir"]] = this.sortInfo.direction;
             }
+            if (this.multiSort) {
+                var pn = this.paramNames;
+                p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
+            }
+            
             this.proxy.load(p, this.reader, this.loadRecords, this, options);
         }
     },
@@ -19603,7 +19614,9 @@ Roo.extend(Roo.data.Store, Roo.util.Observable, {
     sort : function(fieldName, dir){
         var f = this.fields.get(fieldName);
         if(!dir){
-            if(this.sortInfo && this.sortInfo.field == f.name){ // toggle sort dir
+            this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
+            
+            if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
                 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
             }else{
                 dir = f.sortDir;
@@ -46460,7 +46473,7 @@ Roo.grid.Grid = function(container, config){
         this.dataSource= Roo.factory(this.dataSource, Roo.data);
         this.ds = this.dataSource;
         this.ds.xmodule = this.xmodule || false;
-        
+         
     }
     
     
@@ -46801,6 +46814,8 @@ Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
     */
     dropTarget: false,
     
+   
+    
     // private
     rendered : false,
 
@@ -47263,6 +47278,7 @@ Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
         if(cindex !== false){
             return this.view.getHeaderCell(cindex);
         }
+        return null;
     },
 
     nextVisible : function(h){
@@ -48394,6 +48410,26 @@ Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
         if(this.enableMoveAnim && Roo.enableFx){
             this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
         }
+        // if multisort - fix sortOrder, and reload..
+        if (this.grid.dataSource.multiSort) {
+            // the we can call sort again..
+            var dm = this.grid.dataSource;
+            var cm = this.grid.colModel;
+            var so = [];
+            for(var i = 0; i < cm.config.length; i++ ) {
+                
+                if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
+                    continue; // dont' bother, it's not in sort list or being set.
+                }
+                
+                so.push(cm.config[i].dataIndex);
+            };
+            dm.sortOrder = so;
+            dm.load(dm.lastOptions);
+            
+            
+        }
+        
     },
 
     updateCell : function(dm, rowIndex, dataIndex){
@@ -48540,20 +48576,43 @@ Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
     },
 
     updateHeaderSortState : function(){
-        var state = this.ds.getSortState();
-        if(!state){
-            return;
+        
+        // sort state can be single { field: xxx, direction : yyy}
+        // or   { xxx=>ASC , yyy : DESC ..... }
+        
+        var mstate = {};
+        if (!this.ds.multiSort) { 
+            var state = this.ds.getSortState();
+            if(!state){
+                return;
+            }
+            mstate[state.field] = state.direction;
+            // FIXME... - this is not used here.. but might be elsewhere..
+            this.sortState = state;
+            
+        } else {
+            mstate = this.ds.sortToggle;
         }
-        this.sortState = state;
-        var sortColumn = this.cm.findColumnIndex(state.field);
-        if(sortColumn != -1){
-            var sortDir = state.direction;
-            var sc = this.sortClasses;
-            var hds = this.el.select(this.headerSelector).removeClass(sc);
-            hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
+        //remove existing sort classes..
+        
+        var sc = this.sortClasses;
+        var hds = this.el.select(this.headerSelector).removeClass(sc);
+        
+        for(var f in mstate) {
+        
+            var sortColumn = this.cm.findColumnIndex(f);
+            
+            if(sortColumn != -1){
+                var sortDir = mstate[f];        
+                hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
+            }
         }
+        
+         
+        
     },
 
+
     handleHeaderClick : function(g, index){
         if(this.headersDisabled){
             return;
@@ -48563,6 +48622,22 @@ Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
             return;
         }
         g.stopEditing();
+        
+        if (dm.multiSort) {
+            // update the sortOrder
+            var so = [];
+            for(var i = 0; i < cm.config.length; i++ ) {
+                
+                if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
+                    continue; // dont' bother, it's not in sort list or being set.
+                }
+                
+                so.push(cm.config[i].dataIndex);
+            };
+            dm.sortOrder = so;
+        }
+        
+        
         dm.sort(cm.getDataIndex(index));
     },
 
index 574e69d..4f54ee7 100644 (file)
@@ -4720,7 +4720,8 @@ Roo.data.Store = function(config){
         "start" : "start",
         "limit" : "limit",
         "sort" : "sort",
-        "dir" : "dir"
+        "dir" : "dir",
+        "multisort" : "_multisort"
     };
 
     if(config && config.data){
@@ -4832,6 +4833,7 @@ Roo.data.Store = function(config){
         this.relayEvents(this.proxy,  ["loadexception"]);
     }
     this.sortToggle = {};
+    this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
 
     Roo.data.Store.superclass.constructor.call(this);
 
@@ -4864,6 +4866,10 @@ Roo.extend(Roo.data.Store, Roo.util.Observable, {
     * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
     */
     /**
+    * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
+    */
+    multiSort: false,
+    /**
     * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
     * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
     */
@@ -5020,6 +5026,11 @@ Roo.extend(Roo.data.Store, Roo.util.Observable, {
                 p[pn["sort"]] = this.sortInfo.field;
                 p[pn["dir"]] = this.sortInfo.direction;
             }
+            if (this.multiSort) {
+                var pn = this.paramNames;
+                p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
+            }
+            
             this.proxy.load(p, this.reader, this.loadRecords, this, options);
         }
     },
@@ -5158,7 +5169,9 @@ Roo.extend(Roo.data.Store, Roo.util.Observable, {
     sort : function(fieldName, dir){
         var f = this.fields.get(fieldName);
         if(!dir){
-            if(this.sortInfo && this.sortInfo.field == f.name){ // toggle sort dir
+            this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
+            
+            if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
                 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
             }else{
                 dir = f.sortDir;
@@ -32015,7 +32028,7 @@ Roo.grid.Grid = function(container, config){
         this.dataSource= Roo.factory(this.dataSource, Roo.data);
         this.ds = this.dataSource;
         this.ds.xmodule = this.xmodule || false;
-        
+         
     }
     
     
@@ -32356,6 +32369,8 @@ Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
     */
     dropTarget: false,
     
+   
+    
     // private
     rendered : false,
 
@@ -32818,6 +32833,7 @@ Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
         if(cindex !== false){
             return this.view.getHeaderCell(cindex);
         }
+        return null;
     },
 
     nextVisible : function(h){
@@ -33949,6 +33965,26 @@ Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
         if(this.enableMoveAnim && Roo.enableFx){
             this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
         }
+        // if multisort - fix sortOrder, and reload..
+        if (this.grid.dataSource.multiSort) {
+            // the we can call sort again..
+            var dm = this.grid.dataSource;
+            var cm = this.grid.colModel;
+            var so = [];
+            for(var i = 0; i < cm.config.length; i++ ) {
+                
+                if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
+                    continue; // dont' bother, it's not in sort list or being set.
+                }
+                
+                so.push(cm.config[i].dataIndex);
+            };
+            dm.sortOrder = so;
+            dm.load(dm.lastOptions);
+            
+            
+        }
+        
     },
 
     updateCell : function(dm, rowIndex, dataIndex){
@@ -34095,20 +34131,43 @@ Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
     },
 
     updateHeaderSortState : function(){
-        var state = this.ds.getSortState();
-        if(!state){
-            return;
+        
+        // sort state can be single { field: xxx, direction : yyy}
+        // or   { xxx=>ASC , yyy : DESC ..... }
+        
+        var mstate = {};
+        if (!this.ds.multiSort) { 
+            var state = this.ds.getSortState();
+            if(!state){
+                return;
+            }
+            mstate[state.field] = state.direction;
+            // FIXME... - this is not used here.. but might be elsewhere..
+            this.sortState = state;
+            
+        } else {
+            mstate = this.ds.sortToggle;
         }
-        this.sortState = state;
-        var sortColumn = this.cm.findColumnIndex(state.field);
-        if(sortColumn != -1){
-            var sortDir = state.direction;
-            var sc = this.sortClasses;
-            var hds = this.el.select(this.headerSelector).removeClass(sc);
-            hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
+        //remove existing sort classes..
+        
+        var sc = this.sortClasses;
+        var hds = this.el.select(this.headerSelector).removeClass(sc);
+        
+        for(var f in mstate) {
+        
+            var sortColumn = this.cm.findColumnIndex(f);
+            
+            if(sortColumn != -1){
+                var sortDir = mstate[f];        
+                hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
+            }
         }
+        
+         
+        
     },
 
+
     handleHeaderClick : function(g, index){
         if(this.headersDisabled){
             return;
@@ -34118,6 +34177,22 @@ Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
             return;
         }
         g.stopEditing();
+        
+        if (dm.multiSort) {
+            // update the sortOrder
+            var so = [];
+            for(var i = 0; i < cm.config.length; i++ ) {
+                
+                if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
+                    continue; // dont' bother, it's not in sort list or being set.
+                }
+                
+                so.push(cm.config[i].dataIndex);
+            };
+            dm.sortOrder = so;
+        }
+        
+        
         dm.sort(cm.getDataIndex(index));
     },
 
index 0d63566..0914083 100644 (file)
@@ -62,16 +62,16 @@ f.getField=function(B){return p.fields.get(B);};return f;};Roo.data.Record.AUTO_
 this.dirty=true;if(!this.modified){this.modified={};}if(typeof this.modified[A]=='undefined'){this.modified[A]=this.data[A];}
 this.data[A]=B;if(!this.editing){this.store.afterEdit(this);}},get:function(A){return this.data[A];},beginEdit:function(){this.editing=true;this.modified={};},cancelEdit:function(){this.editing=false;delete this.modified;},endEdit:function(){this.editing=false;if(this.dirty&&this.store){this.store.afterEdit(this);}},reject:function(){var m=this.modified;for(var n in m){if(typeof m[n]!="function"){this.data[n]=m[n];}}
 this.dirty=false;delete this.modified;this.editing=false;if(this.store){this.store.afterReject(this);}},commit:function(){this.dirty=false;delete this.modified;this.editing=false;if(this.store){this.store.afterCommit(this);}},hasError:function(){return this.error!=null;},clearError:function(){this.error=null;},copy:function(A){return new this.constructor(Roo.apply({},this.data),A||this.id);}};
-Roo.data.Store=function(A){this.data=new Roo.util.MixedCollection(false);this.data.getKey=function(o){return o.id;};this.baseParams={};this.paramNames={"start":"start","limit":"limit","sort":"sort","dir":"dir"};if(A&&A.data){this.inlineData=A.data;delete A.data;}
+Roo.data.Store=function(A){this.data=new Roo.util.MixedCollection(false);this.data.getKey=function(o){return o.id;};this.baseParams={};this.paramNames={"start":"start","limit":"limit","sort":"sort","dir":"dir","multisort":"_multisort"};if(A&&A.data){this.inlineData=A.data;delete A.data;}
 Roo.apply(this,A);if(this.reader){this.reader=Roo.factory(this.reader,Roo.data);this.reader.xmodule=this.xmodule||false;if(!this.recordType){this.recordType=this.reader.recordType;}if(this.reader.onMetaChange){this.reader.onMetaChange=this.onMetaChange.createDelegate(this);}}if(this.recordType){this.fields=this.recordType.prototype.fields;}
 this.modified=[];this.addEvents({datachanged:true,metachange:true,add:true,remove:true,update:true,clear:true,beforeload:true,load:true,loadexception:true});if(this.proxy){this.proxy=Roo.factory(this.proxy,Roo.data);this.proxy.xmodule=this.xmodule||false;this.relayEvents(this.proxy,["loadexception"]);}
-this.sortToggle={};Roo.data.Store.superclass.constructor.call(this);if(this.inlineData){this.loadData(this.inlineData);delete this.inlineData;}};Roo.extend(Roo.data.Store,Roo.util.Observable,{remoteSort:false,pruneModifiedRecords:false,lastOptions:null,add:function(A){A=[].concat(A);for(var i=0,B=A.length;i<B;i++){A[i].join(this);}var C=this.data.length;this.data.addAll(A);this.fireEvent("add",this,A,C);},remove:function(A){var B=this.data.indexOf(A);this.data.removeAt(B);if(this.pruneModifiedRecords){this.modified.remove(A);}
+this.sortToggle={};this.sortOrder=[];Roo.data.Store.superclass.constructor.call(this);if(this.inlineData){this.loadData(this.inlineData);delete this.inlineData;}};Roo.extend(Roo.data.Store,Roo.util.Observable,{multiSort:false,remoteSort:false,pruneModifiedRecords:false,lastOptions:null,add:function(A){A=[].concat(A);for(var i=0,B=A.length;i<B;i++){A[i].join(this);}var C=this.data.length;this.data.addAll(A);this.fireEvent("add",this,A,C);},remove:function(A){var B=this.data.indexOf(A);this.data.removeAt(B);if(this.pruneModifiedRecords){this.modified.remove(A);}
 this.fireEvent("remove",this,A,B);},removeAll:function(){this.data.clear();if(this.pruneModifiedRecords){this.modified=[];}
 this.fireEvent("clear",this);},insert:function(A,B){B=[].concat(B);for(var i=0,C=B.length;i<C;i++){this.data.insert(A,B[i]);B[i].join(this);}
-this.fireEvent("add",this,B,A);},indexOf:function(A){return this.data.indexOf(A);},indexOfId:function(id){return this.data.indexOfKey(id);},getById:function(id){return this.data.key(id);},getAt:function(A){return this.data.itemAt(A);},getRange:function(A,B){return this.data.getRange(A,B);},storeOptions:function(o){o=Roo.apply({},o);delete o.callback;delete o.scope;this.lastOptions=o;},load:function(A){A=A||{};if(this.fireEvent("beforeload",this,A)!==false){this.storeOptions(A);var p=Roo.apply(A.params||{},this.baseParams);if(!this.reader.metaFromRemote){p._requestMeta=1;}if(this.sortInfo&&this.remoteSort){var pn=this.paramNames;p[pn["sort"]]=this.sortInfo.field;p[pn["dir"]]=this.sortInfo.direction;}
+this.fireEvent("add",this,B,A);},indexOf:function(A){return this.data.indexOf(A);},indexOfId:function(id){return this.data.indexOfKey(id);},getById:function(id){return this.data.key(id);},getAt:function(A){return this.data.itemAt(A);},getRange:function(A,B){return this.data.getRange(A,B);},storeOptions:function(o){o=Roo.apply({},o);delete o.callback;delete o.scope;this.lastOptions=o;},load:function(A){A=A||{};if(this.fireEvent("beforeload",this,A)!==false){this.storeOptions(A);var p=Roo.apply(A.params||{},this.baseParams);if(!this.reader.metaFromRemote){p._requestMeta=1;}if(this.sortInfo&&this.remoteSort){var pn=this.paramNames;p[pn["sort"]]=this.sortInfo.field;p[pn["dir"]]=this.sortInfo.direction;}if(this.multiSort){var pn=this.paramNames;p[pn["multisort"]]=Roo.encode({sort:this.sortToggle,order:this.sortOrder});}
 this.proxy.load(p,this.reader,this.loadRecords,this,A);}},reload:function(A){this.load(Roo.applyIf(A||{},this.lastOptions));},loadRecords:function(o,A,B){if(!o||B===false){if(B!==false){this.fireEvent("load",this,[],A);}if(A.callback){A.callback.call(A.scope||this,[],A,false);}return;}if(o.success===false){this.fireEvent("loadexception",this,o,A,this.reader.jsonData);return;}var r=o.records,t=o.totalRecords||r.length;if(!A||A.add!==true){if(this.pruneModifiedRecords){this.modified=[];}for(var i=0,C=r.length;i<C;i++){r[i].join(this);}if(this.snapshot){this.data=this.snapshot;delete this.snapshot;}
 this.data.clear();this.data.addAll(r);this.totalLength=t;this.applySort();this.fireEvent("datachanged",this);}else {this.totalLength=Math.max(t,this.data.length+r.length);this.add(r);}
-this.fireEvent("load",this,r,A);if(A.callback){A.callback.call(A.scope||this,r,A,true);}},loadData:function(o,A){var r=this.reader.readRecords(o);this.loadRecords(r,{add:A},true);},getCount:function(){return this.data.length||0;},getTotalCount:function(){return this.totalLength||0;},getSortState:function(){return this.sortInfo;},applySort:function(){if(this.sortInfo&&!this.remoteSort){var s=this.sortInfo,f=s.field;var st=this.fields.get(f).sortType;var fn=function(r1,r2){var v1=st(r1.data[f]),v2=st(r2.data[f]);return v1>v2?1:(v1<v2?-1:0);};this.data.sort(s.direction,fn);if(this.snapshot&&this.snapshot!=this.data){this.snapshot.sort(s.direction,fn);}}},setDefaultSort:function(A,B){this.sortInfo={field:A,direction:B?B.toUpperCase():"ASC"};},sort:function(A,B){var f=this.fields.get(A);if(!B){if(this.sortInfo&&this.sortInfo.field==f.name){B=(this.sortToggle[f.name]||"ASC").toggle("ASC","DESC");}else {B=f.sortDir;}}
+this.fireEvent("load",this,r,A);if(A.callback){A.callback.call(A.scope||this,r,A,true);}},loadData:function(o,A){var r=this.reader.readRecords(o);this.loadRecords(r,{add:A},true);},getCount:function(){return this.data.length||0;},getTotalCount:function(){return this.totalLength||0;},getSortState:function(){return this.sortInfo;},applySort:function(){if(this.sortInfo&&!this.remoteSort){var s=this.sortInfo,f=s.field;var st=this.fields.get(f).sortType;var fn=function(r1,r2){var v1=st(r1.data[f]),v2=st(r2.data[f]);return v1>v2?1:(v1<v2?-1:0);};this.data.sort(s.direction,fn);if(this.snapshot&&this.snapshot!=this.data){this.snapshot.sort(s.direction,fn);}}},setDefaultSort:function(A,B){this.sortInfo={field:A,direction:B?B.toUpperCase():"ASC"};},sort:function(A,B){var f=this.fields.get(A);if(!B){this.sortToggle[f.name]=this.sortToggle[f.name]||f.sortDir;if(this.multiSort||(this.sortInfo&&this.sortInfo.field==f.name)){B=(this.sortToggle[f.name]||"ASC").toggle("ASC","DESC");}else {B=f.sortDir;}}
 this.sortToggle[f.name]=B;this.sortInfo={field:f.name,direction:B};if(!this.remoteSort){this.applySort();this.fireEvent("datachanged",this);}else {this.load(this.lastOptions);}},each:function(fn,A){this.data.each(fn,A);},getModifiedRecords:function(){return this.modified;},createFilterFn:function(A,B,C){if(!B.exec){B=String(B);if(B.length==0){return false;}
 B=new RegExp((C===true?'':'^')+Roo.escapeRe(B),"i");}return function(r){return B.test(r.data[A]);};},sum:function(A,B,C){var rs=this.data.items,v=0;B=B||0;C=(C||C===0)?C:rs.length-1;for(var i=B;i<=C;i++){v+=(rs[i].data[A]||0);}return v;},filter:function(A,B,C){var fn=this.createFilterFn(A,B,C);return fn?this.filterBy(fn):this.clearFilter();},filterBy:function(fn,A){this.snapshot=this.snapshot||this.data;this.data=this.queryBy(fn,A||this);this.fireEvent("datachanged",this);},query:function(A,B,C){var fn=this.createFilterFn(A,B,C);return fn?this.queryBy(fn):this.data.clone();},queryBy:function(fn,A){var B=this.snapshot||this.data;return B.filterBy(fn,A||this);},collect:function(A,B,C){var d=(C===true&&this.snapshot)?this.snapshot.items:this.data.items;var v,sv,r=[],l={};for(var i=0,D=d.length;i<D;i++){v=d[i].data[A];sv=String(v);if((B||!Roo.isEmpty(v))&&!l[sv]){l[sv]=true;r[r.length]=v;}}return r;},clearFilter:function(A){if(this.snapshot&&this.snapshot!=this.data){this.data=this.snapshot;delete this.snapshot;if(A!==true){this.fireEvent("datachanged",this);}}},afterEdit:function(A){if(this.modified.indexOf(A)==-1){this.modified.push(A);}
 this.fireEvent("update",this,A,Roo.data.Record.EDIT);},afterReject:function(A){this.modified.remove(A);this.fireEvent("update",this,A,Roo.data.Record.REJECT);},afterCommit:function(A){this.modified.remove(A);this.fireEvent("update",this,A,Roo.data.Record.COMMIT);},commitChanges:function(){var m=this.modified.slice(0);this.modified=[];for(var i=0,A=m.length;i<A;i++){m[i].commit();}},rejectChanges:function(){var m=this.modified.slice(0);this.modified=[];for(var i=0,A=m.length;i<A;i++){m[i].reject();}},onMetaChange:function(A,B,o){this.recordType=B;this.fields=B.prototype.fields;delete this.snapshot;this.sortInfo=A.sortInfo||this.sortInfo;this.modified=[];this.fireEvent('metachange',this,this.reader.meta);}});
@@ -626,7 +626,7 @@ A++;}}return null;},getSelections:function(){return this.selModel.getSelections(
 Roo.grid.AbstractGridView=function(){this.grid=null;this.events={"beforerowremoved":true,"beforerowsinserted":true,"beforerefresh":true,"rowremoved":true,"rowsinserted":true,"rowupdated":true,"refresh":true};Roo.grid.AbstractGridView.superclass.constructor.call(this);};Roo.extend(Roo.grid.AbstractGridView,Roo.util.Observable,{rowClass:"x-grid-row",cellClass:"x-grid-cell",tdClass:"x-grid-td",hdClass:"x-grid-hd",splitClass:"x-grid-hd-split",init:function(A){this.grid=A;var B=this.grid.getGridEl().id;this.colSelector="#"+B+" ."+this.cellClass+"-";this.tdSelector="#"+B+" ."+this.tdClass+"-";this.hdSelector="#"+B+" ."+this.hdClass+"-";this.splitSelector="#"+B+" ."+this.splitClass+"-";},getColumnRenderers:function(){var A=[];var cm=this.grid.colModel;var B=cm.getColumnCount();for(var i=0;i<B;i++){A[i]=cm.getRenderer(i);}return A;},getColumnIds:function(){var A=[];var cm=this.grid.colModel;var B=cm.getColumnCount();for(var i=0;i<B;i++){A[i]=cm.getColumnId(i);}return A;},getDataIndexes:function(){if(!this.indexMap){this.indexMap=this.buildIndexMap();}return this.indexMap.colToData;},getColumnIndexByDataIndex:function(A){if(!this.indexMap){this.indexMap=this.buildIndexMap();}return this.indexMap.dataToCol[A];},setCSSStyle:function(A,B,C){var D="#"+this.grid.id+" .x-grid-col-"+A;Roo.util.CSS.updateRule(D,B,C);},generateRules:function(cm){var A=[],B=this.grid.id+'-cssrules';Roo.util.CSS.removeStyleSheet(B);for(var i=0,C=cm.getColumnCount();i<C;i++){var D=cm.getColumnId(i);A.push(this.colSelector,D," {\n",cm.config[i].css,"}\n",this.tdSelector,D," {\n}\n",this.hdSelector,D," {\n}\n",this.splitSelector,D," {\n}\n");}return Roo.util.CSS.createStyleSheet(A.join(""),B);}});
 Roo.grid.HeaderDragZone=function(A,hd,B){this.grid=A;this.view=A.getView();this.ddGroup="gridHeader"+this.grid.getGridEl().id;Roo.grid.HeaderDragZone.superclass.constructor.call(this,hd);if(B){this.setHandleElId(Roo.id(hd));this.setOuterHandleElId(Roo.id(B));}
 this.scroll=false;};Roo.extend(Roo.grid.HeaderDragZone,Roo.dd.DragZone,{maxDragWidth:120,getDragData:function(e){var t=Roo.lib.Event.getTarget(e);var h=this.view.findHeaderCell(t);if(h){return {ddel:h.firstChild,header:h};}return false;},onInitDrag:function(e){this.view.headersDisabled=true;var A=this.dragData.ddel.cloneNode(true);A.id=Roo.id();A.style.width=Math.min(this.dragData.header.offsetWidth,this.maxDragWidth)+"px";this.proxy.update(A);return true;},afterValidDrop:function(){var v=this.view;setTimeout(function(){v.headersDisabled=false;},50);},afterInvalidDrop:function(){var v=this.view;setTimeout(function(){v.headersDisabled=false;},50);}});
-Roo.grid.HeaderDropZone=function(A,hd,B){this.grid=A;this.view=A.getView();this.proxyTop=Roo.DomHelper.append(document.body,{cls:"col-move-top",html:"&#160;"},true);this.proxyBottom=Roo.DomHelper.append(document.body,{cls:"col-move-bottom",html:"&#160;"},true);this.proxyTop.hide=this.proxyBottom.hide=function(){this.setLeftTop(-100,-100);this.setStyle("visibility","hidden");};this.ddGroup="gridHeader"+this.grid.getGridEl().id;Roo.grid.HeaderDropZone.superclass.constructor.call(this,A.getGridEl().dom);};Roo.extend(Roo.grid.HeaderDropZone,Roo.dd.DropZone,{proxyOffsets:[-4,-9],fly:Roo.Element.fly,getTargetFromEvent:function(e){var t=Roo.lib.Event.getTarget(e);var A=this.view.findCellIndex(t);if(A!==false){return this.view.getHeaderCell(A);}},nextVisible:function(h){var v=this.view,cm=this.grid.colModel;h=h.nextSibling;while(h){if(!cm.isHidden(v.getCellIndex(h))){return h;}
+Roo.grid.HeaderDropZone=function(A,hd,B){this.grid=A;this.view=A.getView();this.proxyTop=Roo.DomHelper.append(document.body,{cls:"col-move-top",html:"&#160;"},true);this.proxyBottom=Roo.DomHelper.append(document.body,{cls:"col-move-bottom",html:"&#160;"},true);this.proxyTop.hide=this.proxyBottom.hide=function(){this.setLeftTop(-100,-100);this.setStyle("visibility","hidden");};this.ddGroup="gridHeader"+this.grid.getGridEl().id;Roo.grid.HeaderDropZone.superclass.constructor.call(this,A.getGridEl().dom);};Roo.extend(Roo.grid.HeaderDropZone,Roo.dd.DropZone,{proxyOffsets:[-4,-9],fly:Roo.Element.fly,getTargetFromEvent:function(e){var t=Roo.lib.Event.getTarget(e);var A=this.view.findCellIndex(t);if(A!==false){return this.view.getHeaderCell(A);}return null;},nextVisible:function(h){var v=this.view,cm=this.grid.colModel;h=h.nextSibling;while(h){if(!cm.isHidden(v.getCellIndex(h))){return h;}
 h=h.nextSibling;}return null;},prevVisible:function(h){var v=this.view,cm=this.grid.colModel;h=h.prevSibling;while(h){if(!cm.isHidden(v.getCellIndex(h))){return h;}
 h=h.prevSibling;}return null;},positionIndicator:function(h,n,e){var x=Roo.lib.Event.getPageX(e);var r=Roo.lib.Dom.getRegion(n.firstChild);var px,pt,py=r.top+this.proxyOffsets[1];if((r.right-x)<=(r.right-r.left)/2){px=r.right+this.view.borderWidth;pt="after";}else {px=r.left;pt="before";}var A=this.view.getCellIndex(h);var B=this.view.getCellIndex(n);if(this.grid.colModel.isFixed(B)){return false;}var C=this.grid.colModel.isLocked(B);if(pt=="after"){B++;}if(A<B){B--;}if(A==B&&(C==this.grid.colModel.isLocked(A))){return false;}
 px+=this.proxyOffsets[0];this.proxyTop.setLeftTop(px,py);this.proxyTop.show();if(!this.bottomOffset){this.bottomOffset=this.view.mainHd.getHeight();}
@@ -661,10 +661,13 @@ rp.alt=L.join(" ");E+=rt.apply(rp);rp.cells=cb;D+=rt.apply(rp);}return [E,D];}:f
 rp.cells=F;if(this.getRowClass){L.push(this.getRowClass(r,G));}if(H){I={record:r,rowIndex:G,rowClass:''}
 this.grid.fireEvent('rowclass',this,I);L.push(I.rowClass);}
 rp.alt=L.join(" ");rp.cells=F.join("");E[E.length]=rt.apply(rp);rp.cells=cb.join("");D[D.length]=rt.apply(rp);}return [E.join(""),D.join("")];},renderBody:function(){var A=this.renderRows();var bt=this.templates.body;return [bt.apply({rows:A[0]}),bt.apply({rows:A[1]})];},refresh:function(A){this.fireEvent("beforerefresh",this);this.grid.stopEditing();var B=this.renderBody();this.lockedBody.update(B[0]);this.mainBody.update(B[1]);if(A===true){this.updateHeaders();this.updateColumns();this.updateSplitters();this.updateHeaderSortState();}
-this.syncRowHeights();this.layout();this.fireEvent("refresh",this);},handleColumnMove:function(cm,A,B){this.indexMap=null;var s=this.getScrollState();this.refresh(true);this.restoreScroll(s);this.afterMove(B);},afterMove:function(A){if(this.enableMoveAnim&&Roo.enableFx){this.fly(this.getHeaderCell(A).firstChild).highlight(this.hlColor);}},updateCell:function(dm,A,B){var C=this.getColumnIndexByDataIndex(B);if(typeof C=="undefined"){return;}var cm=this.grid.colModel;var D=this.getCell(A,C);var E=this.getCellText(A,C);var p={cellId:"x-grid-cell-"+A+"-"+C,id:cm.getColumnId(C),css:C==cm.getColumnCount()-1?"x-grid-col-last":""};var F=cm.getRenderer(C);var G=F(dm.getValueAt(A,B),p,A,C,dm);if(typeof G=="undefined"||G==="")G="&#160;";E.innerHTML=G;D.className=this.cellClass+" "+this.idToCssName(p.cellId)+" "+p.css;this.syncRowHeights(A,A);},calcColumnWidth:function(A,B){var C=0;if(this.grid.autoSizeHeaders){var h=this.getHeaderCellMeasure(A);C=Math.max(C,h.scrollWidth);}var tb,D;if(this.cm.isLocked(A)){tb=this.getLockedTable();D=A;}else {tb=this.getBodyTable();D=A-this.cm.getLockedCount();}if(tb&&tb.rows){var E=tb.rows;var F=Math.min(B||E.length,E.length);for(var i=0;i<F;i++){var G=E[i].childNodes[D].firstChild;C=Math.max(C,G.scrollWidth);}}return C+5;},autoSizeColumn:function(A,B,C){if(this.cm.isHidden(A)){return;}if(B){var D=this.cm.getColumnId(A);this.css.updateRule(this.colSelector+this.idToCssName(D),"width",this.grid.minColumnWidth+"px");if(this.grid.autoSizeHeaders){this.css.updateRule(this.hdSelector+this.idToCssName(D),"width",this.grid.minColumnWidth+"px");}}var E=this.calcColumnWidth(A);this.cm.setColumnWidth(A,Math.max(this.grid.minColumnWidth,E),C);if(!C){this.grid.fireEvent("columnresize",A,E);}},autoSizeColumns:function(){var cm=this.grid.colModel;var A=cm.getColumnCount();for(var i=0;i<A;i++){this.autoSizeColumn(i,true,true);}if(cm.getTotalWidth()<this.scroller.dom.clientWidth){this.fitColumns();}else {this.updateColumns();this.layout();}},fitColumns:function(A){var cm=this.grid.colModel;var B=cm.getColumnCount();var C=[];var D=0;var i,w;for(i=0;i<B;i++){if(!cm.isHidden(i)&&!cm.isFixed(i)){w=cm.getColumnWidth(i);C.push(i);C.push(w);D+=w;}}var E=Math.min(this.scroller.dom.clientWidth,this.el.getWidth());if(A){E-=17;}var F=(E-cm.getTotalWidth())/D;while(C.length){w=C.pop();i=C.pop();cm.setColumnWidth(i,Math.floor(w+w*F),true);}
-this.updateColumns();this.layout();},onRowSelect:function(A){var B=this.getRowComposite(A);B.addClass("x-grid-row-selected");},onRowDeselect:function(A){var B=this.getRowComposite(A);B.removeClass("x-grid-row-selected");},onCellSelect:function(A,B){var C=this.getCell(A,B);if(C){Roo.fly(C).addClass("x-grid-cell-selected");}},onCellDeselect:function(A,B){var C=this.getCell(A,B);if(C){Roo.fly(C).removeClass("x-grid-cell-selected");}},updateHeaderSortState:function(){var A=this.ds.getSortState();if(!A){return;}
-this.sortState=A;var B=this.cm.findColumnIndex(A.field);if(B!=-1){var C=A.direction;var sc=this.sortClasses;var D=this.el.select(this.headerSelector).removeClass(sc);D.item(B).addClass(sc[C=="DESC"?1:0]);}},handleHeaderClick:function(g,A){if(this.headersDisabled){return;}var dm=g.dataSource,cm=g.colModel;if(!cm.isSortable(A)){return;}
-g.stopEditing();dm.sort(cm.getDataIndex(A));},destroy:function(){if(this.colMenu){this.colMenu.removeAll();Roo.menu.MenuMgr.unregister(this.colMenu);this.colMenu.getEl().remove();delete this.colMenu;}if(this.hmenu){this.hmenu.removeAll();Roo.menu.MenuMgr.unregister(this.hmenu);this.hmenu.getEl().remove();delete this.hmenu;}if(this.grid.enableColumnMove){var A=Roo.dd.DDM.ids['gridHeader'+this.grid.getGridEl().id];if(A){for(var dd in A){if(!A[dd].config.isTarget&&A[dd].dragElId){var B=A[dd].dragElId;A[dd].unreg();Roo.get(B).remove();}else if(A[dd].config.isTarget){A[dd].proxyTop.remove();A[dd].proxyBottom.remove();A[dd].unreg();}if(Roo.dd.DDM.locationCache[dd]){delete Roo.dd.DDM.locationCache[dd];}}delete Roo.dd.DDM.ids['gridHeader'+this.grid.getGridEl().id];}}
+this.syncRowHeights();this.layout();this.fireEvent("refresh",this);},handleColumnMove:function(cm,A,B){this.indexMap=null;var s=this.getScrollState();this.refresh(true);this.restoreScroll(s);this.afterMove(B);},afterMove:function(A){if(this.enableMoveAnim&&Roo.enableFx){this.fly(this.getHeaderCell(A).firstChild).highlight(this.hlColor);}if(this.grid.dataSource.multiSort){var dm=this.grid.dataSource;var cm=this.grid.colModel;var so=[];for(var i=0;i<cm.config.length;i++){if((typeof(dm.sortToggle[cm.config[i].dataIndex])=='undefined')){continue;}
+so.push(cm.config[i].dataIndex);};dm.sortOrder=so;dm.load(dm.lastOptions);}},updateCell:function(dm,A,B){var C=this.getColumnIndexByDataIndex(B);if(typeof C=="undefined"){return;}var cm=this.grid.colModel;var D=this.getCell(A,C);var E=this.getCellText(A,C);var p={cellId:"x-grid-cell-"+A+"-"+C,id:cm.getColumnId(C),css:C==cm.getColumnCount()-1?"x-grid-col-last":""};var F=cm.getRenderer(C);var G=F(dm.getValueAt(A,B),p,A,C,dm);if(typeof G=="undefined"||G==="")G="&#160;";E.innerHTML=G;D.className=this.cellClass+" "+this.idToCssName(p.cellId)+" "+p.css;this.syncRowHeights(A,A);},calcColumnWidth:function(A,B){var C=0;if(this.grid.autoSizeHeaders){var h=this.getHeaderCellMeasure(A);C=Math.max(C,h.scrollWidth);}var tb,D;if(this.cm.isLocked(A)){tb=this.getLockedTable();D=A;}else {tb=this.getBodyTable();D=A-this.cm.getLockedCount();}if(tb&&tb.rows){var E=tb.rows;var F=Math.min(B||E.length,E.length);for(var i=0;i<F;i++){var G=E[i].childNodes[D].firstChild;C=Math.max(C,G.scrollWidth);}}return C+5;},autoSizeColumn:function(A,B,C){if(this.cm.isHidden(A)){return;}if(B){var D=this.cm.getColumnId(A);this.css.updateRule(this.colSelector+this.idToCssName(D),"width",this.grid.minColumnWidth+"px");if(this.grid.autoSizeHeaders){this.css.updateRule(this.hdSelector+this.idToCssName(D),"width",this.grid.minColumnWidth+"px");}}var E=this.calcColumnWidth(A);this.cm.setColumnWidth(A,Math.max(this.grid.minColumnWidth,E),C);if(!C){this.grid.fireEvent("columnresize",A,E);}},autoSizeColumns:function(){var cm=this.grid.colModel;var A=cm.getColumnCount();for(var i=0;i<A;i++){this.autoSizeColumn(i,true,true);}if(cm.getTotalWidth()<this.scroller.dom.clientWidth){this.fitColumns();}else {this.updateColumns();this.layout();}},fitColumns:function(A){var cm=this.grid.colModel;var B=cm.getColumnCount();var C=[];var D=0;var i,w;for(i=0;i<B;i++){if(!cm.isHidden(i)&&!cm.isFixed(i)){w=cm.getColumnWidth(i);C.push(i);C.push(w);D+=w;}}var E=Math.min(this.scroller.dom.clientWidth,this.el.getWidth());if(A){E-=17;}var F=(E-cm.getTotalWidth())/D;while(C.length){w=C.pop();i=C.pop();cm.setColumnWidth(i,Math.floor(w+w*F),true);}
+this.updateColumns();this.layout();},onRowSelect:function(A){var B=this.getRowComposite(A);B.addClass("x-grid-row-selected");},onRowDeselect:function(A){var B=this.getRowComposite(A);B.removeClass("x-grid-row-selected");},onCellSelect:function(A,B){var C=this.getCell(A,B);if(C){Roo.fly(C).addClass("x-grid-cell-selected");}},onCellDeselect:function(A,B){var C=this.getCell(A,B);if(C){Roo.fly(C).removeClass("x-grid-cell-selected");}},updateHeaderSortState:function(){var A={};if(!this.ds.multiSort){var B=this.ds.getSortState();if(!B){return;}
+A[B.field]=B.direction;this.sortState=B;}else {A=this.ds.sortToggle;}var sc=this.sortClasses;var C=this.el.select(this.headerSelector).removeClass(sc);for(var f in A){var D=this.cm.findColumnIndex(f);if(D!=-1){var E=A[f];C.item(D).addClass(sc[E=="DESC"?1:0]);}}},handleHeaderClick:function(g,A){if(this.headersDisabled){return;}var dm=g.dataSource,cm=g.colModel;if(!cm.isSortable(A)){return;}
+g.stopEditing();if(dm.multiSort){var so=[];for(var i=0;i<cm.config.length;i++){if((typeof(dm.sortToggle[cm.config[i].dataIndex])=='undefined')&&(A!=i)){continue;}
+so.push(cm.config[i].dataIndex);};dm.sortOrder=so;}
+dm.sort(cm.getDataIndex(A));},destroy:function(){if(this.colMenu){this.colMenu.removeAll();Roo.menu.MenuMgr.unregister(this.colMenu);this.colMenu.getEl().remove();delete this.colMenu;}if(this.hmenu){this.hmenu.removeAll();Roo.menu.MenuMgr.unregister(this.hmenu);this.hmenu.getEl().remove();delete this.hmenu;}if(this.grid.enableColumnMove){var A=Roo.dd.DDM.ids['gridHeader'+this.grid.getGridEl().id];if(A){for(var dd in A){if(!A[dd].config.isTarget&&A[dd].dragElId){var B=A[dd].dragElId;A[dd].unreg();Roo.get(B).remove();}else if(A[dd].config.isTarget){A[dd].proxyTop.remove();A[dd].proxyBottom.remove();A[dd].unreg();}if(Roo.dd.DDM.locationCache[dd]){delete Roo.dd.DDM.locationCache[dd];}}delete Roo.dd.DDM.ids['gridHeader'+this.grid.getGridEl().id];}}
 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id)+'-cssrules');this.bind(null,null);Roo.EventManager.removeResizeListener(this.onWindowResize,this);},handleLockChange:function(){this.refresh(true);},onDenyColumnLock:function(){},onDenyColumnHide:function(){},handleHdMenuClick:function(A){var B=this.hdCtxIndex;var cm=this.cm,ds=this.ds;switch(A.id){case "asc":ds.sort(cm.getDataIndex(B),"ASC");break;case "desc":ds.sort(cm.getDataIndex(B),"DESC");break;case "lock":var lc=cm.getLockedCount();if(cm.getColumnCount(true)<=lc+1){this.onDenyColumnLock();return;}if(lc!=B){cm.setLocked(B,true,true);cm.moveColumn(B,lc);this.grid.fireEvent("columnmove",B,lc);}else {cm.setLocked(B,true);}break;case "unlock":var lc=cm.getLockedCount();if((lc-1)!=B){cm.setLocked(B,false,true);cm.moveColumn(B,lc-1);this.grid.fireEvent("columnmove",B,lc-1);}else {cm.setLocked(B,false);}break;default:B=cm.getIndexById(A.id.substr(4));if(B!=-1){if(A.checked&&cm.getColumnCount(true)<=1){this.onDenyColumnHide();return false;}
 cm.setHidden(B,A.checked);}}return true;},beforeColMenuShow:function(){var cm=this.cm,A=cm.getColumnCount();this.colMenu.removeAll();for(var i=0;i<A;i++){this.colMenu.add(new Roo.menu.CheckItem({id:"col-"+cm.getColumnId(i),text:cm.getColumnHeader(i),checked:!cm.isHidden(i),hideOnClick:false}));}},handleHdCtx:function(g,A,e){e.stopEvent();var hd=this.getHeaderCell(A);this.hdCtxIndex=A;var ms=this.hmenu.items,cm=this.cm;ms.get("asc").setDisabled(!cm.isSortable(A));ms.get("desc").setDisabled(!cm.isSortable(A));if(this.grid.enableColLock!==false){ms.get("lock").setDisabled(cm.isLocked(A));ms.get("unlock").setDisabled(!cm.isLocked(A));}
 this.hmenu.show(hd,"tl-bl");},handleHdOver:function(e){var hd=this.findHeaderCell(e.getTarget());if(hd&&!this.headersDisabled){if(this.grid.colModel.isSortable(this.getCellIndex(hd))){this.fly(hd).addClass("x-grid-hd-over");}}},handleHdOut:function(e){var hd=this.findHeaderCell(e.getTarget());if(hd){this.fly(hd).removeClass("x-grid-hd-over");}},handleSplitDblClick:function(e,t){var i=this.getCellIndex(t);if(this.grid.enableColumnResize!==false&&this.cm.isResizable(i)&&!this.cm.isFixed(i)){this.autoSizeColumn(i,true);this.layout();}},render:function(){var cm=this.cm;var A=cm.getColumnCount();if(this.grid.monitorWindowResize===true){Roo.EventManager.onWindowResize(this.onWindowResize,this,true);}var B=this.renderHeaders();var C=this.templates.body.apply({rows:""});var D=this.templates.master.apply({lockedBody:C,body:C,lockedHeader:B[0],header:B[1]});this.grid.getGridEl().dom.innerHTML=D;this.initElements();this.el.on("scroll",function(){this.el.dom.scrollTop=0;},this);this.scroller.on("scroll",this.handleScroll,this);this.lockedBody.on("mousewheel",this.handleWheel,this);this.mainBody.on("mousewheel",this.handleWheel,this);this.mainHd.on("mouseover",this.handleHdOver,this);this.mainHd.on("mouseout",this.handleHdOut,this);this.mainHd.on("dblclick",this.handleSplitDblClick,this,{delegate:"."+this.splitClass});this.lockedHd.on("mouseover",this.handleHdOver,this);this.lockedHd.on("mouseout",this.handleHdOut,this);this.lockedHd.on("dblclick",this.handleSplitDblClick,this,{delegate:"."+this.splitClass});if(this.grid.enableColumnResize!==false&&Roo.grid.SplitDragZone){new Roo.grid.SplitDragZone(this.grid,this.lockedHd.dom,this.mainHd.dom);}