directory_contents.js revision f8ee788a64d60abd8f2d742a5fdedde054ecd910
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)'use strict';
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
84e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * Scanner of the entries.
94e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * @constructor
104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) */
114e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)function ContentScanner() {
124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  this.cancelled_ = false;
134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
154e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)/**
164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * Starts to scan the entries. For example, starts to read the entries in a
174e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * directory, or starts to search with some query on a file system.
184e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * Derived classes must override this method.
194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) *
204e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * @param {function(Array.<Entry>)} entriesCallback Called when some chunk of
214e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) *     entries are read. This can be called a couple of times until the
224e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) *     completion.
234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * @param {function()} successCallback Called when the scan is completed
244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) *     successfully.
254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * @param {function(FileError)} errorCallback Called an error occurs.
264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) */
274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)ContentScanner.prototype.scan = function(
284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    entriesCallback, successCallback, errorCallback) {
294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)};
304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)/**
324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * Request cancelling of the running scan. When the cancelling is done,
334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * an error will be reported from errorCallback passed to scan().
344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) */
354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)ContentScanner.prototype.cancel = function() {
364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  this.cancelled_ = true;
374e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)};
384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)/**
404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * Scanner of the entries in a directory.
414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * @param {DirectoryEntry} entry The directory to be read.
424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * @constructor
434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * @extends {ContentScanner}
444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) */
454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)function DirectoryContentScanner(entry) {
464e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  ContentScanner.call(this);
474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  this.entry_ = entry;
484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)/**
514e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * Extends ContentScanner.
524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) */
534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)DirectoryContentScanner.prototype.__proto__ = ContentScanner.prototype;
544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)/**
564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * Starts to read the entries in the directory.
574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * @override
584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) */
594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)DirectoryContentScanner.prototype.scan = function(
604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    entriesCallback, successCallback, errorCallback) {
61a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!this.entry_ || util.isFakeEntry(this.entry_)) {
624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    // If entry is not specified or a fake, we cannot read it.
635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    errorCallback(util.createDOMError(
645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        util.FileError.INVALID_MODIFICATION_ERR));
654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return;
664e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
684e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  metrics.startInterval('DirectoryScan');
694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  var reader = this.entry_.createReader();
704e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  var readEntries = function() {
714e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    reader.readEntries(
724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        function(entries) {
734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          if (this.cancelled_) {
745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            errorCallback(util.createDOMError(util.FileError.ABORT_ERR));
754e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)            return;
764e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          }
774e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
784e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          if (entries.length === 0) {
794e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)            // All entries are read.
804e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)            metrics.recordInterval('DirectoryScan');
814e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)            successCallback();
824e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)            return;
834e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          }
844e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
854e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          entriesCallback(entries);
864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          readEntries();
874e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        }.bind(this),
884e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        errorCallback);
894e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }.bind(this);
904e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  readEntries();
914e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)};
924e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)/**
944e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * Scanner of the entries for the search results on Drive File System.
954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * @param {string} query The query string.
964e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * @constructor
974e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * @extends {ContentScanner}
984e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) */
994e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)function DriveSearchContentScanner(query) {
1004e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  ContentScanner.call(this);
1014e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  this.query_ = query;
1024e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
1034e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1044e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)/**
1054e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * Extends ContentScanner.
1064e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) */
1074e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)DriveSearchContentScanner.prototype.__proto__ = ContentScanner.prototype;
1084e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)/**
1104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * Delay in milliseconds to be used for drive search scan, in order to reduce
1114e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * the number of server requests while user is typing the query.
1124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * @type {number}
1134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * @private
1144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * @const
1154e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) */
1164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)DriveSearchContentScanner.SCAN_DELAY_ = 200;
1174e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1184e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)/**
1194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * Maximum number of results which is shown on the search.
1204e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * @type {number}
1214e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * @private
1224e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * @const
1234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) */
1244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)DriveSearchContentScanner.MAX_RESULTS_ = 100;
1254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)/**
1274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * Starts to search on Drive File System.
1284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * @override
1294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) */
1304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)DriveSearchContentScanner.prototype.scan = function(
1314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    entriesCallback, successCallback, errorCallback) {
1324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  var numReadEntries = 0;
1334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  var readEntries = function(nextFeed) {
1344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    chrome.fileBrowserPrivate.searchDrive(
1354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        {query: this.query_, nextFeed: nextFeed},
1364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        function(entries, nextFeed) {
1374e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          if (this.cancelled_) {
1385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            errorCallback(util.createDOMError(util.FileError.ABORT_ERR));
1394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)            return;
1404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          }
1414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          // TODO(tbarzic): Improve error handling.
1434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          if (!entries) {
1444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)            console.error('Drive search encountered an error.');
1455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            errorCallback(util.createDOMError(
1465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                util.FileError.INVALID_MODIFICATION_ERR));
1474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)            return;
1484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          }
1494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          var numRemainingEntries =
1514e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)              DriveSearchContentScanner.MAX_RESULTS_ - numReadEntries;
1524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          if (entries.length >= numRemainingEntries) {
1534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)            // The limit is hit, so quit the scan here.
1544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)            entries = entries.slice(0, numRemainingEntries);
1554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)            nextFeed = '';
1564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          }
1574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          numReadEntries += entries.length;
1594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          if (entries.length > 0)
1604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)            entriesCallback(entries);
1614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          if (nextFeed === '')
1634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)            successCallback();
1644e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          else
1654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)            readEntries(nextFeed);
1664e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        }.bind(this));
1674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }.bind(this);
1684e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Let's give another search a chance to cancel us before we begin.
1704e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  setTimeout(
1714e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      function() {
1724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        // Check cancelled state before read the entries.
1734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        if (this.cancelled_) {
1745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          errorCallback(util.createDOMError(util.FileError.ABORT_ERR));
1754e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          return;
1764e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        }
1774e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        readEntries('');
1784e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      }.bind(this),
1794e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      DriveSearchContentScanner.SCAN_DELAY_);
1804e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)};
1814e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1824e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)/**
1834e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * Scanner of the entries of the file name search on the directory tree, whose
1844e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * root is entry.
1854e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * @param {DirectoryEntry} entry The root of the search target directory tree.
1864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * @param {string} query The query of the search.
1874e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * @constructor
1884e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * @extends {ContentScanner}
1894e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) */
1904e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)function LocalSearchContentScanner(entry, query) {
1914e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  ContentScanner.call(this);
1924e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  this.entry_ = entry;
1934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  this.query_ = query.toLowerCase();
1944e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
1954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1964e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)/**
197c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch * Extends ContentScanner.
1984e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) */
1994e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)LocalSearchContentScanner.prototype.__proto__ = ContentScanner.prototype;
2004e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2014e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)/**
2024e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * Starts the file name search.
2034e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * @override
2044e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) */
2054e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)LocalSearchContentScanner.prototype.scan = function(
2064e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    entriesCallback, successCallback, errorCallback) {
2074e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  var numRunningTasks = 0;
2084e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  var error = null;
2094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  var maybeRunCallback = function() {
2104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    if (numRunningTasks === 0) {
2114e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      if (this.cancelled_)
2125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        errorCallback(util.createDOMError(util.FileError.ABORT_ERR));
2134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      else if (error)
2144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        errorCallback(error);
2154e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      else
2164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        successCallback();
2174e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    }
2184e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }.bind(this);
2194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2204e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  var processEntry = function(entry) {
2214e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    numRunningTasks++;
2224e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    var onError = function(fileError) {
2234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      if (!error)
2244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        error = fileError;
2254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      numRunningTasks--;
2264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      maybeRunCallback();
2274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    };
2284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    var onSuccess = function(entries) {
2304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      if (this.cancelled_ || error || entries.length === 0) {
2314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        numRunningTasks--;
2324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        maybeRunCallback();
2334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        return;
2344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      }
2354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      // Filters by the query, and if found, run entriesCallback.
2374e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      var foundEntries = entries.filter(function(entry) {
2384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        return entry.name.toLowerCase().indexOf(this.query_) >= 0;
2394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      }.bind(this));
2404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      if (foundEntries.length > 0)
2414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        entriesCallback(foundEntries);
2424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      // Start to process sub directories.
2444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      for (var i = 0; i < entries.length; i++) {
2454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        if (entries[i].isDirectory)
2464e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          processEntry(entries[i]);
2474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      }
2484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      // Read remaining entries.
2504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      reader.readEntries(onSuccess, onError);
2514e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    }.bind(this);
2524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    var reader = entry.createReader();
2544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    reader.readEntries(onSuccess, onError);
2554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }.bind(this);
2564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  processEntry(this.entry_);
2584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)};
2594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)/**
2614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * Scanner of the entries for the metadata search on Drive File System.
2624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * @param {DriveMetadataSearchContentScanner.SearchType} searchType The option
2634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) *     of the search.
2644e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * @constructor
2654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * @extends {ContentScanner}
2664e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) */
2675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)function DriveMetadataSearchContentScanner(searchType) {
2684e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  ContentScanner.call(this);
2694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  this.searchType_ = searchType;
2704e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
2714e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)/**
2734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * Extends ContentScanner.
2744e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) */
2754e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)DriveMetadataSearchContentScanner.prototype.__proto__ =
2764e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    ContentScanner.prototype;
2774e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2784e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)/**
2794e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * The search types on the Drive File System.
2804e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * @enum {string}
2814e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) */
2824e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)DriveMetadataSearchContentScanner.SearchType = Object.freeze({
2834e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  SEARCH_ALL: 'ALL',
2844e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  SEARCH_SHARED_WITH_ME: 'SHARED_WITH_ME',
2854e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  SEARCH_RECENT_FILES: 'EXCLUDE_DIRECTORIES',
2864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  SEARCH_OFFLINE: 'OFFLINE'
2874e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)});
2884e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2894e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)/**
2904e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * Starts to metadata-search on Drive File System.
2914e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * @override
2924e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) */
2934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)DriveMetadataSearchContentScanner.prototype.scan = function(
2944e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    entriesCallback, successCallback, errorCallback) {
2954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  chrome.fileBrowserPrivate.searchDriveMetadata(
2965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      {query: '', types: this.searchType_, maxResults: 500},
2974e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      function(results) {
2984e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        if (this.cancelled_) {
2995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          errorCallback(util.createDOMError(util.FileError.ABORT_ERR));
3004e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          return;
3014e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        }
3024e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
3034e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        if (!results) {
3044e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          console.error('Drive search encountered an error.');
3055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          errorCallback(util.createDOMError(
3065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              util.FileError.INVALID_MODIFICATION_ERR));
3074e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          return;
3084e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        }
3094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
3104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        var entries = results.map(function(result) { return result.entry; });
3114e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        if (entries.length > 0)
3124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          entriesCallback(entries);
3134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        successCallback();
3144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      }.bind(this));
3154e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)};
3164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
3174e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)/**
318c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * This class manages filters and determines a file should be shown or not.
319c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * When filters are changed, a 'changed' event is fired.
320c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) *
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {MetadataCache} metadataCache Metadata cache service.
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {boolean} showHidden If files starting with '.' are shown.
3232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @constructor
324c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * @extends {cr.EventTarget}
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
326c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)function FileFilter(metadataCache, showHidden) {
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /**
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   * @type {MetadataCache}
329c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)   * @private
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   */
331c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  this.metadataCache_ = metadataCache;
3324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /**
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   * @type Object.<string, Function>
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   * @private
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   */
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.filters_ = {};
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.setFilterHidden(!showHidden);
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Do not show entries marked as 'deleted'.
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.addFilter('deleted', function(entry) {
342c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    var internal = this.metadataCache_.getCached(entry, 'internal');
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return !(internal && internal.deleted);
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }.bind(this));
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
347c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)/*
348c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * FileFilter extends cr.EventTarget.
349c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) */
350c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)FileFilter.prototype = {__proto__: cr.EventTarget.prototype};
351c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {string} name Filter identifier.
3542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {function(Entry)} callback A filter — a function receiving an Entry,
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *     and returning bool.
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
357c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)FileFilter.prototype.addFilter = function(name, callback) {
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.filters_[name] = callback;
359c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  cr.dispatchSimpleEvent(this, 'changed');
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {string} name Filter identifier.
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
365c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)FileFilter.prototype.removeFilter = function(name) {
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  delete this.filters_[name];
367c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  cr.dispatchSimpleEvent(this, 'changed');
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
3712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {boolean} value If do not show hidden files.
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
373c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)FileFilter.prototype.setFilterHidden = function(value) {
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (value) {
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    this.addFilter(
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        'hidden',
377c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        function(entry) { return entry.name.substr(0, 1) !== '.'; }
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    );
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    this.removeFilter('hidden');
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @return {boolean} If the files with names starting with "." are not shown.
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
387c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)FileFilter.prototype.isFilterHiddenOn = function() {
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return 'hidden' in this.filters_;
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {Entry} entry File entry.
3932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @return {boolean} True if the file should be shown, false otherwise.
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
395c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)FileFilter.prototype.filter = function(entry) {
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (var name in this.filters_) {
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!this.filters_[name](entry))
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
403c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)/**
404c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * A context of DirectoryContents.
405c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * TODO(yoshiki): remove this. crbug.com/224869.
406c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) *
407c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * @param {FileFilter} fileFilter The file-filter context.
408c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * @param {MetadataCache} metadataCache Metadata cache service.
409c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * @constructor
410c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) */
411c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)function FileListContext(fileFilter, metadataCache) {
412c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  /**
413c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)   * @type {cr.ui.ArrayDataModel}
414c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)   */
415a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  this.fileList = new cr.ui.ArrayDataModel([]);
4164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
417c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  /**
418c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)   * @type {MetadataCache}
419c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)   */
420c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  this.metadataCache = metadataCache;
421c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
422c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  /**
423c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)   * @type {FileFilter}
424c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)   */
425c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  this.fileFilter = fileFilter;
426c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * This class is responsible for scanning directory (or search results),
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * and filling the fileList. Different descendants handle various types of
4312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * directory contents shown: basic directory, drive search results, local search
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * results.
4334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * TODO(hidehiko): Remove EventTarget from this.
4344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) *
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {FileListContext} context The file list context.
4364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * @param {boolean} isSearch True for search directory contents, otherwise
4374e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) *     false.
4384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * @param {DirectoryEntry} directoryEntry The entry of the current directory.
4394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * @param {function():ContentScanner} scannerFactory The factory to create
4404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) *     ContentScanner instance.
4412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @constructor
4422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @extends {cr.EventTarget}
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
4445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)function DirectoryContents(context,
4455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           isSearch,
4465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           directoryEntry,
4474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                           scannerFactory) {
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.context_ = context;
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.fileList_ = context.fileList;
4504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
4514e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  this.isSearch_ = isSearch;
4524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  this.directoryEntry_ = directoryEntry;
4534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
4544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  this.scannerFactory_ = scannerFactory;
4554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  this.scanner_ = null;
456cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  this.processNewEntriesQueue_ = new AsyncUtil.Queue();
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.scanCancelled_ = false;
458f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
459f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  this.lastSpaceInMetadataCache_ = 0;
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
4632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * DirectoryContents extends cr.EventTarget.
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DirectoryContents.prototype.__proto__ = cr.EventTarget.prototype;
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Create the copy of the object, but without scan started.
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @return {DirectoryContents} Object copy.
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DirectoryContents.prototype.clone = function() {
4724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return new DirectoryContents(
4735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      this.context_,
4745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      this.isSearch_,
4755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      this.directoryEntry_,
4765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      this.scannerFactory_);
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
480f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * Disposes the reserved metadata cache.
481f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) */
482f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)DirectoryContents.prototype.dispose = function() {
483f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  this.context_.metadataCache.resizeBy(-this.lastSpaceInMetadataCache_);
484f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)};
485f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
486f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)/**
487f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * Make a space for current directory size in the metadata cache.
488f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) *
489f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * @param {number} size The cache size to be set.
490f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * @private
491f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) */
492f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)DirectoryContents.prototype.makeSpaceInMetadataCache_ = function(size) {
493f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  this.context_.metadataCache.resizeBy(size - this.lastSpaceInMetadataCache_);
494f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  this.lastSpaceInMetadataCache_ = size;
495f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)};
496f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
497f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)/**
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Use a given fileList instead of the fileList from the context.
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {Array|cr.ui.ArrayDataModel} fileList The new file list.
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DirectoryContents.prototype.setFileList = function(fileList) {
5025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (fileList instanceof cr.ui.ArrayDataModel)
5035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    this.fileList_ = fileList;
5045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  else
5055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    this.fileList_ = new cr.ui.ArrayDataModel(fileList);
506f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  this.makeSpaceInMetadataCache_(this.fileList_.length);
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Use the filelist from the context and replace its contents with the entries
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * from the current fileList.
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DirectoryContents.prototype.replaceContextFileList = function() {
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (this.context_.fileList !== this.fileList_) {
5155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    var spliceArgs = this.fileList_.slice();
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    var fileList = this.context_.fileList;
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    spliceArgs.unshift(0, fileList.length);
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    fileList.splice.apply(fileList, spliceArgs);
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    this.fileList_ = fileList;
520f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    this.makeSpaceInMetadataCache_(this.fileList_.length);
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @return {boolean} If the scan is active.
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DirectoryContents.prototype.isScanning = function() {
528cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return this.scanner_ || this.processNewEntriesQueue_.isRunning();
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
5322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @return {boolean} True if search results (drive or local).
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DirectoryContents.prototype.isSearch = function() {
5354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return this.isSearch_;
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @return {DirectoryEntry} A DirectoryEntry for current directory. In case of
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *     search -- the top directory from which search is run.
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DirectoryContents.prototype.getDirectoryEntry = function() {
5434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return this.directoryEntry_;
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Start directory scan/search operation. Either 'scan-completed' or
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 'scan-failed' event will be fired upon completion.
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DirectoryContents.prototype.scan = function() {
551effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  /**
552effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch   * Invoked when the scanning is completed successfully.
553effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch   * @this {DirectoryContents}
554effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch   */
555effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  function completionCallback() {
556effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    this.onScanFinished_();
557effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    this.onScanCompleted_();
558effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
559effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
560effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  /**
561effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch   * Invoked when the scanning is finished but is not completed due to error.
562effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch   * @this {DirectoryContents}
563effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch   */
564effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  function errorCallback() {
565effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    this.onScanFinished_();
566effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    this.onScanError_();
567effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
568effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
5694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // TODO(hidehiko,mtomasz): this scan method must be called at most once.
5704e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Remove such a limitation.
5714e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  this.scanner_ = this.scannerFactory_();
5724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  this.scanner_.scan(this.onNewEntries_.bind(this),
573effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                     completionCallback.bind(this),
574effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                     errorCallback.bind(this));
5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
5784e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * Cancels the running scan.
5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DirectoryContents.prototype.cancelScan = function() {
581c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (this.scanCancelled_)
582c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.scanCancelled_ = true;
5844e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (this.scanner_)
5854e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    this.scanner_.cancel();
5864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
587effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  this.onScanFinished_();
588effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
589cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  this.processNewEntriesQueue_.cancel();
5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cr.dispatchSimpleEvent(this, 'scan-cancelled');
5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)/**
594effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch * Called when the scanning by scanner_ is done, even when the scanning is
595effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch * succeeded or failed. This is called before completion (or error) callback.
596effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch *
5974e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * @private
5984e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) */
599effb81e5f8246d0db0270817048dc992db66e9fbBen MurdochDirectoryContents.prototype.onScanFinished_ = function() {
6004e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  this.scanner_ = null;
601effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
602cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  this.processNewEntriesQueue_.run(function(callback) {
603effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    // TODO(yoshiki): Here we should fire the update event of changed
604effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    // items. Currently we have a method this.fileList_.updateIndex() to
605effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    // fire an event, but this method takes only 1 argument and invokes sort
606effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    // one by one. It is obviously time wasting. Instead, we call sort
607effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    // directory.
608effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    // In future, we should implement a good method like updateIndexes and
609effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    // use it here.
610effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    var status = this.fileList_.sortStatus;
611effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    if (status)
612effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      this.fileList_.sort(status.field, status.direction);
613effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
614effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    callback();
615effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }.bind(this));
616effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch};
617effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
618effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch/**
619effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch * Called when the scanning by scanner_ is succeeded.
620effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch * @private
621effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch */
622effb81e5f8246d0db0270817048dc992db66e9fbBen MurdochDirectoryContents.prototype.onScanCompleted_ = function() {
6234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (this.scanCancelled_)
6244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return;
6254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
626cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  this.processNewEntriesQueue_.run(function(callback) {
6274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    // Call callback first, so isScanning() returns false in the event handlers.
6284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    callback();
629effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
6304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    cr.dispatchSimpleEvent(this, 'scan-completed');
6314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }.bind(this));
6324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)};
6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Called in case scan has failed. Should send the event.
6364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * @private
6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
6384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)DirectoryContents.prototype.onScanError_ = function() {
6394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (this.scanCancelled_)
6404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return;
6414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
642cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  this.processNewEntriesQueue_.run(function(callback) {
6434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    // Call callback first, so isScanning() returns false in the event handlers.
6444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    callback();
6454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    cr.dispatchSimpleEvent(this, 'scan-failed');
6464e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }.bind(this));
6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
6504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * Called when some chunk of entries are read by scanner.
6514e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * @param {Array.<Entry>} entries The list of the scanned entries.
6524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * @private
6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
6544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)DirectoryContents.prototype.onNewEntries_ = function(entries) {
6554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (this.scanCancelled_)
6564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return;
6574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
6584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  var entriesFiltered = [].filter.call(
6594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      entries, this.context_.fileFilter.filter.bind(this.context_.fileFilter));
6604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
661010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // Caching URL to reduce a number of calls of toURL in sort.
662010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // This is a temporary solution. We need to fix a root cause of slow toURL.
663010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // See crbug.com/370908 for detail.
664010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  entriesFiltered.forEach(function(entry) { entry.cachedUrl = entry.toURL(); });
665010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
66646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (entriesFiltered.length === 0)
66746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    return;
66846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
669f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Enlarge the cache size into the new filelist size.
670f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  var newListSize = this.fileList_.length + entriesFiltered.length;
671f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  this.makeSpaceInMetadataCache_(newListSize);
6725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
673cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  this.processNewEntriesQueue_.run(function(callbackOuter) {
674f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    var finish = function() {
675f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      // Update the filelist without waiting the metadata.
676f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      this.fileList_.push.apply(this.fileList_, entriesFiltered);
677f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      cr.dispatchSimpleEvent(this, 'scan-updated');
678f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
679f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      callbackOuter();
680f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    }.bind(this);
681cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // Because the prefetchMetadata can be slow, throttling by splitting entries
682cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // into smaller chunks to reduce UI latency.
683cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // TODO(hidehiko,mtomasz): This should be handled in MetadataCache.
684cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    var MAX_CHUNK_SIZE = 25;
685cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    var prefetchMetadataQueue = new AsyncUtil.ConcurrentQueue(4);
686cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    for (var i = 0; i < entriesFiltered.length; i += MAX_CHUNK_SIZE) {
687cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      if (prefetchMetadataQueue.isCancelled())
688cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        break;
689cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
690cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      var chunk = entriesFiltered.slice(i, i + MAX_CHUNK_SIZE);
691cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      prefetchMetadataQueue.run(function(chunk, callbackInner) {
692cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        this.prefetchMetadata(chunk, function() {
693cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          if (!prefetchMetadataQueue.isCancelled()) {
694cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)            if (this.scanCancelled_)
695cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)              prefetchMetadataQueue.cancel();
696cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          }
6974e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
698cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          // Checks if this is the last task.
699cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          if (prefetchMetadataQueue.getWaitingTasksCount() === 0 &&
700cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)              prefetchMetadataQueue.getRunningTasksCount() === 1) {
701f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)            // |callbackOuter| in |finish| must be called before
702f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)            // |callbackInner|, to prevent double-calling.
703f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)            finish();
704cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          }
705cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
706cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          callbackInner();
707cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        }.bind(this));
708cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      }.bind(this, chunk));
709cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    }
710cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }.bind(this));
7115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
7125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
7145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {Array.<Entry>} entries Files.
715558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch * @param {function(Object)} callback Callback on done.
7165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
7175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DirectoryContents.prototype.prefetchMetadata = function(entries, callback) {
718f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  this.context_.metadataCache.getLatest(entries, 'filesystem|drive', callback);
7195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
7205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
7224e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * Creates a DirectoryContents instance to show entries in a directory.
723c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) *
7244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * @param {FileListContext} context File list context.
7254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * @param {DirectoryEntry} directoryEntry The current directory entry.
7264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * @return {DirectoryContents} Created DirectoryContents instance.
7275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
7284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)DirectoryContents.createForDirectory = function(context, directoryEntry) {
7294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return new DirectoryContents(
7304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      context,
7314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      false,  // Non search.
7324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      directoryEntry,
7334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      function() {
7344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        return new DirectoryContentScanner(directoryEntry);
7354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      });
7364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)};
7375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
7394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * Creates a DirectoryContents instance to show the result of the search on
7404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * Drive File System.
741c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) *
7425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {FileListContext} context File list context.
7434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * @param {DirectoryEntry} directoryEntry The current directory entry.
7445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {string} query Search query.
7454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * @return {DirectoryContents} Created DirectoryContents instance.
7465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
7474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)DirectoryContents.createForDriveSearch = function(
7485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    context, directoryEntry, query) {
7494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return new DirectoryContents(
7504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      context,
7514e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      true,  // Search.
7524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      directoryEntry,
7534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      function() {
7544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        return new DriveSearchContentScanner(query);
7554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      });
7565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
7575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
7594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * Creates a DirectoryContents instance to show the result of the search on
7604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * Local File System.
7614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) *
7625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {FileListContext} context File list context.
7634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * @param {DirectoryEntry} directoryEntry The current directory entry.
7645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {string} query Search query.
7654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * @return {DirectoryContents} Created DirectoryContents instance.
7665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
7674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)DirectoryContents.createForLocalSearch = function(
7684e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    context, directoryEntry, query) {
7694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return new DirectoryContents(
7704e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      context,
7714e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      true,  // Search.
7724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      directoryEntry,
7734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      function() {
7744e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        return new LocalSearchContentScanner(directoryEntry, query);
7754e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      });
7765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
7775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
7794e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * Creates a DirectoryContents instance to show the result of metadata search
7804e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * on Drive File System.
781c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) *
782c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * @param {FileListContext} context File list context.
7834e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * @param {DirectoryEntry} fakeDirectoryEntry Fake directory entry representing
7844e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) *     the set of result entries. This serves as a top directory for the
7854e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) *     search.
7864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * @param {DriveMetadataSearchContentScanner.SearchType} searchType The type of
7874e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) *     the search. The scanner will restricts the entries based on the given
7884e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) *     type.
7894e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * @return {DirectoryContents} Created DirectoryContents instance.
7904e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) */
7914e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)DirectoryContents.createForDriveMetadataSearch = function(
7925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    context, fakeDirectoryEntry, searchType) {
7934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return new DirectoryContents(
7944e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      context,
7954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      true,  // Search
7964e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      fakeDirectoryEntry,
7974e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      function() {
7985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        return new DriveMetadataSearchContentScanner(searchType);
7994e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      });
800c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)};
801