/*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ import { Observable } from 'rxjs/Observable'; import { Observer } from 'rxjs/Observer'; import { Event, Emitter } from 'vs/base/common/event'; import { TPromise } from 'vs/base/common/winjs.base'; import * as types from 'vs/base/common/types'; import { IDisposableDataProvider } from 'sql/base/browser/ui/table/interfaces'; export interface IFindPosition { col: number; row: number; } function defaultSort(args: Slick.OnSortEventArgs, data: Array): Array { let field = args.sortCol.field; let sign = args.sortAsc ? 1 : -1; return data.sort((a, b) => (a[field] === b[field] ? 0 : (a[field] > b[field] ? 1 : -1)) * sign); } export class TableDataView implements IDisposableDataProvider { private _data: Array; private _findArray: Array; private _findObs: Observable; private _findIndex: number; private _onRowCountChange = new Emitter(); get onRowCountChange(): Event { return this._onRowCountChange.event; } private _onFindCountChange = new Emitter(); get onFindCountChange(): Event { return this._onFindCountChange.event; } constructor( data?: Array, private _findFn?: (val: T, exp: string) => Array, private _sortFn?: (args: Slick.OnSortEventArgs, data: Array) => Array ) { if (data) { this._data = data; } else { this._data = new Array(); } if (!_sortFn) { this._sortFn = defaultSort; } } sort(args: Slick.OnSortEventArgs) { this._data = this._sortFn(args, this._data); } getLength(): number { return this._data.length; } getItem(index: number): T { return this._data[index]; } push(items: Array); push(item: T); push(input: T | Array) { if (Array.isArray(input)) { this._data.push(...input); } else { this._data.push(input); } this._onRowCountChange.fire(); } clear() { this._data = new Array(); this._onRowCountChange.fire(); } find(exp: string, maxMatches: number = 0): Thenable { if (!this._findFn) { return TPromise.wrapError(new Error('no find function provided')); } this._findArray = new Array(); this._findIndex = 0; this._onFindCountChange.fire(this._findArray.length); if (exp) { this._findObs = Observable.create((observer: Observer) => { for (let i = 0; i < this._data.length; i++) { let item = this._data[i]; let result = this._findFn(item, exp); if (result) { result.forEach(pos => { let index = { col: pos, row: i }; this._findArray.push(index); observer.next(index); this._onFindCountChange.fire(this._findArray.length); }); if (maxMatches > 0 && this._findArray.length > maxMatches) { break; } } } }); return this._findObs.take(1).toPromise().then(() => { return this._findArray[this._findIndex]; }); } else { return TPromise.wrapError(new Error('no expression')); } } clearFind() { this._findArray = new Array(); this._findIndex = 0; this._findObs = undefined; this._onFindCountChange.fire(this._findArray.length); } findNext(): Thenable { if (this._findArray && this._findArray.length !== 0) { if (this._findIndex === this._findArray.length - 1) { this._findIndex = 0; } else { ++this._findIndex; } return TPromise.as(this._findArray[this._findIndex]); } else { return TPromise.wrapError(new Error('no search running')); } } findPrevious(): Thenable { if (this._findArray && this._findArray.length !== 0) { if (this._findIndex === 0) { this._findIndex = this._findArray.length - 1; } else { --this._findIndex; } return TPromise.as(this._findArray[this._findIndex]); } else { return TPromise.wrapError(new Error('no search running')); } } get currentFindPosition(): Thenable { if (this._findArray && this._findArray.length !== 0) { return TPromise.as(this._findArray[this._findIndex]); } else { return TPromise.wrapError(new Error('no search running')); } } /* 1 indexed */ get findPosition(): number { return types.isUndefinedOrNull(this._findIndex) ? 0 : this._findIndex + 1; } get findCount(): number { return types.isUndefinedOrNull(this._findArray) ? 0 : this._findArray.length; } dispose() { this._data = undefined; this._findArray = undefined; this._findObs = undefined; } }