Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / ui / file_manager / file_manager / foreground / js / file_watcher.js
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 'use strict';
6
7 /**
8  * Watches for changes in the tracked directory, including local metadata
9  * changes.
10  *
11  * @param {MetadataCache} metadataCache Instance of MetadataCache.
12  * @extends {cr.EventTarget}
13  * @constructor
14  */
15 function FileWatcher(metadataCache) {
16   this.queue_ = new AsyncUtil.Queue();
17   this.metadataCache_ = metadataCache;
18   this.watchedDirectoryEntry_ = null;
19
20   this.onDirectoryChangedBound_ = this.onDirectoryChanged_.bind(this);
21   chrome.fileBrowserPrivate.onDirectoryChanged.addListener(
22       this.onDirectoryChangedBound_);
23
24   this.filesystemMetadataObserverId_ = null;
25   this.thumbnailMetadataObserverId_ = null;
26   this.driveMetadataObserverId_ = null;
27 }
28
29 /**
30  * FileWatcher extends cr.EventTarget.
31  */
32 FileWatcher.prototype.__proto__ = cr.EventTarget.prototype;
33
34 /**
35  * Stops watching (must be called before page unload).
36  */
37 FileWatcher.prototype.dispose = function() {
38   chrome.fileBrowserPrivate.onDirectoryChanged.removeListener(
39       this.onDirectoryChangedBound_);
40   if (this.watchedDirectoryEntry_)
41     this.resetWatchedEntry_(function() {}, function() {});
42 };
43
44 /**
45  * Called when a file in the watched directory is changed.
46  * @param {Event} event Change event.
47  * @private
48  */
49 FileWatcher.prototype.onDirectoryChanged_ = function(event) {
50   if (this.watchedDirectoryEntry_ &&
51       event.entry.toURL() === this.watchedDirectoryEntry_.toURL()) {
52     var e = new Event('watcher-directory-changed');
53     this.dispatchEvent(e);
54   }
55 };
56
57 /**
58  * Called when general metadata in the watched directory has been changed.
59  *
60  * @param {Array.<Entry>} entries Array of entries.
61  * @param {Object.<string, Object>} properties Map from entry URLs to metadata
62  *     properties.
63  * @private
64  */
65 FileWatcher.prototype.onFilesystemMetadataChanged_ = function(
66     entries, properties) {
67   this.dispatchMetadataEvent_('filesystem', entries, properties);
68 };
69
70 /**
71  * Called when thumbnail metadata in the watched directory has been changed.
72  *
73  * @param {Array.<Entry>} entries Array of entries.
74  * @param {Object.<string, Object>} properties Map from entry URLs to metadata
75  *     properties.
76  * @private
77  */
78 FileWatcher.prototype.onThumbnailMetadataChanged_ = function(
79     entries, properties) {
80   this.dispatchMetadataEvent_('thumbnail', entries, properties);
81 };
82
83 /**
84  * Called when drive metadata in the watched directory has been changed.
85  *
86  * @param {Array.<Entry>} entries Array of entries.
87  * @param {Object.<string, Object>} properties Map from entry URLs to metadata
88  *     properties.
89  * @private
90  */
91 FileWatcher.prototype.onDriveMetadataChanged_ = function(
92     entries, properties) {
93   this.dispatchMetadataEvent_('drive', entries, properties);
94 };
95
96 /**
97  * Dispatches an event about detected change in metadata within the tracked
98  * directory.
99  *
100  * @param {string} type Type of the metadata change.
101  * @param {Array.<Entry>} entries Array of entries.
102  * @param {Object.<string, Object>} properties Map from entry URLs to metadata
103  *     properties.
104  * @private
105  */
106 FileWatcher.prototype.dispatchMetadataEvent_ = function(
107     type, entries, properties) {
108   var e = new Event('watcher-metadata-changed');
109   e.metadataType = type;
110   e.entries = entries;
111   e.properties = properties;
112   this.dispatchEvent(e);
113 };
114
115 /**
116  * Changes the watched directory. In case of a fake entry, the watch is
117  * just released, since there is no reason to track a fake directory.
118  *
119  * @param {!DirectoryEntry|!Object} entry Directory entry to be tracked, or the
120  *     fake entry.
121  * @param {function()} callback Completion callback.
122  */
123 FileWatcher.prototype.changeWatchedDirectory = function(entry, callback) {
124   if (!util.isFakeEntry(entry)) {
125     this.changeWatchedEntry_(
126         entry,
127         callback,
128         function() {
129           console.error(
130              'Unable to change the watched directory to: ' + entry.toURL());
131           callback();
132         });
133   } else {
134     this.resetWatchedEntry_(
135         callback,
136         function() {
137           console.error('Unable to reset the watched directory.');
138           callback();
139         });
140   }
141 };
142
143 /**
144  * Resets the watched entry to the passed directory.
145  *
146  * @param {function()} onSuccess Success callback.
147  * @param {function()} onError Error callback.
148  * @private
149  */
150 FileWatcher.prototype.resetWatchedEntry_ = function(onSuccess, onError) {
151   // Run the tasks in the queue to avoid races.
152   this.queue_.run(function(callback) {
153     // Release the watched directory.
154     if (this.watchedDirectoryEntry_) {
155       chrome.fileBrowserPrivate.removeFileWatch(
156           this.watchedDirectoryEntry_.toURL(),
157           function(result) {
158             this.watchedDirectoryEntry_ = null;
159             if (result)
160               onSuccess();
161             else
162               onError();
163             callback();
164           }.bind(this));
165       this.metadataCache_.removeObserver(this.filesystemMetadataObserverId_);
166       this.metadataCache_.removeObserver(this.thumbnailMetadataObserverId_);
167       this.metadataCache_.removeObserver(this.driveMetadataObserverId_);
168     } else {
169       onSuccess();
170       callback();
171     }
172   }.bind(this));
173 };
174
175 /**
176  * Sets the watched entry to the passed directory.
177  *
178  * @param {!DirectoryEntry} entry Directory to be watched.
179  * @param {function()} onSuccess Success callback.
180  * @param {function()} onError Error callback.
181  * @private
182  */
183 FileWatcher.prototype.changeWatchedEntry_ = function(
184     entry, onSuccess, onError) {
185   var setEntryClosure = function() {
186     // Run the tasks in the queue to avoid races.
187     this.queue_.run(function(callback) {
188       chrome.fileBrowserPrivate.addFileWatch(
189           entry.toURL(),
190           function(result) {
191             if (!result) {
192               this.watchedDirectoryEntry_ = null;
193               onError();
194             } else {
195               this.watchedDirectoryEntry_ = entry;
196               onSuccess();
197             }
198             callback();
199           }.bind(this));
200       this.filesystemMetadataObserverId_ = this.metadataCache_.addObserver(
201         entry,
202         MetadataCache.CHILDREN,
203         'filesystem',
204         this.onFilesystemMetadataChanged_.bind(this));
205       this.thumbnailMetadataObserverId_ = this.metadataCache_.addObserver(
206         entry,
207         MetadataCache.CHILDREN,
208         'thumbnail',
209         this.onThumbnailMetadataChanged_.bind(this));
210       this.driveMetadataObserverId_ = this.metadataCache_.addObserver(
211         entry,
212         MetadataCache.CHILDREN,
213         'drive',
214         this.onDriveMetadataChanged_.bind(this));
215     }.bind(this));
216   }.bind(this);
217
218   // Reset the watched directory first, then set the new watched directory.
219   this.resetWatchedEntry_(setEntryClosure, onError);
220 };
221
222 /**
223  * @return {DirectoryEntry} Current watched directory entry.
224  */
225 FileWatcher.prototype.getWatchedDirectoryEntry = function() {
226   return this.watchedDirectoryEntry_;
227 };