OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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 'use strict'; | 5 'use strict'; |
6 | 6 |
7 /** | 7 /** |
8 * Called from the main frame when unloading. | 8 * Called from the main frame when unloading. |
9 * @param {boolean=} opt_exiting True if the app is exiting. | 9 * @param {boolean=} opt_exiting True if the app is exiting. |
10 */ | 10 */ |
11 function unload(opt_exiting) { Gallery.instance.onUnload(opt_exiting); } | 11 function unload(opt_exiting) { Gallery.instance.onUnload(opt_exiting); } |
12 | 12 |
13 /** | 13 /** |
14 * Overrided metadata worker's path. | 14 * Overrided metadata worker's path. |
15 * @type {string} | 15 * @type {string} |
16 * @const | 16 * @const |
17 */ | 17 */ |
18 ContentProvider.WORKER_SCRIPT = '/js/metadata_worker.js'; | 18 ContentProvider.WORKER_SCRIPT = '/js/metadata_worker.js'; |
19 | 19 |
20 /** | 20 /** |
21 * Data model for gallery. | 21 * Data model for gallery. |
22 * | 22 * |
23 * @param {MetadataCache} metadataCache Metadata cache. | 23 * @param {MetadataCache} metadataCache Metadata cache. |
24 * @constructor | 24 * @constructor |
25 * @extends {cr.ui.ArrayDataModel} | 25 * @extends {cr.ui.ArrayDataModel} |
26 */ | 26 */ |
27 function GalleryDataModel(metadataCache) { | 27 function GalleryDataModel(metadataCache) { |
28 cr.ui.ArrayDataModel.call(this, []); | 28 cr.ui.ArrayDataModel.call(this, []); |
| 29 |
| 30 /** |
| 31 * Metadata cache. |
| 32 * @type {MetadataCache} |
| 33 * @private |
| 34 */ |
29 this.metadataCache_ = metadataCache; | 35 this.metadataCache_ = metadataCache; |
| 36 |
| 37 /** |
| 38 * Directory where the image is saved if the image is located in a read-only |
| 39 * volume. |
| 40 * @type {DirectoryEntry} |
| 41 */ |
| 42 this.fallbackSaveDirectory = null; |
30 } | 43 } |
31 | 44 |
32 /** | 45 /** |
33 * Maximum number of full size image cache. | 46 * Maximum number of full size image cache. |
34 * @type {number} | 47 * @type {number} |
35 * @const | 48 * @const |
36 * @private | 49 * @private |
37 */ | 50 */ |
38 GalleryDataModel.MAX_FULL_IMAGE_CACHE_ = 3; | 51 GalleryDataModel.MAX_FULL_IMAGE_CACHE_ = 3; |
39 | 52 |
(...skipping 25 matching lines...) Expand all Loading... |
65 var newMetadata = ContentProvider.ConvertContentMetadata( | 78 var newMetadata = ContentProvider.ConvertContentMetadata( |
66 metadataEncoder.getMetadata(), | 79 metadataEncoder.getMetadata(), |
67 MetadataCache.cloneMetadata(item.getMetadata())); | 80 MetadataCache.cloneMetadata(item.getMetadata())); |
68 if (newMetadata.filesystem) | 81 if (newMetadata.filesystem) |
69 newMetadata.filesystem.modificationTime = new Date(); | 82 newMetadata.filesystem.modificationTime = new Date(); |
70 if (newMetadata.drive) | 83 if (newMetadata.drive) |
71 newMetadata.drive.present = true; | 84 newMetadata.drive.present = true; |
72 | 85 |
73 return new Promise(function(fulfill, reject) { | 86 return new Promise(function(fulfill, reject) { |
74 item.saveToFile( | 87 item.saveToFile( |
75 null, | 88 this.fallbackSaveDirectory, |
76 overwrite, | 89 overwrite, |
77 canvas, | 90 canvas, |
78 metadataEncoder, | 91 metadataEncoder, |
79 function(success) { | 92 function(success) { |
80 if (!success) { | 93 if (!success) { |
81 reject('Failed to save the image.'); | 94 reject('Failed to save the image.'); |
82 return; | 95 return; |
83 } | 96 } |
84 | 97 |
85 // The item's entry is updated to the latest entry. Update metadata. | 98 // The item's entry is updated to the latest entry. Update metadata. |
(...skipping 10 matching lines...) Expand all Loading... |
96 if (util.isSameEntry(oldEntry, item.getEntry())) { | 109 if (util.isSameEntry(oldEntry, item.getEntry())) { |
97 // Need an update of metdataCache. | 110 // Need an update of metdataCache. |
98 this.metadataCache_.set( | 111 this.metadataCache_.set( |
99 item.getEntry(), | 112 item.getEntry(), |
100 Gallery.METADATA_TYPE, | 113 Gallery.METADATA_TYPE, |
101 newMetadata); | 114 newMetadata); |
102 } else { | 115 } else { |
103 // New entry is added and the item now tracks it. | 116 // New entry is added and the item now tracks it. |
104 // Add another item for the old entry. | 117 // Add another item for the old entry. |
105 var anotherItem = new Gallery.Item( | 118 var anotherItem = new Gallery.Item( |
106 oldEntry, oldMetadata, this.metadataCache_, item.isOriginal()); | 119 oldEntry, |
| 120 oldMetadata, |
| 121 this.metadataCache_, |
| 122 item.isOriginal(), |
| 123 item.isReadOnly()); |
107 // The item must be added behind the existing item so that it does | 124 // The item must be added behind the existing item so that it does |
108 // not change the index of the existing item. | 125 // not change the index of the existing item. |
109 // TODO(hirono): Update the item index of the selection model | 126 // TODO(hirono): Update the item index of the selection model |
110 // correctly. | 127 // correctly. |
111 this.splice(this.indexOf(item) + 1, 0, anotherItem); | 128 this.splice(this.indexOf(item) + 1, 0, anotherItem); |
112 } | 129 } |
113 | 130 |
114 fulfill(); | 131 fulfill(); |
115 }.bind(this)); | 132 }.bind(this)); |
116 }.bind(this)); | 133 }.bind(this)); |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
184 }; | 201 }; |
185 this.container_ = document.querySelector('.gallery'); | 202 this.container_ = document.querySelector('.gallery'); |
186 this.document_ = document; | 203 this.document_ = document; |
187 this.metadataCache_ = this.context_.metadataCache; | 204 this.metadataCache_ = this.context_.metadataCache; |
188 this.volumeManager_ = volumeManager; | 205 this.volumeManager_ = volumeManager; |
189 this.selectedEntry_ = null; | 206 this.selectedEntry_ = null; |
190 this.metadataCacheObserverId_ = null; | 207 this.metadataCacheObserverId_ = null; |
191 this.onExternallyUnmountedBound_ = this.onExternallyUnmounted_.bind(this); | 208 this.onExternallyUnmountedBound_ = this.onExternallyUnmounted_.bind(this); |
192 | 209 |
193 this.dataModel_ = new GalleryDataModel(this.context_.metadataCache); | 210 this.dataModel_ = new GalleryDataModel(this.context_.metadataCache); |
| 211 var downloadVolumeInfo = this.volumeManager_.getCurrentProfileVolumeInfo( |
| 212 VolumeManagerCommon.VolumeType.DOWNLOADS); |
| 213 downloadVolumeInfo.resolveDisplayRoot().then(function(entry) { |
| 214 this.dataModel_.fallbackSaveDirectory = entry; |
| 215 }.bind(this)).catch(function(error) { |
| 216 console.error( |
| 217 'Failed to obtain the fallback directory: ' + (error.stack || error)); |
| 218 }); |
194 this.selectionModel_ = new cr.ui.ListSelectionModel(); | 219 this.selectionModel_ = new cr.ui.ListSelectionModel(); |
195 | 220 |
196 this.initDom_(); | 221 this.initDom_(); |
197 this.initListeners_(); | 222 this.initListeners_(); |
198 } | 223 } |
199 | 224 |
200 /** | 225 /** |
201 * Gallery extends cr.EventTarget. | 226 * Gallery extends cr.EventTarget. |
202 */ | 227 */ |
203 Gallery.prototype.__proto__ = cr.EventTarget.prototype; | 228 Gallery.prototype.__proto__ = cr.EventTarget.prototype; |
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
331 this.filenameEdit_.addEventListener('focus', | 356 this.filenameEdit_.addEventListener('focus', |
332 this.onFilenameFocus_.bind(this)); | 357 this.onFilenameFocus_.bind(this)); |
333 | 358 |
334 this.filenameEdit_.addEventListener('keydown', | 359 this.filenameEdit_.addEventListener('keydown', |
335 this.onFilenameEditKeydown_.bind(this)); | 360 this.onFilenameEditKeydown_.bind(this)); |
336 | 361 |
337 var middleSpacer = this.filenameSpacer_ = | 362 var middleSpacer = this.filenameSpacer_ = |
338 this.toolbar_.querySelector('.middle-spacer'); | 363 this.toolbar_.querySelector('.middle-spacer'); |
339 var buttonSpacer = this.toolbar_.querySelector('button-spacer'); | 364 var buttonSpacer = this.toolbar_.querySelector('button-spacer'); |
340 | 365 |
341 this.prompt_ = new ImageEditor.Prompt(this.container_, str); | 366 this.prompt_ = new ImageEditor.Prompt(this.container_, strf); |
342 | 367 |
343 this.modeButton_ = this.toolbar_.querySelector('button.mode'); | 368 this.modeButton_ = this.toolbar_.querySelector('button.mode'); |
344 this.modeButton_.addEventListener('click', this.toggleMode_.bind(this, null)); | 369 this.modeButton_.addEventListener('click', this.toggleMode_.bind(this, null)); |
345 | 370 |
346 this.mosaicMode_ = new MosaicMode(content, | 371 this.mosaicMode_ = new MosaicMode(content, |
347 this.dataModel_, | 372 this.dataModel_, |
348 this.selectionModel_, | 373 this.selectionModel_, |
349 this.volumeManager_, | 374 this.volumeManager_, |
350 this.toggleMode_.bind(this, null)); | 375 this.toggleMode_.bind(this, null)); |
351 | 376 |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
403 * @param {!Array.<Entry>} selectedEntries Array of selected entries. | 428 * @param {!Array.<Entry>} selectedEntries Array of selected entries. |
404 */ | 429 */ |
405 Gallery.prototype.load = function(entries, selectedEntries) { | 430 Gallery.prototype.load = function(entries, selectedEntries) { |
406 // Obtains max chank size. | 431 // Obtains max chank size. |
407 var maxChunkSize = 20; | 432 var maxChunkSize = 20; |
408 var volumeInfo = this.volumeManager_.getVolumeInfo(entries[0]); | 433 var volumeInfo = this.volumeManager_.getVolumeInfo(entries[0]); |
409 if (volumeInfo && | 434 if (volumeInfo && |
410 volumeInfo.volumeType === VolumeManagerCommon.VolumeType.MTP) { | 435 volumeInfo.volumeType === VolumeManagerCommon.VolumeType.MTP) { |
411 maxChunkSize = 1; | 436 maxChunkSize = 1; |
412 } | 437 } |
| 438 if (volumeInfo.isReadOnly) |
| 439 this.context_.readonlyDirName = volumeInfo.label; |
413 | 440 |
414 // Make loading list. | 441 // Make loading list. |
415 var entrySet = {}; | 442 var entrySet = {}; |
416 for (var i = 0; i < entries.length; i++) { | 443 for (var i = 0; i < entries.length; i++) { |
417 var entry = entries[i]; | 444 var entry = entries[i]; |
418 entrySet[entry.toURL()] = { | 445 entrySet[entry.toURL()] = { |
419 entry: entry, | 446 entry: entry, |
420 selected: false, | 447 selected: false, |
421 index: i | 448 index: i |
422 }; | 449 }; |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
456 var entries = chunk.map(function(chunkItem) { | 483 var entries = chunk.map(function(chunkItem) { |
457 return chunkItem.entry; | 484 return chunkItem.entry; |
458 }); | 485 }); |
459 self.metadataCache_.get(entries, Gallery.METADATA_TYPE, fulfill); | 486 self.metadataCache_.get(entries, Gallery.METADATA_TYPE, fulfill); |
460 }).then(function(metadataList) { | 487 }).then(function(metadataList) { |
461 if (chunk.length !== metadataList.length) | 488 if (chunk.length !== metadataList.length) |
462 return Promise.reject('Failed to load metadata.'); | 489 return Promise.reject('Failed to load metadata.'); |
463 | 490 |
464 // Add items to the model. | 491 // Add items to the model. |
465 var items = chunk.map(function(chunkItem, index) { | 492 var items = chunk.map(function(chunkItem, index) { |
| 493 var volumeInfo = self.volumeManager_.getVolumeInfo(chunkItem.entry); |
466 var clonedMetadata = MetadataCache.cloneMetadata(metadataList[index]); | 494 var clonedMetadata = MetadataCache.cloneMetadata(metadataList[index]); |
467 return new Gallery.Item( | 495 return new Gallery.Item( |
468 chunkItem.entry, | 496 chunkItem.entry, |
469 clonedMetadata, | 497 clonedMetadata, |
470 self.metadataCache_, | 498 self.metadataCache_, |
471 /* original */ true); | 499 /* original */ true, |
| 500 /* readonly */ !!(volumeInfo && volumeInfo.isReadOnly)); |
472 }); | 501 }); |
473 self.dataModel_.push.apply(self.dataModel_, items); | 502 self.dataModel_.push.apply(self.dataModel_, items); |
474 | 503 |
475 // Apply the selection. | 504 // Apply the selection. |
476 var selectionUpdated = false; | 505 var selectionUpdated = false; |
477 for (var i = 0; i < chunk.length; i++) { | 506 for (var i = 0; i < chunk.length; i++) { |
478 if (!chunk[i].selected) | 507 if (!chunk[i].selected) |
479 continue; | 508 continue; |
480 var index = self.dataModel_.indexOf(items[i]); | 509 var index = self.dataModel_.indexOf(items[i]); |
481 if (index < 0) | 510 if (index < 0) |
(...skipping 315 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
797 | 826 |
798 // Name box and rename support. | 827 // Name box and rename support. |
799 | 828 |
800 /** | 829 /** |
801 * Updates the UI related to the selected item and the persistent state. | 830 * Updates the UI related to the selected item and the persistent state. |
802 * | 831 * |
803 * @private | 832 * @private |
804 */ | 833 */ |
805 Gallery.prototype.updateSelectionAndState_ = function() { | 834 Gallery.prototype.updateSelectionAndState_ = function() { |
806 var numSelectedItems = this.selectionModel_.selectedIndexes.length; | 835 var numSelectedItems = this.selectionModel_.selectedIndexes.length; |
807 var displayName = ''; | |
808 var selectedEntryURL = null; | 836 var selectedEntryURL = null; |
809 | 837 |
810 // If it's selecting something, update the variable values. | 838 // If it's selecting something, update the variable values. |
811 if (numSelectedItems) { | 839 if (numSelectedItems) { |
812 // Obtains selected item. | 840 // Obtains selected item. |
813 var selectedItem = | 841 var selectedItem = |
814 this.dataModel_.item(this.selectionModel_.selectedIndex); | 842 this.dataModel_.item(this.selectionModel_.selectedIndex); |
815 this.selectedEntry_ = selectedItem.getEntry(); | 843 this.selectedEntry_ = selectedItem.getEntry(); |
816 selectedEntryURL = this.selectedEntry_.toURL(); | 844 selectedEntryURL = this.selectedEntry_.toURL(); |
817 | 845 |
818 // Update cache. | 846 // Update cache. |
819 selectedItem.touch(); | 847 selectedItem.touch(); |
820 this.dataModel_.evictCache(); | 848 this.dataModel_.evictCache(); |
821 | 849 |
822 // Update the title and the display name. | 850 // Update the title and the display name. |
823 if (numSelectedItems === 1) { | 851 if (numSelectedItems === 1) { |
824 window.top.document.title = this.selectedEntry_.name; | 852 window.top.document.title = this.selectedEntry_.name; |
825 displayName = ImageUtil.getDisplayNameFromName(this.selectedEntry_.name); | 853 this.filenameEdit_.disabled = selectedItem.isReadOnly(); |
| 854 this.filenameEdit_.value = |
| 855 ImageUtil.getDisplayNameFromName(this.selectedEntry_.name); |
826 } else if (this.context_.curDirEntry) { | 856 } else if (this.context_.curDirEntry) { |
827 // If the Gallery was opened on search results the search query will not | 857 // If the Gallery was opened on search results the search query will not |
828 // be recorded in the app state and the relaunch will just open the | 858 // be recorded in the app state and the relaunch will just open the |
829 // gallery in the curDirEntry directory. | 859 // gallery in the curDirEntry directory. |
830 window.top.document.title = this.context_.curDirEntry.name; | 860 window.top.document.title = this.context_.curDirEntry.name; |
831 displayName = strf('GALLERY_ITEMS_SELECTED', numSelectedItems); | 861 this.filenameEdit_.disabled = true; |
| 862 this.filenameEdit_.value = |
| 863 strf('GALLERY_ITEMS_SELECTED', numSelectedItems); |
832 } | 864 } |
833 } | 865 } |
834 | 866 |
835 window.top.util.updateAppState( | 867 window.top.util.updateAppState( |
836 null, // Keep the current directory. | 868 null, // Keep the current directory. |
837 selectedEntryURL, // Update the selection. | 869 selectedEntryURL, // Update the selection. |
838 {gallery: (this.currentMode_ === this.mosaicMode_ ? 'mosaic' : 'slide')}); | 870 {gallery: (this.currentMode_ === this.mosaicMode_ ? 'mosaic' : 'slide')}); |
839 | 871 |
840 // We can't rename files in readonly directory. | |
841 // We can only rename a single file. | |
842 this.filenameEdit_.disabled = numSelectedItems !== 1 || | |
843 this.context_.readonlyDirName; | |
844 this.filenameEdit_.value = displayName; | |
845 | |
846 // Update the share button. | 872 // Update the share button. |
847 var item = this.getSingleSelectedItem(); | 873 var item = this.getSingleSelectedItem(); |
848 this.shareButton_.hidden = !item || !item.isOnDrive(); | 874 this.shareButton_.hidden = !item || !item.isOnDrive(); |
849 }; | 875 }; |
850 | 876 |
851 /** | 877 /** |
852 * Click event handler on filename edit box | 878 * Click event handler on filename edit box |
853 * @private | 879 * @private |
854 */ | 880 */ |
855 Gallery.prototype.onFilenameFocus_ = function() { | 881 Gallery.prototype.onFilenameFocus_ = function() { |
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
983 window.loadTimeData.data = backgroundComponents.stringData; | 1009 window.loadTimeData.data = backgroundComponents.stringData; |
984 gallery = new Gallery(backgroundComponents.volumeManager); | 1010 gallery = new Gallery(backgroundComponents.volumeManager); |
985 }; | 1011 }; |
986 | 1012 |
987 /** | 1013 /** |
988 * Loads entries. | 1014 * Loads entries. |
989 */ | 1015 */ |
990 window.loadEntries = function(entries, selectedEntries) { | 1016 window.loadEntries = function(entries, selectedEntries) { |
991 gallery.load(entries, selectedEntries); | 1017 gallery.load(entries, selectedEntries); |
992 }; | 1018 }; |
OLD | NEW |