Upgrade to ExtJS 4.0.0 - Released 04/26/2011
[extjs.git] / src / view / AbstractView.js
1 /**
2  * @class Ext.view.AbstractView
3  * @extends Ext.Component
4  * This is an abstract superclass and should not be used directly. Please see {@link Ext.view.View}.
5  */
6 Ext.define('Ext.view.AbstractView', {
7     extend: 'Ext.Component',
8     alternateClassName: 'Ext.view.AbstractView',
9     requires: [
10         'Ext.LoadMask',
11         'Ext.data.StoreManager',
12         'Ext.CompositeElementLite',
13         'Ext.DomQuery',
14         'Ext.selection.DataViewModel'
15     ],
16     
17     inheritableStatics: {
18         getRecord: function(node) {
19             return this.getBoundView(node).getRecord(node);
20         },
21         
22         getBoundView: function(node) {
23             return Ext.getCmp(node.boundView);
24         }
25     },
26     
27     /**
28      * @cfg {String/Array/Ext.XTemplate} tpl
29      * @required
30      * The HTML fragment or an array of fragments that will make up the template used by this DataView.  This should
31      * be specified in the same format expected by the constructor of {@link Ext.XTemplate}.
32      */
33     /**
34      * @cfg {Ext.data.Store} store
35      * @required
36      * The {@link Ext.data.Store} to bind this DataView to.
37      */
38
39     /**
40      * @cfg {String} itemSelector
41      * @required
42      * <b>This is a required setting</b>. A simple CSS selector (e.g. <tt>div.some-class</tt> or
43      * <tt>span:first-child</tt>) that will be used to determine what nodes this DataView will be
44      * working with. The itemSelector is used to map DOM nodes to records. As such, there should
45      * only be one root level element that matches the selector for each record.
46      */
47     
48     /**
49      * @cfg {String} itemCls
50      * Specifies the class to be assigned to each element in the view when used in conjunction with the
51      * {@link #itemTpl} configuration.
52      */
53     itemCls: Ext.baseCSSPrefix + 'dataview-item',
54     
55     /**
56      * @cfg {String/Array/Ext.XTemplate} itemTpl
57      * The inner portion of the item template to be rendered. Follows an XTemplate
58      * structure and will be placed inside of a tpl.
59      */
60
61     /**
62      * @cfg {String} overItemCls
63      * A CSS class to apply to each item in the view on mouseover (defaults to undefined). 
64      * Ensure {@link #trackOver} is set to `true` to make use of this.
65      */
66
67     /**
68      * @cfg {String} loadingText
69      * A string to display during data load operations (defaults to undefined).  If specified, this text will be
70      * displayed in a loading div and the view's contents will be cleared while loading, otherwise the view's
71      * contents will continue to display normally until the new data is loaded and the contents are replaced.
72      */
73     loadingText: 'Loading...',
74     
75     /**
76      * @cfg {String} loadingCls
77      * The CSS class to apply to the loading message element (defaults to Ext.LoadMask.prototype.msgCls "x-mask-loading")
78      */
79     
80     /**
81      * @cfg {Boolean} loadingUseMsg
82      * Whether or not to use the loading message.
83      * @private
84      */
85     loadingUseMsg: true,
86     
87
88     /**
89      * @cfg {Number} loadingHeight
90      * If specified, gives an explicit height for the data view when it is showing the {@link #loadingText},
91      * if that is specified. This is useful to prevent the view's height from collapsing to zero when the
92      * loading mask is applied and there are no other contents in the data view. Defaults to undefined.
93      */
94
95     /**
96      * @cfg {String} selectedItemCls
97      * A CSS class to apply to each selected item in the view (defaults to 'x-view-selected').
98      */
99     selectedItemCls: Ext.baseCSSPrefix + 'item-selected',
100
101     /**
102      * @cfg {String} emptyText
103      * The text to display in the view when there is no data to display (defaults to '').
104      * Note that when using local data the emptyText will not be displayed unless you set
105      * the {@link #deferEmptyText} option to false.
106      */
107     emptyText: "",
108
109     /**
110      * @cfg {Boolean} deferEmptyText True to defer emptyText being applied until the store's first load
111      */
112     deferEmptyText: true,
113
114     /**
115      * @cfg {Boolean} trackOver True to enable mouseenter and mouseleave events
116      */
117     trackOver: false,
118
119     /**
120      * @cfg {Boolean} blockRefresh Set this to true to ignore datachanged events on the bound store. This is useful if
121      * you wish to provide custom transition animations via a plugin (defaults to false)
122      */
123     blockRefresh: false,
124
125     /**
126      * @cfg {Boolean} disableSelection <p><tt>true</tt> to disable selection within the DataView. Defaults to <tt>false</tt>.
127      * This configuration will lock the selection model that the DataView uses.</p>
128      */
129
130
131     //private
132     last: false,
133     
134     triggerEvent: 'itemclick',
135     triggerCtEvent: 'containerclick',
136     
137     addCmpEvents: function() {
138         
139     },
140
141     // private
142     initComponent : function(){
143         var me = this,
144             isDef = Ext.isDefined,
145             itemTpl = me.itemTpl,
146             memberFn = {};
147             
148         if (itemTpl) {
149             if (Ext.isArray(itemTpl)) {
150                 // string array
151                 itemTpl = itemTpl.join('');
152             } else if (Ext.isObject(itemTpl)) {
153                 // tpl instance
154                 memberFn = Ext.apply(memberFn, itemTpl.initialConfig);
155                 itemTpl = itemTpl.html;
156             }
157             
158             if (!me.itemSelector) {
159                 me.itemSelector = '.' + me.itemCls;
160             }
161             
162             itemTpl = Ext.String.format('<tpl for="."><div class="{0}">{1}</div></tpl>', me.itemCls, itemTpl);
163             me.tpl = Ext.create('Ext.XTemplate', itemTpl, memberFn);
164         }
165
166         //<debug>
167         if (!isDef(me.tpl) || !isDef(me.itemSelector)) {
168             Ext.Error.raise({
169                 sourceClass: 'Ext.view.View',
170                 tpl: me.tpl,
171                 itemSelector: me.itemSelector,
172                 msg: "DataView requires both tpl and itemSelector configurations to be defined."
173             });
174         }
175         //</debug>
176
177         me.callParent();
178         if(Ext.isString(me.tpl) || Ext.isArray(me.tpl)){
179             me.tpl = Ext.create('Ext.XTemplate', me.tpl);
180         }
181
182         //<debug>
183         // backwards compat alias for overClass/selectedClass
184         // TODO: Consider support for overCls generation Ext.Component config
185         if (isDef(me.overCls) || isDef(me.overClass)) {
186             if (Ext.isDefined(Ext.global.console)) {
187                 Ext.global.console.warn('Ext.view.View: Using the deprecated overCls or overClass configuration. Use overItemCls instead.');
188             }
189             me.overItemCls = me.overCls || me.overClass;
190             delete me.overCls;
191             delete me.overClass;
192         }
193
194         if (me.overItemCls) {
195             me.trackOver = true;
196         }
197         
198         if (isDef(me.selectedCls) || isDef(me.selectedClass)) {
199             if (Ext.isDefined(Ext.global.console)) {
200                 Ext.global.console.warn('Ext.view.View: Using the deprecated selectedCls or selectedClass configuration. Use selectedItemCls instead.');
201             }
202             me.selectedItemCls = me.selectedCls || me.selectedClass;
203             delete me.selectedCls;
204             delete me.selectedClass;
205         }
206         //</debug>
207         
208         me.addEvents(
209             /**
210              * @event beforerefresh
211              * Fires before the view is refreshed
212              * @param {Ext.view.View} this The DataView object
213              */
214             'beforerefresh',
215             /**
216              * @event refresh
217              * Fires when the view is refreshed
218              * @param {Ext.view.View} this The DataView object
219              */
220             'refresh',
221             /**
222              * @event itemupdate
223              * Fires when the node associated with an individual record is updated
224              * @param {Ext.data.Model} record The model instance
225              * @param {Number} index The index of the record/node
226              * @param {HTMLElement} node The node that has just been updated
227              */
228             'itemupdate',
229             /**
230              * @event itemadd
231              * Fires when the nodes associated with an recordset have been added to the underlying store
232              * @param {Array[Ext.data.Model]} records The model instance
233              * @param {Number} index The index at which the set of record/nodes starts
234              * @param {Array[HTMLElement]} node The node that has just been updated
235              */
236             'itemadd',
237             /**
238              * @event itemremove
239              * Fires when the node associated with an individual record is removed
240              * @param {Ext.data.Model} record The model instance
241              * @param {Number} index The index of the record/node
242              */
243             'itemremove'
244         );
245
246         me.addCmpEvents();
247
248         if (me.store) {
249             me.store = Ext.data.StoreManager.lookup(me.store);
250         }
251         me.all = new Ext.CompositeElementLite();
252         me.getSelectionModel().bindComponent(me);
253     },
254
255     onRender: function() {
256         var me = this,
257             loadingText = me.loadingText,
258             loadingHeight = me.loadingHeight,
259             undef;
260
261         me.callParent(arguments);
262         if (loadingText) {
263             
264             // Attach the LoadMask to a *Component* so that it can be sensitive to resizing during long loads.
265             // If this DataView is floating, then mask this DataView.
266             // Otherwise, mask its owning Container (or this, if there *is* no owning Container).
267             // LoadMask captures the element upon render.
268             me.loadMask = Ext.create('Ext.LoadMask', me.floating ? me : me.ownerCt || me, {
269                 msg: loadingText,
270                 msgCls: me.loadingCls,
271                 useMsg: me.loadingUseMsg,
272                 listeners: {
273                     beforeshow: function() {
274                         me.getTargetEl().update('');
275                         me.getSelectionModel().deselectAll();
276                         me.all.clear();
277                         if (loadingHeight) {
278                             me.setCalculatedSize(undef, loadingHeight);
279                         }
280                     },
281                     hide: function() {
282                         if (loadingHeight) {
283                             me.setHeight(me.height);
284                         }
285                     }
286                 }
287             });
288         }
289     },
290
291     getSelectionModel: function(){
292         var me = this,
293             mode = 'SINGLE';
294
295         if (!me.selModel) {
296             me.selModel = {};
297         }
298
299         if (me.simpleSelect) {
300             mode = 'SIMPLE';
301         } else if (me.multiSelect) {
302             mode = 'MULTI';
303         }
304
305         Ext.applyIf(me.selModel, {
306             allowDeselect: me.allowDeselect,
307             mode: mode
308         });
309
310         if (!me.selModel.events) {
311             me.selModel = Ext.create('Ext.selection.DataViewModel', me.selModel);
312         }
313
314         if (!me.selModel.hasRelaySetup) {
315             me.relayEvents(me.selModel, ['selectionchange', 'beforeselect', 'select', 'deselect']);
316             me.selModel.hasRelaySetup = true;
317         }
318
319         // lock the selection model if user
320         // has disabled selection
321         if (me.disableSelection) {
322             me.selModel.locked = true;
323         }
324
325         return me.selModel;
326     },
327
328     /**
329      * Refreshes the view by reloading the data from the store and re-rendering the template.
330      */
331     refresh: function() {
332         var me = this,
333             el,
334             records;
335             
336         if (!me.rendered) {
337             return;
338         }
339         
340         me.fireEvent('beforerefresh', me);
341         el = me.getTargetEl();
342         records = me.store.getRange();
343
344         el.update('');
345         if (records.length < 1) {
346             if (!me.deferEmptyText || me.hasSkippedEmptyText) {
347                 el.update(me.emptyText);
348             }
349             me.all.clear();
350         } else {
351             me.tpl.overwrite(el, me.collectData(records, 0));
352             me.all.fill(Ext.query(me.getItemSelector(), el.dom));
353             me.updateIndexes(0);
354         }
355         
356         me.selModel.refresh();
357         me.hasSkippedEmptyText = true;
358         me.fireEvent('refresh', me);
359     },
360
361     /**
362      * Function which can be overridden to provide custom formatting for each Record that is used by this
363      * DataView's {@link #tpl template} to render each node.
364      * @param {Array/Object} data The raw data object that was used to create the Record.
365      * @param {Number} recordIndex the index number of the Record being prepared for rendering.
366      * @param {Record} record The Record being prepared for rendering.
367      * @return {Array/Object} The formatted data in a format expected by the internal {@link #tpl template}'s overwrite() method.
368      * (either an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'}))
369      */
370     prepareData: function(data, index, record) {
371         if (record) {    
372             Ext.apply(data, record.getAssociatedData());            
373         }
374         return data;
375     },
376     
377     /**
378      * <p>Function which can be overridden which returns the data object passed to this
379      * DataView's {@link #tpl template} to render the whole DataView.</p>
380      * <p>This is usually an Array of data objects, each element of which is processed by an
381      * {@link Ext.XTemplate XTemplate} which uses <tt>'&lt;tpl for="."&gt;'</tt> to iterate over its supplied
382      * data object as an Array. However, <i>named</i> properties may be placed into the data object to
383      * provide non-repeating data such as headings, totals etc.</p>
384      * @param {Array} records An Array of {@link Ext.data.Model}s to be rendered into the DataView.
385      * @param {Number} startIndex the index number of the Record being prepared for rendering.
386      * @return {Array} An Array of data objects to be processed by a repeating XTemplate. May also
387      * contain <i>named</i> properties.
388      */
389     collectData : function(records, startIndex){
390         var r = [],
391             i = 0,
392             len = records.length;
393
394         for(; i < len; i++){
395             r[r.length] = this.prepareData(records[i].data, startIndex + i, records[i]);
396         }
397
398         return r;
399     },
400
401     // private
402     bufferRender : function(records, index){
403         var div = document.createElement('div');
404         this.tpl.overwrite(div, this.collectData(records, index));
405         return Ext.query(this.getItemSelector(), div);
406     },
407
408     // private
409     onUpdate : function(ds, record){
410         var me = this,
411             index = me.store.indexOf(record),
412             original,
413             node;
414
415         if (index > -1){
416             original = me.all.elements[index];
417             node = me.bufferRender([record], index)[0];
418
419             me.all.replaceElement(index, node, true);
420             me.updateIndexes(index, index);
421
422             // Maintain selection after update
423             // TODO: Move to approriate event handler.
424             me.selModel.refresh();
425             me.fireEvent('itemupdate', record, index, node);
426         }
427
428     },
429
430     // private
431     onAdd : function(ds, records, index) {
432         var me = this,
433             nodes;
434             
435         if (me.all.getCount() === 0) {
436             me.refresh();
437             return;
438         }
439         
440         nodes = me.bufferRender(records, index);
441         me.doAdd(nodes, records, index);
442
443         me.selModel.refresh();
444         me.updateIndexes(index);
445         me.fireEvent('itemadd', records, index, nodes);
446     },
447
448     doAdd: function(nodes, records, index) {
449         var n, a = this.all.elements;
450         if (index < this.all.getCount()) {
451             n = this.all.item(index).insertSibling(nodes, 'before', true);
452             a.splice.apply(a, [index, 0].concat(nodes));
453         } 
454         else {
455             n = this.all.last().insertSibling(nodes, 'after', true);
456             a.push.apply(a, nodes);
457         }    
458     },
459     
460     // private
461     onRemove : function(ds, record, index) {
462         var me = this;
463         
464         me.doRemove(record, index);
465         me.updateIndexes(index);
466         if (me.store.getCount() === 0){
467             me.refresh();
468         }
469         me.fireEvent('itemremove', record, index);
470     },
471     
472     doRemove: function(record, index) {
473         this.all.removeElement(index, true);
474     },
475
476     /**
477      * Refreshes an individual node's data from the store.
478      * @param {Number} index The item's data index in the store
479      */
480     refreshNode : function(index){
481         this.onUpdate(this.store, this.store.getAt(index));
482     },
483
484     // private
485     updateIndexes : function(startIndex, endIndex) {
486         var ns = this.all.elements,
487             records = this.store.getRange();
488         startIndex = startIndex || 0;
489         endIndex = endIndex || ((endIndex === 0) ? 0 : (ns.length - 1));
490         for(var i = startIndex; i <= endIndex; i++){
491             ns[i].viewIndex = i;
492             ns[i].viewRecordId = records[i].internalId;
493             if (!ns[i].boundView) {
494                 ns[i].boundView = this.id;
495             }
496         }
497     },
498
499     /**
500      * Returns the store associated with this DataView.
501      * @return {Ext.data.Store} The store
502      */
503     getStore : function(){
504         return this.store;
505     },
506
507     /**
508      * Changes the data store bound to this view and refreshes it.
509      * @param {Store} store The store to bind to this view
510      */
511     bindStore : function(store, initial) {
512         var me = this;
513         
514         if (!initial && me.store) {
515             if (store !== me.store && me.store.autoDestroy) {
516                 me.store.destroy();
517             } 
518             else {
519                 me.mun(me.store, {
520                     scope: me,
521                     datachanged: me.onDataChanged,
522                     add: me.onAdd,
523                     remove: me.onRemove,
524                     update: me.onUpdate,
525                     clear: me.refresh
526                 });
527             }
528             if (!store) {
529                 if (me.loadMask) {
530                     me.loadMask.bindStore(null);
531                 }
532                 me.store = null;
533             }
534         }
535         if (store) {
536             store = Ext.data.StoreManager.lookup(store);
537             me.mon(store, {
538                 scope: me,
539                 datachanged: me.onDataChanged,
540                 add: me.onAdd,
541                 remove: me.onRemove,
542                 update: me.onUpdate,
543                 clear: me.refresh
544             });
545             if (me.loadMask) {
546                 me.loadMask.bindStore(store);
547             }
548         }
549         
550         me.store = store;
551         // Bind the store to our selection model
552         me.getSelectionModel().bind(store);
553         
554         if (store) {
555             me.refresh(true);
556         }
557     },
558
559     /**
560      * @private
561      * Calls this.refresh if this.blockRefresh is not true
562      */
563     onDataChanged: function() {
564         if (this.blockRefresh !== true) {
565             this.refresh.apply(this, arguments);
566         }
567     },
568
569     /**
570      * Returns the template node the passed child belongs to, or null if it doesn't belong to one.
571      * @param {HTMLElement} node
572      * @return {HTMLElement} The template node
573      */
574     findItemByChild: function(node){
575         return Ext.fly(node).findParent(this.getItemSelector(), this.getTargetEl());
576     },
577     
578     /**
579      * Returns the template node by the Ext.EventObject or null if it is not found.
580      * @param {Ext.EventObject} e
581      */
582     findTargetByEvent: function(e) {
583         return e.getTarget(this.getItemSelector(), this.getTargetEl());
584     },
585
586
587     /**
588      * Gets the currently selected nodes.
589      * @return {Array} An array of HTMLElements
590      */
591     getSelectedNodes: function(){
592         var nodes   = [],
593             records = this.selModel.getSelection(),
594             ln = records.length,
595             i  = 0;
596
597         for (; i < ln; i++) {
598             nodes.push(this.getNode(records[i]));
599         }
600
601         return nodes;
602     },
603
604     /**
605      * Gets an array of the records from an array of nodes
606      * @param {Array} nodes The nodes to evaluate
607      * @return {Array} records The {@link Ext.data.Model} objects
608      */
609     getRecords: function(nodes) {
610         var records = [],
611             i = 0,
612             len = nodes.length,
613             data = this.store.data;
614
615         for (; i < len; i++) {
616             records[records.length] = data.getByKey(nodes[i].viewRecordId);
617         }
618
619         return records;
620     },
621
622     /**
623      * Gets a record from a node
624      * @param {Element/HTMLElement} node The node to evaluate
625      * 
626      * @return {Record} record The {@link Ext.data.Model} object
627      */
628     getRecord: function(node){
629         return this.store.data.getByKey(Ext.getDom(node).viewRecordId);
630     },
631     
632
633     /**
634      * Returns true if the passed node is selected, else false.
635      * @param {HTMLElement/Number/Ext.data.Model} node The node, node index or record to check
636      * @return {Boolean} True if selected, else false
637      */
638     isSelected : function(node) {
639         // TODO: El/Idx/Record
640         var r = this.getRecord(node);
641         return this.selModel.isSelected(r);
642     },
643     
644     /**
645      * Selects a record instance by record instance or index.
646      * @param {Ext.data.Model/Index} records An array of records or an index
647      * @param {Boolean} keepExisting
648      * @param {Boolean} suppressEvent Set to false to not fire a select event
649      */
650     select: function(records, keepExisting, suppressEvent) {
651         this.selModel.select(records, keepExisting, suppressEvent);
652     },
653
654     /**
655      * Deselects a record instance by record instance or index.
656      * @param {Ext.data.Model/Index} records An array of records or an index
657      * @param {Boolean} suppressEvent Set to false to not fire a deselect event
658      */
659     deselect: function(records, suppressEvent) {
660         this.selModel.deselect(records, suppressEvent);
661     },
662
663     /**
664      * Gets a template node.
665      * @param {HTMLElement/String/Number/Ext.data.Model} nodeInfo An HTMLElement template node, index of a template node,
666      * the id of a template node or the record associated with the node.
667      * @return {HTMLElement} The node or null if it wasn't found
668      */
669     getNode : function(nodeInfo) {
670         if (Ext.isString(nodeInfo)) {
671             return document.getElementById(nodeInfo);
672         } else if (Ext.isNumber(nodeInfo)) {
673             return this.all.elements[nodeInfo];
674         } else if (nodeInfo instanceof Ext.data.Model) {
675             return this.getNodeByRecord(nodeInfo);
676         }
677         return nodeInfo;
678     },
679     
680     /**
681      * @private
682      */
683     getNodeByRecord: function(record) {
684         var ns = this.all.elements,
685             ln = ns.length,
686             i = 0;
687         
688         for (; i < ln; i++) {
689             if (ns[i].viewRecordId === record.internalId) {
690                 return ns[i];
691             }
692         }
693         
694         return null;
695     },
696     
697     /**
698      * Gets a range nodes.
699      * @param {Number} start (optional) The index of the first node in the range
700      * @param {Number} end (optional) The index of the last node in the range
701      * @return {Array} An array of nodes
702      */
703     getNodes: function(start, end) {
704         var ns = this.all.elements,
705             nodes = [],
706             i;
707
708         start = start || 0;
709         end = !Ext.isDefined(end) ? Math.max(ns.length - 1, 0) : end;
710         if (start <= end) {
711             for (i = start; i <= end && ns[i]; i++) {
712                 nodes.push(ns[i]);
713             }
714         } else {
715             for (i = start; i >= end && ns[i]; i--) {
716                 nodes.push(ns[i]);
717             }
718         }
719         return nodes;
720     },
721
722     /**
723      * Finds the index of the passed node.
724      * @param {HTMLElement/String/Number/Record} nodeInfo An HTMLElement template node, index of a template node, the id of a template node
725      * or a record associated with a node.
726      * @return {Number} The index of the node or -1
727      */
728     indexOf: function(node) {
729         node = this.getNode(node);
730         if (Ext.isNumber(node.viewIndex)) {
731             return node.viewIndex;
732         }
733         return this.all.indexOf(node);
734     },
735
736     onDestroy : function() {
737         var me = this;
738         
739         me.all.clear();
740         me.callParent();
741         me.bindStore(null);
742         me.selModel.destroy();
743     },
744
745     // invoked by the selection model to maintain visual UI cues
746     onItemSelect: function(record) {
747         var node = this.getNode(record);
748         Ext.fly(node).addCls(this.selectedItemCls);
749     },
750
751     // invoked by the selection model to maintain visual UI cues
752     onItemDeselect: function(record) {
753         var node = this.getNode(record);
754         Ext.fly(node).removeCls(this.selectedItemCls);
755     },
756     
757     getItemSelector: function() {
758         return this.itemSelector;
759     }
760 }, function() {
761     // all of this information is available directly
762     // from the SelectionModel itself, the only added methods
763     // to DataView regarding selection will perform some transformation/lookup
764     // between HTMLElement/Nodes to records and vice versa.
765     Ext.deprecate('extjs', '4.0', function() {
766         Ext.view.AbstractView.override({
767             /**
768              * @cfg {Boolean} multiSelect
769              * True to allow selection of more than one item at a time, false to allow selection of only a single item
770              * at a time or no selection at all, depending on the value of {@link #singleSelect} (defaults to false).
771              */
772             /**
773              * @cfg {Boolean} singleSelect
774              * True to allow selection of exactly one item at a time, false to allow no selection at all (defaults to false).
775              * Note that if {@link #multiSelect} = true, this value will be ignored.
776              */
777             /**
778              * @cfg {Boolean} simpleSelect
779              * True to enable multiselection by clicking on multiple items without requiring the user to hold Shift or Ctrl,
780              * false to force the user to hold Ctrl or Shift to select more than on item (defaults to false).
781              */
782             
783             /**
784              * Gets the number of selected nodes.
785              * @return {Number} The node count
786              */
787             getSelectionCount : function(){
788                 console.warn("DataView: getSelectionCount will be removed, please interact with the Ext.selection.DataViewModel");
789                 return this.selModel.getSelection().length;
790             },
791         
792             /**
793              * Gets an array of the selected records
794              * @return {Array} An array of {@link Ext.data.Model} objects
795              */
796             getSelectedRecords : function(){
797                 console.warn("DataView: getSelectedRecords will be removed, please interact with the Ext.selection.DataViewModel");
798                 return this.selModel.getSelection();
799             },
800     
801             select: function(records, keepExisting, supressEvents) {
802                 console.warn("DataView: select will be removed, please access select through a DataView's SelectionModel, ie: view.getSelectionModel().select()");
803                 var sm = this.getSelectionModel();
804                 return sm.select.apply(sm, arguments);
805             },
806             
807             clearSelections: function() {
808                 console.warn("DataView: clearSelections will be removed, please access deselectAll through DataView's SelectionModel, ie: view.getSelectionModel().deselectAll()");
809                 var sm = this.getSelectionModel();
810                 return sm.deselectAll();
811             }
812         });    
813     });
814 });