OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 /** | 5 /** |
6 * The current selection object. | 6 * The current selection object. |
7 * | 7 * |
8 * @param {!FileManager} fileManager FileManager instance. | 8 * @param {FileManager} fileManager FileManager instance. |
9 * @param {!Array.<number>} indexes Selected indexes. | 9 * @param {Array.<number>} indexes Selected indexes. |
10 * @constructor | 10 * @constructor |
11 * @struct | |
12 */ | 11 */ |
13 function FileSelection(fileManager, indexes) { | 12 function FileSelection(fileManager, indexes) { |
14 /** | |
15 * @type {!FileManager} | |
16 * @private | |
17 * @const | |
18 */ | |
19 this.fileManager_ = fileManager; | 13 this.fileManager_ = fileManager; |
20 | |
21 /** | |
22 * @type {number} | |
23 * @private | |
24 */ | |
25 this.computeBytesSequence_ = 0; | 14 this.computeBytesSequence_ = 0; |
26 | |
27 /** | |
28 * @type {!Array.<number>} | |
29 * @const | |
30 */ | |
31 this.indexes = indexes; | 15 this.indexes = indexes; |
32 | |
33 /** | |
34 * @type {!Array.<!Entry>} | |
35 * @const | |
36 */ | |
37 this.entries = []; | 16 this.entries = []; |
38 | |
39 /** | |
40 * @type {number} | |
41 */ | |
42 this.totalCount = 0; | 17 this.totalCount = 0; |
43 | |
44 /** | |
45 * @type {number} | |
46 */ | |
47 this.fileCount = 0; | 18 this.fileCount = 0; |
48 | |
49 /** | |
50 * @type {number} | |
51 */ | |
52 this.directoryCount = 0; | 19 this.directoryCount = 0; |
53 | |
54 /** | |
55 * @type {number} | |
56 */ | |
57 this.bytes = 0; | 20 this.bytes = 0; |
58 | |
59 /** | |
60 * @type {boolean} | |
61 */ | |
62 this.showBytes = false; | 21 this.showBytes = false; |
63 | 22 this.allDriveFilesPresent = false, |
64 /** | |
65 * @type {boolean} | |
66 */ | |
67 this.allDriveFilesPresent = false; | |
68 | |
69 /** | |
70 * @type {?string} | |
71 */ | |
72 this.iconType = null; | 23 this.iconType = null; |
73 | |
74 /** | |
75 * @type {boolean} | |
76 */ | |
77 this.bytesKnown = false; | 24 this.bytesKnown = false; |
78 | |
79 /** | |
80 * @type {boolean} | |
81 * @private | |
82 */ | |
83 this.mustBeHidden_ = false; | 25 this.mustBeHidden_ = false; |
84 | |
85 /** | |
86 * @type {Array.<string>} | |
87 */ | |
88 this.mimeTypes = null; | 26 this.mimeTypes = null; |
89 | 27 |
90 /** | |
91 * @type {!FileTasks} | |
92 */ | |
93 this.tasks = new FileTasks(this.fileManager_); | |
94 | |
95 /** | |
96 * @type {Promise} | |
97 * @private | |
98 */ | |
99 this.asyncInitPromise_ = null; | |
100 | |
101 // Synchronously compute what we can. | 28 // Synchronously compute what we can. |
102 for (var i = 0; i < this.indexes.length; i++) { | 29 for (var i = 0; i < this.indexes.length; i++) { |
103 var entry = /** @type {!Entry} */ | 30 var entry = /** @type {!Entry} */ |
104 (fileManager.getFileList().item(this.indexes[i])); | 31 (fileManager.getFileList().item(this.indexes[i])); |
105 if (!entry) | 32 if (!entry) |
106 continue; | 33 continue; |
107 | 34 |
108 this.entries.push(entry); | 35 this.entries.push(entry); |
109 | 36 |
110 if (this.iconType == null) { | 37 if (this.iconType == null) { |
111 this.iconType = FileType.getIcon(entry); | 38 this.iconType = FileType.getIcon(entry); |
112 } else if (this.iconType != 'unknown') { | 39 } else if (this.iconType != 'unknown') { |
113 var iconType = FileType.getIcon(entry); | 40 var iconType = FileType.getIcon(entry); |
114 if (this.iconType != iconType) | 41 if (this.iconType != iconType) |
115 this.iconType = 'unknown'; | 42 this.iconType = 'unknown'; |
116 } | 43 } |
117 | 44 |
118 if (entry.isFile) { | 45 if (entry.isFile) { |
119 this.fileCount += 1; | 46 this.fileCount += 1; |
120 } else { | 47 } else { |
121 this.directoryCount += 1; | 48 this.directoryCount += 1; |
122 } | 49 } |
123 this.totalCount++; | 50 this.totalCount++; |
124 } | 51 } |
| 52 |
| 53 this.tasks = new FileTasks(this.fileManager_); |
| 54 |
| 55 Object.seal(this); |
125 } | 56 } |
126 | 57 |
127 /** | 58 /** |
128 * Computes data required to get file tasks and requests the tasks. | 59 * Computes data required to get file tasks and requests the tasks. |
129 * @return {!Promise} | 60 * |
| 61 * @param {function()} callback The callback. |
130 */ | 62 */ |
131 FileSelection.prototype.completeInit = function() { | 63 FileSelection.prototype.createTasks = function(callback) { |
132 if (!this.asyncInitPromise_) { | 64 if (!this.fileManager_.isOnDrive()) { |
133 if (!this.fileManager_.isOnDrive()) { | 65 this.tasks.init(this.entries); |
134 this.asyncInitPromise_ = Promise.resolve(); | 66 callback(); |
135 this.tasks.init(this.entries); | 67 return; |
136 this.allDriveFilesPresent = true; | 68 } |
137 } else { | 69 |
138 this.asyncInitPromise_ = new Promise(function(fulfill) { | 70 this.fileManager_.metadataCache_.get( |
139 this.fileManager_.metadataCache.get(this.entries, 'external', fulfill); | 71 this.entries, 'external', function(props) { |
140 }.bind(this)).then(function(props) { | |
141 var present = props.filter(function(p) { | 72 var present = props.filter(function(p) { |
142 return p && p.availableOffline; | 73 return p && p.availableOffline; |
143 }); | 74 }); |
144 this.allDriveFilesPresent = present.length == props.length; | 75 this.allDriveFilesPresent = present.length == props.length; |
145 // Collect all of the mime types and push that info into the | 76 |
146 // selection. | 77 // Collect all of the mime types and push that info into the selection. |
147 this.mimeTypes = props.map(function(value) { | 78 this.mimeTypes = props.map(function(value) { |
148 return (value && value.contentMimeType) || ''; | 79 return (value && value.contentMimeType) || ''; |
149 }); | 80 }); |
| 81 |
150 this.tasks.init(this.entries, this.mimeTypes); | 82 this.tasks.init(this.entries, this.mimeTypes); |
| 83 callback(); |
151 }.bind(this)); | 84 }.bind(this)); |
152 } | |
153 } | |
154 return this.asyncInitPromise_; | |
155 }; | 85 }; |
156 | 86 |
157 /** | 87 /** |
158 * Computes the total size of selected files. | 88 * Computes the total size of selected files. |
159 * | 89 * |
160 * @param {function()} callback Completion callback. Not called when cancelled, | 90 * @param {function()} callback Completion callback. Not called when cancelled, |
161 * or a new call has been invoked in the meantime. | 91 * or a new call has been invoked in the meantime. |
162 */ | 92 */ |
163 FileSelection.prototype.computeBytes = function(callback) { | 93 FileSelection.prototype.computeBytes = function(callback) { |
164 if (this.entries.length == 0) { | 94 if (this.entries.length == 0) { |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
213 * | 143 * |
214 * @private | 144 * @private |
215 */ | 145 */ |
216 FileSelection.prototype.cancelComputing_ = function() { | 146 FileSelection.prototype.cancelComputing_ = function() { |
217 this.computeBytesSequence_++; | 147 this.computeBytesSequence_++; |
218 }; | 148 }; |
219 | 149 |
220 /** | 150 /** |
221 * This object encapsulates everything related to current selection. | 151 * This object encapsulates everything related to current selection. |
222 * | 152 * |
223 * @param {!FileManager} fileManager File manager instance. | 153 * @param {FileManager} fileManager File manager instance. |
224 * @extends {cr.EventTarget} | 154 * @extends {cr.EventTarget} |
225 * @constructor | 155 * @constructor |
226 * @struct | 156 * @struct |
227 * @suppress {checkStructDictInheritance} | 157 * @suppress {checkStructDictInheritance} |
228 */ | 158 */ |
229 function FileSelectionHandler(fileManager) { | 159 function FileSelectionHandler(fileManager) { |
230 cr.EventTarget.call(this); | 160 cr.EventTarget.call(this); |
231 | 161 |
232 this.fileManager_ = fileManager; | 162 this.fileManager_ = fileManager; |
233 // TODO(dgozman): create a shared object with most of UI elements. | 163 // TODO(dgozman): create a shared object with most of UI elements. |
234 this.previewPanel_ = fileManager.ui.previewPanel; | 164 this.previewPanel_ = fileManager.ui.previewPanel; |
235 this.taskMenuButton_ = fileManager.ui.taskMenuButton; | 165 this.taskMenuButton_ = fileManager.ui.taskMenuButton; |
236 this.selection = new FileSelection(this.fileManager_, []); | 166 this.selection = new FileSelection(this.fileManager_, []); |
237 | 167 |
238 /** | 168 /** |
239 * @private | 169 * @private |
240 * @type {number} | 170 * @type {number} |
241 */ | 171 */ |
242 this.selectionUpdateTimer_ = 0; | 172 this.selectionUpdateTimer_ = 0; |
243 | 173 |
244 /** | 174 /** |
245 * @private | 175 * @private |
246 * @type {!Date} | 176 * @type {!Date} |
247 */ | 177 */ |
248 this.lastFileSelectionTime_ = new Date(); | 178 this.lastFileSelectionTime_ = new Date(); |
249 } | 179 } |
250 | 180 |
251 /** | 181 /** |
252 * @enum {string} | |
253 */ | |
254 FileSelectionHandler.EventType = { | |
255 /** | |
256 * Dispatched every time when selection is changed. | |
257 */ | |
258 CHANGE: 'change', | |
259 | |
260 /** | |
261 * Dispatched 200ms later after the selecton is changed. | |
262 * If multiple changes are happened during the term, only one CHANGE_THROTTLED | |
263 * event is dispatched. | |
264 */ | |
265 CHANGE_THROTTLED: 'changethrottled' | |
266 }; | |
267 | |
268 /** | |
269 * Create the temporary disabled action item. | 182 * Create the temporary disabled action item. |
270 * @return {Object} Created disabled item. | 183 * @return {Object} Created disabled item. |
271 * @private | 184 * @private |
272 */ | 185 */ |
273 FileSelectionHandler.createTemporaryDisabledActionItem_ = function() { | 186 FileSelectionHandler.createTemporaryDisabledActionItem_ = function() { |
274 if (!FileSelectionHandler.cachedDisabledActionItem_) { | 187 if (!FileSelectionHandler.cachedDisabledActionItem_) { |
275 FileSelectionHandler.cachedDisabledActionItem_ = { | 188 FileSelectionHandler.cachedDisabledActionItem_ = { |
276 title: str('ACTION_OPEN'), | 189 title: str('ACTION_OPEN'), |
277 disabled: true, | 190 disabled: true, |
278 taskId: null | 191 taskId: null |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
347 this.fileManager_.updateContextMenuActionItems( | 260 this.fileManager_.updateContextMenuActionItems( |
348 [FileSelectionHandler.createTemporaryDisabledActionItem_()]); | 261 [FileSelectionHandler.createTemporaryDisabledActionItem_()]); |
349 } else { | 262 } else { |
350 // Update context menu. | 263 // Update context menu. |
351 this.fileManager_.updateContextMenuActionItems(); | 264 this.fileManager_.updateContextMenuActionItems(); |
352 } | 265 } |
353 | 266 |
354 this.selectionUpdateTimer_ = setTimeout(function() { | 267 this.selectionUpdateTimer_ = setTimeout(function() { |
355 this.selectionUpdateTimer_ = null; | 268 this.selectionUpdateTimer_ = null; |
356 if (this.selection == selection) | 269 if (this.selection == selection) |
357 this.updateFileSelectionAsync_(selection); | 270 this.updateFileSelectionAsync(selection); |
358 }.bind(this), updateDelay); | 271 }.bind(this), updateDelay); |
359 | 272 |
360 cr.dispatchSimpleEvent(this, FileSelectionHandler.EventType.CHANGE); | 273 cr.dispatchSimpleEvent(this, 'change'); |
361 }; | 274 }; |
362 | 275 |
363 /** | 276 /** |
364 * Calculates async selection stats and updates secondary UI elements. | 277 * Calculates async selection stats and updates secondary UI elements. |
365 * | 278 * |
366 * @param {FileSelection} selection The selection object. | 279 * @param {FileSelection} selection The selection object. |
367 * @private | |
368 */ | 280 */ |
369 FileSelectionHandler.prototype.updateFileSelectionAsync_ = function(selection) { | 281 FileSelectionHandler.prototype.updateFileSelectionAsync = function(selection) { |
370 if (this.selection !== selection) | 282 if (this.selection != selection) return; |
371 return; | |
372 | 283 |
373 // Update the file tasks. | 284 // Update the file tasks. |
374 if (this.fileManager_.dialogType === DialogType.FULL_PAGE && | 285 if (this.fileManager_.dialogType === DialogType.FULL_PAGE && |
375 selection.directoryCount === 0 && selection.fileCount > 0) { | 286 selection.directoryCount === 0 && selection.fileCount > 0) { |
376 selection.completeInit().then(function() { | 287 selection.createTasks(function() { |
377 if (this.selection !== selection) | 288 if (this.selection != selection) |
378 return; | 289 return; |
379 selection.tasks.display(this.taskMenuButton_); | 290 selection.tasks.display(this.taskMenuButton_); |
380 selection.tasks.updateMenuItem(); | 291 selection.tasks.updateMenuItem(); |
381 }.bind(this)); | 292 }.bind(this)); |
382 } else { | 293 } else { |
383 this.taskMenuButton_.hidden = true; | 294 this.taskMenuButton_.hidden = true; |
384 } | 295 } |
385 | 296 |
386 // Update preview panels. | 297 // Update preview panels. |
387 var wasVisible = this.previewPanel_.visible; | 298 var wasVisible = this.previewPanel_.visible; |
388 this.previewPanel_.setSelection(selection); | 299 this.previewPanel_.setSelection(selection); |
389 | 300 |
390 // Scroll to item | 301 // Scroll to item |
391 if (!wasVisible && this.selection.totalCount == 1) { | 302 if (!wasVisible && this.selection.totalCount == 1) { |
392 var list = this.fileManager_.getCurrentList(); | 303 var list = this.fileManager_.getCurrentList(); |
393 list.scrollIndexIntoView(list.selectionModel.selectedIndex); | 304 list.scrollIndexIntoView(list.selectionModel.selectedIndex); |
394 } | 305 } |
395 | 306 |
396 // Sync the commands availability. | 307 // Sync the commands availability. |
397 if (this.fileManager_.commandHandler) | 308 if (this.fileManager_.commandHandler) |
398 this.fileManager_.commandHandler.updateAvailability(); | 309 this.fileManager_.commandHandler.updateAvailability(); |
399 | 310 |
400 cr.dispatchSimpleEvent(this, FileSelectionHandler.EventType.CHANGE_THROTTLED); | 311 // Inform tests it's OK to click buttons now. |
| 312 if (selection.totalCount > 0) |
| 313 util.testSendMessage('selection-change-complete'); |
401 }; | 314 }; |
402 | |
403 /** | |
404 * Returns whether all the selected files are available currently or not. | |
405 * Should be called after the selection initialized. | |
406 * @return {boolean} | |
407 */ | |
408 FileSelectionHandler.prototype.isAvailable = function() { | |
409 return !this.fileManager_.isOnDrive() || | |
410 this.fileManager_.volumeManager.getDriveConnectionState().type !== | |
411 VolumeManagerCommon.DriveConnectionType.OFFLINE || | |
412 this.selection.allDriveFilesPresent; | |
413 }; | |
OLD | NEW |