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 // If directory files changes too often, don't rescan directory more than once | 5 // If directory files changes too often, don't rescan directory more than once |
6 // per specified interval | 6 // per specified interval |
7 const SIMULTANEOUS_RESCAN_INTERVAL = 1000; | 7 const SIMULTANEOUS_RESCAN_INTERVAL = 1000; |
8 | 8 |
9 /** | 9 /** |
10 * Data model of the file manager. | 10 * Data model of the file manager. |
(...skipping 550 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
561 }, | 561 }, |
562 | 562 |
563 /** | 563 /** |
564 * Change the state of the model to reflect the specified path (either a | 564 * Change the state of the model to reflect the specified path (either a |
565 * file or directory). | 565 * file or directory). |
566 * | 566 * |
567 * @param {string} path The root path to use | 567 * @param {string} path The root path to use |
568 * @param {Function=} opt_loadedCallback Invoked when the entire directory | 568 * @param {Function=} opt_loadedCallback Invoked when the entire directory |
569 * has been loaded and any default file selected. If there are any | 569 * has been loaded and any default file selected. If there are any |
570 * errors loading the directory this will not get called (even if the | 570 * errors loading the directory this will not get called (even if the |
571 * directory loads OK on retry later). | 571 * directory loads OK on retry later). Will NOT be called if another |
572 * directory change happened while setupPath was in progress. | |
572 * @param {Function=} opt_pathResolveCallback Invoked as soon as the path has | 573 * @param {Function=} opt_pathResolveCallback Invoked as soon as the path has |
573 * been resolved, and called with the base and leaf portions of the path | 574 * been resolved, and called with the base and leaf portions of the path |
574 * name, and a flag indicating if the entry exists. | 575 * name, and a flag indicating if the entry exists. Will be called even |
576 * if another directory change happened while setupPath was in progress, | |
577 * but will pass |false| as |exist| parameter. | |
575 */ | 578 */ |
576 setupPath: function(path, opt_loadedCallback, opt_pathResolveCallback) { | 579 setupPath: function(path, opt_loadedCallback, opt_pathResolveCallback) { |
580 var overridden = false; | |
581 function onExternalDirChange() { overridden = true } | |
582 this.addEventListener('directory-changed', onExternalDirChange); | |
583 | |
584 var resolveCallback = function(exists) { | |
585 this.removeEventListener('directory-changed', onExternalDirChange); | |
586 if (opt_pathResolveCallback) | |
587 opt_pathResolveCallback(baseName, leafName, exists && !overridden); | |
dgozman
2012/03/28 10:28:30
Why do we call this in the case of overridden?
Vladislav Kaznacheev
2012/03/28 14:00:57
Because the client might have to do some cleanup (
| |
588 }.bind(this); | |
589 | |
590 var changeDirectoryEntry = function (entry, callback, initial, exists) { | |
dgozman
2012/03/28 10:28:30
space before (
Vladislav Kaznacheev
2012/03/28 14:00:57
Done.
| |
591 resolveCallback(exists); | |
592 if (!overridden) | |
593 this.changeDirectoryEntry_(entry, callback, initial); | |
594 }.bind(this); | |
595 | |
596 var INITIAL = true; | |
597 var EXISTS = true; | |
598 | |
577 // Split the dirname from the basename. | 599 // Split the dirname from the basename. |
578 var ary = path.match(/^(?:(.*)\/)?([^\/]*)$/); | 600 var ary = path.match(/^(?:(.*)\/)?([^\/]*)$/); |
579 var autoSelect = function() { | 601 var autoSelect = function() { |
580 this.selectIndex(this.autoSelectIndex_); | 602 this.selectIndex(this.autoSelectIndex_); |
581 if (opt_loadedCallback) | 603 if (opt_loadedCallback) |
582 opt_loadedCallback(); | 604 opt_loadedCallback(); |
583 }.bind(this); | 605 }.bind(this); |
584 | 606 |
585 if (!ary) { | 607 if (!ary) { |
586 console.warn('Unable to split default path: ' + path); | 608 console.warn('Unable to split default path: ' + path); |
587 this.changeDirectoryEntry_(this.root_, autoSelect, true); | 609 changeDirectoryEntry(this.root_, autoSelect, INITIAL, !EXISTS); |
dgozman
2012/03/28 10:28:30
resolveCallback was not called here before. Bug?
Vladislav Kaznacheev
2012/03/28 14:00:57
Yes, it was a but (there was another one in onBase
| |
588 return; | 610 return; |
589 } | 611 } |
590 | 612 |
591 var baseName = ary[1]; | 613 var baseName = ary[1]; |
592 var leafName = ary[2]; | 614 var leafName = ary[2]; |
593 | 615 |
594 function resolveCallback(exists) { | |
595 if (opt_pathResolveCallback) | |
596 opt_pathResolveCallback(baseName, leafName, exists); | |
597 } | |
598 | |
599 function onLeafFound(baseDirEntry, leafEntry) { | 616 function onLeafFound(baseDirEntry, leafEntry) { |
600 if (leafEntry.isDirectory) { | 617 if (leafEntry.isDirectory) { |
601 baseName = path; | 618 baseName = path; |
602 leafName = ''; | 619 leafName = ''; |
603 resolveCallback(true); | 620 changeDirectoryEntry(leafEntry, autoSelect, INITIAL, EXISTS); |
604 this.changeDirectoryEntry_(leafEntry, autoSelect, true); | |
605 return; | 621 return; |
606 } | 622 } |
607 | 623 |
608 resolveCallback(true); | |
609 // Leaf is an existing file, cd to its parent directory and select it. | 624 // Leaf is an existing file, cd to its parent directory and select it. |
610 this.changeDirectoryEntry_(baseDirEntry, | 625 changeDirectoryEntry(baseDirEntry, |
611 function() { | 626 function() { |
612 this.selectEntry(leafEntry.name); | 627 this.selectEntry(leafEntry.name); |
613 if (opt_loadedCallback) | 628 if (opt_loadedCallback) |
614 opt_loadedCallback(); | 629 opt_loadedCallback(); |
615 }.bind(this), | 630 }.bind(this), |
616 false /*HACK*/); | 631 !INITIAL /*HACK*/, |
632 EXISTS); | |
617 // TODO(kaznacheev): Fix history.replaceState for the File Browser and | 633 // TODO(kaznacheev): Fix history.replaceState for the File Browser and |
618 // change the last parameter back to |true|. Passing |false| makes things | 634 // change !INITIAL to INITIAL. Passing |false| makes things |
619 // less ugly for now. | 635 // less ugly for now. |
620 } | 636 } |
621 | 637 |
622 function onLeafError(baseDirEntry, err) { | 638 function onLeafError(baseDirEntry, err) { |
623 resolveCallback(false); | |
624 // Usually, leaf does not exist, because it's just a suggested file name. | 639 // Usually, leaf does not exist, because it's just a suggested file name. |
625 if (err.code != FileError.NOT_FOUND_ERR) | 640 if (err.code != FileError.NOT_FOUND_ERR) |
626 console.log('Unexpected error resolving default leaf: ' + err); | 641 console.log('Unexpected error resolving default leaf: ' + err); |
627 this.changeDirectoryEntry_(baseDirEntry, autoSelect, true); | 642 changeDirectoryEntry(baseDirEntry, autoSelect, INITIAL, !EXISTS); |
628 } | 643 } |
629 | 644 |
630 var onBaseError = function(err) { | 645 var onBaseError = function(err) { |
631 resolveCallback(false); | |
632 console.log('Unexpected error resolving default base "' + | 646 console.log('Unexpected error resolving default base "' + |
633 baseName + '": ' + err); | 647 baseName + '": ' + err); |
634 if (path != '/' + DirectoryModel.DOWNLOADS_DIRECTORY) { | 648 if (path != '/' + DirectoryModel.DOWNLOADS_DIRECTORY) { |
635 // Can't find the provided path, let's go to default one instead. | 649 // Can't find the provided path, let's go to default one instead. |
636 this.setupDefaultPath(opt_loadedCallback); | 650 resolveCallback(!EXISTS); |
651 if (!overridden) | |
652 this.setupDefaultPath(opt_loadedCallback); | |
637 } else { | 653 } else { |
638 // Well, we can't find the downloads dir. Let's just show something, | 654 // Well, we can't find the downloads dir. Let's just show something, |
639 // or we will get an infinite recursion. | 655 // or we will get an infinite recursion. |
640 this.changeDirectoryEntry_(this.root_, opt_loadedCallback, true); | 656 changeDirectoryEntry(this.root_, opt_loadedCallback, INITIAL, !EXISTS); |
641 } | 657 } |
642 }.bind(this); | 658 }.bind(this); |
643 | 659 |
644 var onBaseFound = function(baseDirEntry) { | 660 var onBaseFound = function(baseDirEntry) { |
645 if (!leafName) { | 661 if (!leafName) { |
646 // Default path is just a directory, cd to it and we're done. | 662 // Default path is just a directory, cd to it and we're done. |
647 this.changeDirectoryEntry_(baseDirEntry, autoSelect, true); | 663 changeDirectoryEntry(baseDirEntry, autoSelect, INITIAL, !EXISTS); |
648 return; | 664 return; |
649 } | 665 } |
650 | 666 |
651 util.resolvePath(this.root_, path, | 667 util.resolvePath(this.root_, path, |
652 onLeafFound.bind(this, baseDirEntry), | 668 onLeafFound.bind(this, baseDirEntry), |
653 onLeafError.bind(this, baseDirEntry)); | 669 onLeafError.bind(this, baseDirEntry)); |
654 }.bind(this); | 670 }.bind(this); |
655 | 671 |
656 var root = this.root_; | 672 var root = this.root_; |
657 if (baseName) { | 673 if (baseName) { |
658 root.getDirectory( | 674 root.getDirectory( |
659 baseName, {create: false}, onBaseFound, onBaseError); | 675 baseName, {create: false}, onBaseFound, onBaseError); |
660 } else { | 676 } else { |
661 this.getDefaultDirectory_(function(defaultDir) { | 677 this.getDefaultDirectory_(function(defaultDir) { |
662 baseName = defaultDir; | 678 baseName = defaultDir; |
663 root.getDirectory( | 679 root.getDirectory( |
664 baseName, {create: false}, onBaseFound, onBaseError); | 680 baseName, {create: false}, onBaseFound, onBaseError); |
665 }); | 681 }); |
666 } | 682 } |
667 }, | 683 }, |
668 | 684 |
669 setupDefaultPath: function(opt_callback) { | 685 setupDefaultPath: function(opt_callback) { |
686 var overridden = false; | |
687 function onExternalDirChange() { overridden = true } | |
688 this.addEventListener('directory-changed', onExternalDirChange); | |
689 | |
670 this.getDefaultDirectory_(function(path) { | 690 this.getDefaultDirectory_(function(path) { |
671 this.setupPath(path, opt_callback); | 691 this.removeEventListener('directory-changed', onExternalDirChange); |
692 if (!overridden) | |
693 this.setupPath(path, opt_callback); | |
672 }.bind(this)); | 694 }.bind(this)); |
673 }, | 695 }, |
674 | 696 |
675 getDefaultDirectory_: function(callback) { | 697 getDefaultDirectory_: function(callback) { |
676 function onGetDirectoryComplete(entries, error) { | 698 function onGetDirectoryComplete(entries, error) { |
677 if (entries.length > 0) | 699 if (entries.length > 0) |
678 callback(entries[0].fullPath); | 700 callback(entries[0].fullPath); |
679 else | 701 else |
680 callback('/' + DirectoryModel.DOWNLOADS_DIRECTORY); | 702 callback('/' + DirectoryModel.DOWNLOADS_DIRECTORY); |
681 } | 703 } |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
747 function onCacheDone() { | 769 function onCacheDone() { |
748 waitCount--; | 770 waitCount--; |
749 // If all caching functions finished synchronously or entries.length = 0 | 771 // If all caching functions finished synchronously or entries.length = 0 |
750 // call the callback synchronously. | 772 // call the callback synchronously. |
751 if (waitCount == 0) | 773 if (waitCount == 0) |
752 setTimeout(callback, 0); | 774 setTimeout(callback, 0); |
753 } | 775 } |
754 }, | 776 }, |
755 | 777 |
756 /** | 778 /** |
757 * Get root entries asynchronously. Invokes callback | 779 * Get root entries asynchronously. |
758 * when have finished. | 780 * @param {function(Array.<Entry>} callback Called when roots are resolved. |
781 * @param {boolean} resolveGData See comment for updateRoots. | |
759 */ | 782 */ |
760 resolveRoots_: function(callback) { | 783 resolveRoots_: function(callback, resolveGData) { |
761 var groups = { | 784 var groups = { |
762 downloads: null, | 785 downloads: null, |
763 archives: null, | 786 archives: null, |
764 removables: null, | 787 removables: null, |
765 gdata: null | 788 gdata: null |
766 }; | 789 }; |
767 | 790 |
768 metrics.startInterval('Load.Roots'); | 791 metrics.startInterval('Load.Roots'); |
769 function done() { | 792 function done() { |
770 for (var i in groups) | 793 for (var i in groups) |
(...skipping 18 matching lines...) Expand all Loading... | |
789 } | 812 } |
790 | 813 |
791 function onDownloadsError(error) { | 814 function onDownloadsError(error) { |
792 groups.downloads = []; | 815 groups.downloads = []; |
793 done(); | 816 done(); |
794 } | 817 } |
795 | 818 |
796 var self = this; | 819 var self = this; |
797 | 820 |
798 function onGData(entry) { | 821 function onGData(entry) { |
799 console.log('onGData'); | 822 console.log('GData found:', entry); |
800 console.log(entry); | |
801 self.unmountedGDataEntry_ = null; | 823 self.unmountedGDataEntry_ = null; |
802 groups.gdata = [entry]; | 824 groups.gdata = [entry]; |
803 done(); | 825 done(); |
804 } | 826 } |
805 | 827 |
806 function onGDataError(error) { | 828 function onGDataError(error) { |
807 console.log('onGDataError'); | 829 console.log('GData error: ', error); |
808 console.log(error); | |
809 self.unmountedGDataEntry_ = { | 830 self.unmountedGDataEntry_ = { |
831 unmounted: true, // Clients use this field to distinguish a fake root. | |
832 toURL: function() { return '' }, | |
810 fullPath: '/' + DirectoryModel.GDATA_DIRECTORY | 833 fullPath: '/' + DirectoryModel.GDATA_DIRECTORY |
811 }; | 834 }; |
812 groups.gdata = [self.unmountedGDataEntry_]; | 835 groups.gdata = [self.unmountedGDataEntry_]; |
813 done(); | 836 done(); |
814 } | 837 } |
815 | 838 |
816 var root = this.root_; | 839 var root = this.root_; |
817 root.getDirectory(DirectoryModel.DOWNLOADS_DIRECTORY, { create: false }, | 840 root.getDirectory(DirectoryModel.DOWNLOADS_DIRECTORY, { create: false }, |
818 onDownloads, onDownloadsError); | 841 onDownloads, onDownloadsError); |
819 util.readDirectory(root, DirectoryModel.ARCHIVE_DIRECTORY, | 842 util.readDirectory(root, DirectoryModel.ARCHIVE_DIRECTORY, |
820 append.bind(this, 'archives')); | 843 append.bind(this, 'archives')); |
821 util.readDirectory(root, DirectoryModel.REMOVABLE_DIRECTORY, | 844 util.readDirectory(root, DirectoryModel.REMOVABLE_DIRECTORY, |
822 append.bind(this, 'removables')); | 845 append.bind(this, 'removables')); |
823 if (this.showGData_) { | 846 if (this.showGData_) { |
824 root.getDirectory(DirectoryModel.GDATA_DIRECTORY, { create: false }, | 847 if (resolveGData) { |
825 onGData, onGDataError); | 848 root.getDirectory(DirectoryModel.GDATA_DIRECTORY, { create: false }, |
849 onGData, onGDataError); | |
850 } else { | |
851 onGDataError('lazy mount'); | |
852 } | |
826 } else { | 853 } else { |
827 groups.gdata = []; | 854 groups.gdata = []; |
828 } | 855 } |
829 }, | 856 }, |
830 | 857 |
831 updateRoots: function(opt_callback) { | 858 /** |
832 console.log('directoryModel_.updateRoots'); | 859 * @param {function} opt_callback Called when all roots are resolved. |
860 * @param {boolean} opt_resolveGData If true GData should be resolved for real, | |
861 * If false a stub entry should be created. | |
862 */ | |
863 updateRoots: function(opt_callback, opt_resolveGData) { | |
864 console.log('resolving roots'); | |
833 var self = this; | 865 var self = this; |
834 this.resolveRoots_(function(rootEntries) { | 866 this.resolveRoots_(function(rootEntries) { |
835 console.log('rootsList_ = '); | 867 console.log('resolved roots:', rootEntries); |
836 console.log(self.rootsList_); | |
837 var dm = self.rootsList_; | 868 var dm = self.rootsList_; |
838 var args = [0, dm.length].concat(rootEntries); | 869 var args = [0, dm.length].concat(rootEntries); |
839 dm.splice.apply(dm, args); | 870 dm.splice.apply(dm, args); |
840 | 871 |
841 self.updateRootsListSelection_(); | 872 self.updateRootsListSelection_(); |
842 | 873 |
843 if (opt_callback) | 874 if (opt_callback) |
844 opt_callback(); | 875 opt_callback(); |
845 }); | 876 }, opt_resolveGData); |
846 }, | 877 }, |
847 | 878 |
848 onRootsSelectionChanged_: function(event) { | 879 onRootsSelectionChanged_: function(event) { |
849 var root = this.rootsList.item(this.rootsListSelection.selectedIndex); | 880 var root = this.rootsList.item(this.rootsListSelection.selectedIndex); |
850 var current = this.currentEntry.fullPath; | |
851 if (root && this.rootPath != root.fullPath) | 881 if (root && this.rootPath != root.fullPath) |
852 this.changeDirectory(root.fullPath); | 882 this.changeDirectory(root.fullPath); |
853 }, | 883 }, |
854 | 884 |
855 updateRootsListSelection_: function() { | 885 updateRootsListSelection_: function() { |
856 var roots = this.rootsList_; | 886 var roots = this.rootsList_; |
857 var rootPath = this.rootPath; | 887 var rootPath = this.rootPath; |
858 for (var index = 0; index < roots.length; index++) { | 888 for (var index = 0; index < roots.length; index++) { |
859 if (roots.item(index).fullPath == rootPath) { | 889 if (roots.item(index).fullPath == rootPath) { |
860 this.rootsListSelection.selectedIndex = index; | 890 this.rootsListSelection.selectedIndex = index; |
(...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
990 | 1020 |
991 recordMetrics_: function() { | 1021 recordMetrics_: function() { |
992 metrics.recordInterval('DirectoryScan'); | 1022 metrics.recordInterval('DirectoryScan'); |
993 if (this.dir_.fullPath == | 1023 if (this.dir_.fullPath == |
994 '/' + DirectoryModel.DOWNLOADS_DIRECTORY) { | 1024 '/' + DirectoryModel.DOWNLOADS_DIRECTORY) { |
995 metrics.recordMediumCount("DownloadsCount", this.list_.length); | 1025 metrics.recordMediumCount("DownloadsCount", this.list_.length); |
996 } | 1026 } |
997 } | 1027 } |
998 }; | 1028 }; |
999 | 1029 |
OLD | NEW |