| 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 |