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
3 // found in the LICENSE file.
6 * Base item of NavigationListModel. Should not be created directly.
7 * @param {string} label Label.
10 function NavigationModelItem(label) {
14 NavigationModelItem.prototype = {
15 get label() { return this.label_; }
19 * Check whether given two model items are same.
20 * @param {NavigationModelItem} item1 The first item to be compared.
21 * @param {NavigationModelItem} item2 The second item to be compared.
22 * @return {boolean} True if given two model items are same.
24 NavigationModelItem.isSame = function(item1, item2) {
25 if (item1.isVolume != item2.isVolume)
29 return item1.volumeInfo === item2.volumeInfo;
31 return util.isSameEntry(item1.entry, item2.entry);
35 * Item of NavigationListModel for shortcuts.
37 * @param {string} label Label.
38 * @param {!DirectoryEntry} entry Entry. Cannot be null.
40 * @extends {NavigationModelItem}
42 function NavigationModelShortcutItem(label, entry) {
43 NavigationModelItem.call(this, label);
48 NavigationModelShortcutItem.prototype = {
49 __proto__: NavigationModelItem.prototype,
50 get entry() { return this.entry_; },
51 get isVolume() { return false; },
52 get isShortcut() { return true; }
56 * Item of NavigationListModel for volumes.
58 * @param {string} label Label.
59 * @param {!VolumeInfo} volumeInfo Volume info for the volume. Cannot be null.
61 * @extends {NavigationModelItem}
63 function NavigationModelVolumeItem(label, volumeInfo) {
64 NavigationModelItem.call(this, label);
65 this.volumeInfo_ = volumeInfo;
66 // Start resolving the display root because it is used
67 // for determining executability of commands.
68 this.volumeInfo_.resolveDisplayRoot(
69 function() {}, function() {});
73 NavigationModelVolumeItem.prototype = {
74 __proto__: NavigationModelItem.prototype,
75 get volumeInfo() { return this.volumeInfo_; },
76 get isVolume() { return true; },
77 get isShortcut() { return false; }
81 * A navigation list model. This model combines the 2 lists.
82 * @param {VolumeManagerWrapper} volumeManager VolumeManagerWrapper instance.
83 * @param {(cr.ui.ArrayDataModel|FolderShortcutsDataModel)} shortcutListModel
84 * The list of folder shortcut.
86 * @extends {cr.EventTarget}
88 function NavigationListModel(volumeManager, shortcutListModel) {
89 cr.EventTarget.call(this);
91 this.volumeManager_ = volumeManager;
92 this.shortcutListModel_ = shortcutListModel;
94 var volumeInfoToModelItem = function(volumeInfo) {
95 return new NavigationModelVolumeItem(
100 var entryToModelItem = function(entry) {
101 var item = new NavigationModelShortcutItem(
108 * Type of updated list.
116 Object.freeze(ListType);
118 // Generates this.volumeList_ and this.shortcutList_ from the models.
120 this.volumeManager_.volumeInfoList.slice().map(volumeInfoToModelItem);
122 this.shortcutList_ = [];
123 for (var i = 0; i < this.shortcutListModel_.length; i++) {
124 var shortcutEntry = /** @type {Entry} */ (this.shortcutListModel_.item(i));
125 var volumeInfo = this.volumeManager_.getVolumeInfo(shortcutEntry);
126 this.shortcutList_.push(entryToModelItem(shortcutEntry));
129 // Generates a combined 'permuted' event from an event of either list.
130 var permutedHandler = function(listType, event) {
133 // Build the volumeList.
134 if (listType == ListType.VOLUME_LIST) {
135 // The volume is mounted or unmounted.
138 // Use the old instances if they just move.
139 for (var i = 0; i < event.permutation.length; i++) {
140 if (event.permutation[i] >= 0)
141 newList[event.permutation[i]] = this.volumeList_[i];
144 // Create missing instances.
145 for (var i = 0; i < event.newLength; i++) {
147 newList[i] = volumeInfoToModelItem(
148 this.volumeManager_.volumeInfoList.item(i));
151 this.volumeList_ = newList;
153 permutation = event.permutation.slice();
155 // shortcutList part has not been changed, so the permutation should be
156 // just identity mapping with a shift.
157 for (var i = 0; i < this.shortcutList_.length; i++) {
158 permutation.push(i + this.volumeList_.length);
161 // Build the shortcutList.
163 // volumeList part has not been changed, so the permutation should be
167 for (var i = 0; i < this.volumeList_.length; i++) {
172 var oldListIndex = 0;
174 while (modelIndex < this.shortcutListModel_.length &&
175 oldListIndex < this.shortcutList_.length) {
176 var shortcutEntry = this.shortcutListModel_.item(modelIndex);
177 var cmp = this.shortcutListModel_.compare(
178 shortcutEntry, this.shortcutList_[oldListIndex].entry);
180 // The shortcut at shortcutList_[oldListIndex] is removed.
181 permutation.push(-1);
187 // Reuse the old instance.
188 permutation.push(newList.length + this.volumeList_.length);
189 newList.push(this.shortcutList_[oldListIndex]);
192 // We needs to create a new instance for the shortcut entry.
193 newList.push(entryToModelItem(shortcutEntry));
198 // Add remaining (new) shortcuts if necessary.
199 for (; modelIndex < this.shortcutListModel_.length; modelIndex++) {
200 var shortcutEntry = this.shortcutListModel_.item(modelIndex);
201 newList.push(entryToModelItem(shortcutEntry));
204 // Fill remaining permutation if necessary.
205 for (; oldListIndex < this.shortcutList_.length; oldListIndex++)
206 permutation.push(-1);
208 this.shortcutList_ = newList;
211 // Dispatch permuted event.
212 var permutedEvent = new Event('permuted');
213 permutedEvent.newLength =
214 this.volumeList_.length + this.shortcutList_.length;
215 permutedEvent.permutation = permutation;
216 this.dispatchEvent(permutedEvent);
219 this.volumeManager_.volumeInfoList.addEventListener(
220 'permuted', permutedHandler.bind(this, ListType.VOLUME_LIST));
221 this.shortcutListModel_.addEventListener(
222 'permuted', permutedHandler.bind(this, ListType.SHORTCUT_LIST));
224 // 'change' event is just ignored, because it is not fired neither in
225 // the folder shortcut list nor in the volume info list.
226 // 'splice' and 'sorted' events are not implemented, since they are not used
231 * NavigationList inherits cr.EventTarget.
233 NavigationListModel.prototype = {
234 __proto__: cr.EventTarget.prototype,
235 get length() { return this.length_(); },
236 get folderShortcutList() { return this.shortcutList_; }
240 * Returns the item at the given index.
241 * @param {number} index The index of the entry to get.
242 * @return {NavigationModelItem} The item at the given index.
244 NavigationListModel.prototype.item = function(index) {
245 var offset = this.volumeList_.length;
247 return this.volumeList_[index];
248 return this.shortcutList_[index - offset];
252 * Returns the number of items in the model.
253 * @return {number} The length of the model.
256 NavigationListModel.prototype.length_ = function() {
257 return this.volumeList_.length + this.shortcutList_.length;
261 * Returns the first matching item.
262 * @param {NavigationModelItem} modelItem The entry to find.
263 * @param {number=} opt_fromIndex If provided, then the searching start at
264 * the {@code opt_fromIndex}.
265 * @return {number} The index of the first found element or -1 if not found.
267 NavigationListModel.prototype.indexOf = function(modelItem, opt_fromIndex) {
268 for (var i = opt_fromIndex || 0; i < this.length; i++) {
269 if (modelItem === this.item(i))
276 * Called externally when one of the items is not found on the filesystem.
277 * @param {NavigationModelItem} modelItem The entry which is not found.
279 NavigationListModel.prototype.onItemNotFoundError = function(modelItem) {
280 if (modelItem.isVolume) {
281 // TODO(mtomasz, yoshiki): Implement when needed.
284 if (modelItem.isShortcut) {
285 // For shortcuts, lets the shortcut model handle this situation.
286 this.shortcutListModel_.onItemNotFoundError(modelItem.entry);