+ * Purge the least recently used records in the prefetch if the purgeCount
+ * has been exceeded.
+ */
+ purgeRecords: function() {
+ var me = this,
+ prefetchCount = me.prefetchData.getCount(),
+ purgeCount = me.purgePageCount * me.pageSize,
+ numRecordsToPurge = prefetchCount - purgeCount - 1,
+ i = 0;
+
+ for (; i <= numRecordsToPurge; i++) {
+ me.prefetchData.removeAt(0);
+ }
+ },
+
+ /**
+ * Determines if the range has already been satisfied in the prefetchData.
+ * @private
+ * @param {Number} start The start index
+ * @param {Number} end The end index in the range
+ */
+ rangeSatisfied: function(start, end) {
+ var me = this,
+ i = start,
+ satisfied = true;
+
+ for (; i < end; i++) {
+ if (!me.prefetchData.getByKey(i)) {
+ satisfied = false;
+ //<debug>
+ if (end - i > me.pageSize) {
+ Ext.Error.raise("A single page prefetch could never satisfy this request.");
+ }
+ //</debug>
+ break;
+ }
+ }
+ return satisfied;
+ },
+
+ /**
+ * Determines the page from a record index
+ * @param {Number} index The record index
+ * @return {Number} The page the record belongs to
+ */
+ getPageFromRecordIndex: function(index) {
+ return Math.floor(index / this.pageSize) + 1;
+ },
+
+ /**
+ * Handles a guaranteed range being loaded
+ * @private
+ */
+ onGuaranteedRange: function() {
+ var me = this,
+ totalCount = me.getTotalCount(),
+ start = me.requestStart,
+ end = ((totalCount - 1) < me.requestEnd) ? totalCount - 1 : me.requestEnd,
+ range = [],
+ record,
+ i = start;
+
+ //<debug>
+ if (start > end) {
+ Ext.Error.raise("Start (" + start + ") was greater than end (" + end + ")");
+ }
+ //</debug>
+
+ if (start !== me.guaranteedStart && end !== me.guaranteedEnd) {
+ me.guaranteedStart = start;
+ me.guaranteedEnd = end;
+
+ for (; i <= end; i++) {
+ record = me.prefetchData.getByKey(i);
+ //<debug>
+ if (!record) {
+ Ext.Error.raise("Record was not found and store said it was guaranteed");
+ }
+ //</debug>
+ range.push(record);
+ }
+ me.fireEvent('guaranteedrange', range, start, end);
+ if (me.cb) {
+ me.cb.call(me.scope || me, range);
+ }
+ }
+
+ me.unmask();
+ },
+
+ // hack to support loadmask
+ mask: function() {
+ this.masked = true;
+ this.fireEvent('beforeload');
+ },
+
+ // hack to support loadmask
+ unmask: function() {
+ if (this.masked) {
+ this.fireEvent('load');
+ }
+ },
+
+ /**
+ * Returns the number of pending requests out.
+ */
+ hasPendingRequests: function() {
+ return this.pendingRequests.length;
+ },
+
+
+ // wait until all requests finish, until guaranteeing the range.
+ onWaitForGuarantee: function() {
+ if (!this.hasPendingRequests()) {
+ this.onGuaranteedRange();
+ }
+ },
+
+ /**
+ * Guarantee a specific range, this will load the store with a range (that
+ * must be the pageSize or smaller) and take care of any loading that may
+ * be necessary.
+ */
+ guaranteeRange: function(start, end, cb, scope) {
+ //<debug>
+ if (start && end) {
+ if (end - start > this.pageSize) {
+ Ext.Error.raise({
+ start: start,
+ end: end,
+ pageSize: this.pageSize,
+ msg: "Requested a bigger range than the specified pageSize"
+ });
+ }
+ }
+ //</debug>
+
+ end = (end > this.totalCount) ? this.totalCount - 1 : end;
+
+ var me = this,
+ i = start,
+ prefetchData = me.prefetchData,
+ range = [],
+ startLoaded = !!prefetchData.getByKey(start),
+ endLoaded = !!prefetchData.getByKey(end),
+ startPage = me.getPageFromRecordIndex(start),
+ endPage = me.getPageFromRecordIndex(end);
+
+ me.cb = cb;
+ me.scope = scope;
+
+ me.requestStart = start;
+ me.requestEnd = end;
+ // neither beginning or end are loaded
+ if (!startLoaded || !endLoaded) {
+ // same page, lets load it
+ if (startPage === endPage) {
+ me.mask();
+ me.prefetchPage(startPage, {
+ //blocking: true,
+ callback: me.onWaitForGuarantee,
+ scope: me
+ });
+ // need to load two pages
+ } else {
+ me.mask();
+ me.prefetchPage(startPage, {
+ //blocking: true,
+ callback: me.onWaitForGuarantee,
+ scope: me
+ });
+ me.prefetchPage(endPage, {
+ //blocking: true,
+ callback: me.onWaitForGuarantee,
+ scope: me
+ });
+ }
+ // Request was already satisfied via the prefetch
+ } else {
+ me.onGuaranteedRange();
+ }
+ },
+
+ // because prefetchData is stored by index
+ // this invalidates all of the prefetchedData
+ sort: function() {
+ var me = this,
+ prefetchData = me.prefetchData,
+ sorters,
+ start,
+ end,
+ range;
+
+ if (me.buffered) {
+ if (me.remoteSort) {
+ prefetchData.clear();
+ me.callParent(arguments);
+ } else {
+ sorters = me.getSorters();
+ start = me.guaranteedStart;
+ end = me.guaranteedEnd;
+
+ if (sorters.length) {
+ prefetchData.sort(sorters);
+ range = prefetchData.getRange();
+ prefetchData.clear();
+ me.cacheRecords(range);
+ delete me.guaranteedStart;
+ delete me.guaranteedEnd;
+ me.guaranteeRange(start, end);
+ }
+ me.callParent(arguments);
+ }
+ } else {
+ me.callParent(arguments);
+ }