OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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 #include "chrome/browser/download/download_manager.h" | 5 #include "chrome/browser/download/download_manager.h" |
6 | 6 |
7 #include "base/callback.h" | 7 #include "base/callback.h" |
8 #include "base/file_util.h" | 8 #include "base/file_util.h" |
9 #include "base/i18n/case_conversion.h" | 9 #include "base/i18n/case_conversion.h" |
10 #include "base/logging.h" | 10 #include "base/logging.h" |
(...skipping 22 matching lines...) Expand all Loading... |
33 #include "chrome/browser/profiles/profile.h" | 33 #include "chrome/browser/profiles/profile.h" |
34 #include "chrome/browser/tab_contents/tab_util.h" | 34 #include "chrome/browser/tab_contents/tab_util.h" |
35 #include "chrome/common/chrome_paths.h" | 35 #include "chrome/common/chrome_paths.h" |
36 #include "chrome/common/pref_names.h" | 36 #include "chrome/common/pref_names.h" |
37 #include "content/browser/browser_thread.h" | 37 #include "content/browser/browser_thread.h" |
38 #include "content/browser/renderer_host/render_process_host.h" | 38 #include "content/browser/renderer_host/render_process_host.h" |
39 #include "content/browser/renderer_host/render_view_host.h" | 39 #include "content/browser/renderer_host/render_view_host.h" |
40 #include "content/browser/renderer_host/resource_dispatcher_host.h" | 40 #include "content/browser/renderer_host/resource_dispatcher_host.h" |
41 #include "content/browser/tab_contents/tab_contents.h" | 41 #include "content/browser/tab_contents/tab_contents.h" |
42 #include "content/common/content_notification_types.h" | 42 #include "content/common/content_notification_types.h" |
| 43 #include "content/common/notification_service.h" |
43 #include "googleurl/src/gurl.h" | 44 #include "googleurl/src/gurl.h" |
44 #include "grit/generated_resources.h" | 45 #include "grit/generated_resources.h" |
45 #include "grit/theme_resources.h" | 46 #include "grit/theme_resources.h" |
46 #include "net/base/mime_util.h" | 47 #include "net/base/mime_util.h" |
47 #include "net/base/net_util.h" | 48 #include "net/base/net_util.h" |
48 #include "ui/base/l10n/l10n_util.h" | 49 #include "ui/base/l10n/l10n_util.h" |
49 #include "ui/base/resource/resource_bundle.h" | 50 #include "ui/base/resource/resource_bundle.h" |
50 | 51 |
51 DownloadManager::DownloadManager(DownloadManagerDelegate* delegate, | 52 DownloadManager::DownloadManager(DownloadManagerDelegate* delegate, |
52 DownloadStatusUpdater* status_updater) | 53 DownloadStatusUpdater* status_updater) |
53 : shutdown_needed_(false), | 54 : shutdown_needed_(false), |
54 profile_(NULL), | 55 profile_(NULL), |
55 file_manager_(NULL), | 56 file_manager_(NULL), |
56 status_updater_(status_updater->AsWeakPtr()), | 57 status_updater_(status_updater->AsWeakPtr()), |
| 58 next_save_page_id_(0), |
57 delegate_(delegate) { | 59 delegate_(delegate) { |
58 if (status_updater_) | 60 if (status_updater_) |
59 status_updater_->AddDelegate(this); | 61 status_updater_->AddDelegate(this); |
60 } | 62 } |
61 | 63 |
62 DownloadManager::~DownloadManager() { | 64 DownloadManager::~DownloadManager() { |
63 DCHECK(!shutdown_needed_); | 65 DCHECK(!shutdown_needed_); |
64 if (status_updater_) | 66 if (status_updater_) |
65 status_updater_->RemoveDelegate(this); | 67 status_updater_->RemoveDelegate(this); |
66 } | 68 } |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
115 // anything left. | 117 // anything left. |
116 | 118 |
117 // Copy downloads_ to separate container so as not to set off checks | 119 // Copy downloads_ to separate container so as not to set off checks |
118 // in DownloadItem destruction. | 120 // in DownloadItem destruction. |
119 DownloadSet downloads_to_delete; | 121 DownloadSet downloads_to_delete; |
120 downloads_to_delete.swap(downloads_); | 122 downloads_to_delete.swap(downloads_); |
121 | 123 |
122 in_progress_.clear(); | 124 in_progress_.clear(); |
123 active_downloads_.clear(); | 125 active_downloads_.clear(); |
124 history_downloads_.clear(); | 126 history_downloads_.clear(); |
125 #if !defined(NDEBUG) | |
126 save_page_as_downloads_.clear(); | |
127 #endif | |
128 STLDeleteElements(&downloads_to_delete); | 127 STLDeleteElements(&downloads_to_delete); |
129 | 128 |
| 129 DCHECK(save_page_downloads_.empty()); |
| 130 |
130 file_manager_ = NULL; | 131 file_manager_ = NULL; |
131 | 132 |
132 download_history_.reset(); | 133 download_history_.reset(); |
133 download_prefs_.reset(); | 134 download_prefs_.reset(); |
134 | 135 |
135 shutdown_needed_ = false; | 136 shutdown_needed_ = false; |
136 } | 137 } |
137 | 138 |
138 void DownloadManager::GetTemporaryDownloads( | 139 void DownloadManager::GetTemporaryDownloads( |
139 const FilePath& dir_path, std::vector<DownloadItem*>* result) { | 140 const FilePath& dir_path, DownloadVector* result) { |
140 DCHECK(result); | 141 DCHECK(result); |
141 | 142 |
142 for (DownloadMap::iterator it = history_downloads_.begin(); | 143 for (DownloadMap::iterator it = history_downloads_.begin(); |
143 it != history_downloads_.end(); ++it) { | 144 it != history_downloads_.end(); ++it) { |
144 if (it->second->is_temporary() && | 145 if (it->second->is_temporary() && |
145 it->second->full_path().DirName() == dir_path) | 146 it->second->full_path().DirName() == dir_path) |
146 result->push_back(it->second); | 147 result->push_back(it->second); |
147 } | 148 } |
148 } | 149 } |
149 | 150 |
150 void DownloadManager::GetAllDownloads( | 151 void DownloadManager::GetAllDownloads( |
151 const FilePath& dir_path, std::vector<DownloadItem*>* result) { | 152 const FilePath& dir_path, DownloadVector* result) { |
152 DCHECK(result); | 153 DCHECK(result); |
153 | 154 |
154 for (DownloadMap::iterator it = history_downloads_.begin(); | 155 for (DownloadMap::iterator it = history_downloads_.begin(); |
155 it != history_downloads_.end(); ++it) { | 156 it != history_downloads_.end(); ++it) { |
156 if (!it->second->is_temporary() && | 157 if (!it->second->is_temporary() && |
157 (dir_path.empty() || it->second->full_path().DirName() == dir_path)) | 158 (dir_path.empty() || it->second->full_path().DirName() == dir_path)) |
158 result->push_back(it->second); | 159 result->push_back(it->second); |
159 } | 160 } |
160 } | 161 } |
161 | 162 |
162 void DownloadManager::GetCurrentDownloads( | 163 void DownloadManager::GetCurrentDownloads( |
163 const FilePath& dir_path, std::vector<DownloadItem*>* result) { | 164 const FilePath& dir_path, DownloadVector* result) { |
164 DCHECK(result); | 165 DCHECK(result); |
165 | 166 |
166 for (DownloadMap::iterator it = history_downloads_.begin(); | 167 for (DownloadMap::iterator it = history_downloads_.begin(); |
167 it != history_downloads_.end(); ++it) { | 168 it != history_downloads_.end(); ++it) { |
168 DownloadItem* item =it->second; | 169 DownloadItem* item =it->second; |
169 // Skip temporary items. | 170 // Skip temporary items. |
170 if (item->is_temporary()) | 171 if (item->is_temporary()) |
171 continue; | 172 continue; |
172 // Skip items that have all their data, and are OK to save. | 173 // Skip items that have all their data, and are OK to save. |
173 if (!item->IsPartialDownload() && | 174 if (!item->IsPartialDownload() && |
174 (item->safety_state() != DownloadItem::DANGEROUS)) | 175 (item->safety_state() != DownloadItem::DANGEROUS)) |
175 continue; | 176 continue; |
176 // Skip items that don't match |dir_path|. | 177 // Skip items that don't match |dir_path|. |
177 // If |dir_path| is empty, all remaining items match. | 178 // If |dir_path| is empty, all remaining items match. |
178 if (!dir_path.empty() && (it->second->full_path().DirName() != dir_path)) | 179 if (!dir_path.empty() && (it->second->full_path().DirName() != dir_path)) |
179 continue; | 180 continue; |
180 | 181 |
181 result->push_back(item); | 182 result->push_back(item); |
182 } | 183 } |
183 | 184 |
184 // If we have a parent profile, let it add its downloads to the results. | 185 // If we have a parent profile, let it add its downloads to the results. |
185 Profile* original_profile = profile_->GetOriginalProfile(); | 186 Profile* original_profile = profile_->GetOriginalProfile(); |
186 if (original_profile != profile_) | 187 if (original_profile != profile_) |
187 original_profile->GetDownloadManager()->GetCurrentDownloads(dir_path, | 188 original_profile->GetDownloadManager()->GetCurrentDownloads(dir_path, |
188 result); | 189 result); |
189 } | 190 } |
190 | 191 |
191 void DownloadManager::SearchDownloads(const string16& query, | 192 void DownloadManager::SearchDownloads(const string16& query, |
192 std::vector<DownloadItem*>* result) { | 193 DownloadVector* result) { |
193 DCHECK(result); | 194 DCHECK(result); |
194 | 195 |
195 string16 query_lower(base::i18n::ToLower(query)); | 196 string16 query_lower(base::i18n::ToLower(query)); |
196 | 197 |
197 for (DownloadMap::iterator it = history_downloads_.begin(); | 198 for (DownloadMap::iterator it = history_downloads_.begin(); |
198 it != history_downloads_.end(); ++it) { | 199 it != history_downloads_.end(); ++it) { |
199 DownloadItem* download_item = it->second; | 200 DownloadItem* download_item = it->second; |
200 | 201 |
201 if (download_item->is_temporary() || download_item->is_extension_install()) | 202 if (download_item->is_temporary() || download_item->is_extension_install()) |
202 continue; | 203 continue; |
(...skipping 667 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
870 BrowserThread::FILE, FROM_HERE, | 871 BrowserThread::FILE, FROM_HERE, |
871 NewRunnableMethod( | 872 NewRunnableMethod( |
872 file_manager_, &DownloadFileManager::CancelDownload, download_id)); | 873 file_manager_, &DownloadFileManager::CancelDownload, download_id)); |
873 } | 874 } |
874 | 875 |
875 void DownloadManager::UpdateAppIcon() { | 876 void DownloadManager::UpdateAppIcon() { |
876 if (status_updater_) | 877 if (status_updater_) |
877 status_updater_->Update(); | 878 status_updater_->Update(); |
878 } | 879 } |
879 | 880 |
| 881 int DownloadManager::RemoveDownloadItems( |
| 882 const DownloadVector& pending_deletes) { |
| 883 if (pending_deletes.empty()) |
| 884 return 0; |
| 885 |
| 886 // Delete from internal maps. |
| 887 for (DownloadVector::const_iterator it = pending_deletes.begin(); |
| 888 it != pending_deletes.end(); |
| 889 ++it) { |
| 890 DownloadItem* download = *it; |
| 891 DCHECK(download); |
| 892 history_downloads_.erase(download->db_handle()); |
| 893 save_page_downloads_.erase(download->id()); |
| 894 downloads_.erase(download); |
| 895 } |
| 896 |
| 897 // Tell observers to refresh their views. |
| 898 NotifyModelChanged(); |
| 899 |
| 900 // Delete the download items themselves. |
| 901 const int num_deleted = static_cast<int>(pending_deletes.size()); |
| 902 STLDeleteContainerPointers(pending_deletes.begin(), pending_deletes.end()); |
| 903 return num_deleted; |
| 904 } |
| 905 |
880 void DownloadManager::RemoveDownload(int64 download_handle) { | 906 void DownloadManager::RemoveDownload(int64 download_handle) { |
881 DownloadMap::iterator it = history_downloads_.find(download_handle); | 907 DownloadMap::iterator it = history_downloads_.find(download_handle); |
882 if (it == history_downloads_.end()) | 908 if (it == history_downloads_.end()) |
883 return; | 909 return; |
884 | 910 |
885 // Make history update. | 911 // Make history update. |
886 DownloadItem* download = it->second; | 912 DownloadItem* download = it->second; |
887 download_history_->RemoveEntry(download); | 913 download_history_->RemoveEntry(download); |
888 | 914 |
889 // Remove from our tables and delete. | 915 // Remove from our tables and delete. |
890 history_downloads_.erase(it); | 916 int downloads_count = RemoveDownloadItems(DownloadVector(1, download)); |
891 int downloads_count = downloads_.erase(download); | |
892 DCHECK_EQ(1, downloads_count); | 917 DCHECK_EQ(1, downloads_count); |
893 | |
894 // Tell observers to refresh their views. | |
895 NotifyModelChanged(); | |
896 | |
897 delete download; | |
898 } | 918 } |
899 | 919 |
900 int DownloadManager::RemoveDownloadsBetween(const base::Time remove_begin, | 920 int DownloadManager::RemoveDownloadsBetween(const base::Time remove_begin, |
901 const base::Time remove_end) { | 921 const base::Time remove_end) { |
902 download_history_->RemoveEntriesBetween(remove_begin, remove_end); | 922 download_history_->RemoveEntriesBetween(remove_begin, remove_end); |
903 | 923 |
904 // All downloads visible to the user will be in the history, | 924 // All downloads visible to the user will be in the history, |
905 // so scan that map. | 925 // so scan that map. |
906 DownloadMap::iterator it = history_downloads_.begin(); | 926 DownloadVector pending_deletes; |
907 std::vector<DownloadItem*> pending_deletes; | 927 for (DownloadMap::const_iterator it = history_downloads_.begin(); |
908 while (it != history_downloads_.end()) { | 928 it != history_downloads_.end(); |
| 929 ++it) { |
909 DownloadItem* download = it->second; | 930 DownloadItem* download = it->second; |
910 if (download->start_time() >= remove_begin && | 931 if (download->start_time() >= remove_begin && |
911 (remove_end.is_null() || download->start_time() < remove_end) && | 932 (remove_end.is_null() || download->start_time() < remove_end) && |
912 (download->IsComplete() || | 933 (download->IsComplete() || download->IsCancelled())) { |
913 download->IsCancelled() || | |
914 download->IsInterrupted())) { | |
915 AssertQueueStateConsistent(download); | 934 AssertQueueStateConsistent(download); |
916 | |
917 // Remove from the map and move to the next in the list. | |
918 history_downloads_.erase(it++); | |
919 | |
920 // Also remove it from any completed dangerous downloads. | |
921 pending_deletes.push_back(download); | 935 pending_deletes.push_back(download); |
922 | |
923 continue; | |
924 } | 936 } |
925 | |
926 ++it; | |
927 } | 937 } |
928 | 938 return RemoveDownloadItems(pending_deletes); |
929 // If we aren't deleting anything, we're done. | |
930 if (pending_deletes.empty()) | |
931 return 0; | |
932 | |
933 // Remove the chosen downloads from the main owning container. | |
934 for (std::vector<DownloadItem*>::iterator it = pending_deletes.begin(); | |
935 it != pending_deletes.end(); it++) { | |
936 downloads_.erase(*it); | |
937 } | |
938 | |
939 // Tell observers to refresh their views. | |
940 NotifyModelChanged(); | |
941 | |
942 // Delete the download items themselves. | |
943 int num_deleted = static_cast<int>(pending_deletes.size()); | |
944 | |
945 STLDeleteContainerPointers(pending_deletes.begin(), pending_deletes.end()); | |
946 pending_deletes.clear(); | |
947 | |
948 return num_deleted; | |
949 } | 939 } |
950 | 940 |
951 int DownloadManager::RemoveDownloads(const base::Time remove_begin) { | 941 int DownloadManager::RemoveDownloads(const base::Time remove_begin) { |
952 return RemoveDownloadsBetween(remove_begin, base::Time()); | 942 return RemoveDownloadsBetween(remove_begin, base::Time()); |
953 } | 943 } |
954 | 944 |
955 int DownloadManager::RemoveAllDownloads() { | 945 int DownloadManager::RemoveAllDownloads() { |
956 if (this != profile_->GetOriginalProfile()->GetDownloadManager()) { | 946 if (this != profile_->GetOriginalProfile()->GetDownloadManager()) { |
957 // This is an incognito downloader. Clear All should clear main download | 947 // This is an incognito downloader. Clear All should clear main download |
958 // manager as well. | 948 // manager as well. |
959 profile_->GetOriginalProfile()->GetDownloadManager()->RemoveAllDownloads(); | 949 profile_->GetOriginalProfile()->GetDownloadManager()->RemoveAllDownloads(); |
960 } | 950 } |
961 // The null times make the date range unbounded. | 951 // The null times make the date range unbounded. |
962 return RemoveDownloadsBetween(base::Time(), base::Time()); | 952 return RemoveDownloadsBetween(base::Time(), base::Time()); |
963 } | 953 } |
964 | 954 |
965 void DownloadManager::SavePageAsDownloadStarted(DownloadItem* download) { | |
966 #if !defined(NDEBUG) | |
967 save_page_as_downloads_.insert(download); | |
968 #endif | |
969 downloads_.insert(download); | |
970 // Add to history and notify observers. | |
971 AddDownloadItemToHistory(download, DownloadHistory::kUninitializedHandle); | |
972 NotifyModelChanged(); | |
973 } | |
974 | |
975 // Initiate a download of a specific URL. We send the request to the | 955 // Initiate a download of a specific URL. We send the request to the |
976 // ResourceDispatcherHost, and let it send us responses like a regular | 956 // ResourceDispatcherHost, and let it send us responses like a regular |
977 // download. | 957 // download. |
978 void DownloadManager::DownloadUrl(const GURL& url, | 958 void DownloadManager::DownloadUrl(const GURL& url, |
979 const GURL& referrer, | 959 const GURL& referrer, |
980 const std::string& referrer_charset, | 960 const std::string& referrer_charset, |
981 TabContents* tab_contents) { | 961 TabContents* tab_contents) { |
982 DownloadUrlToFile(url, referrer, referrer_charset, DownloadSaveInfo(), | 962 DownloadUrlToFile(url, referrer, referrer_charset, DownloadSaveInfo(), |
983 tab_contents); | 963 tab_contents); |
984 } | 964 } |
(...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1158 | 1138 |
1159 // TODO(rdsmith): Convert to DCHECK() when http://crbug.com/84508 | 1139 // TODO(rdsmith): Convert to DCHECK() when http://crbug.com/84508 |
1160 // is fixed. | 1140 // is fixed. |
1161 CHECK_NE(DownloadHistory::kUninitializedHandle, db_handle); | 1141 CHECK_NE(DownloadHistory::kUninitializedHandle, db_handle); |
1162 | 1142 |
1163 DCHECK(download->db_handle() == DownloadHistory::kUninitializedHandle); | 1143 DCHECK(download->db_handle() == DownloadHistory::kUninitializedHandle); |
1164 download->set_db_handle(db_handle); | 1144 download->set_db_handle(db_handle); |
1165 | 1145 |
1166 DCHECK(!ContainsKey(history_downloads_, download->db_handle())); | 1146 DCHECK(!ContainsKey(history_downloads_, download->db_handle())); |
1167 history_downloads_[download->db_handle()] = download; | 1147 history_downloads_[download->db_handle()] = download; |
| 1148 |
| 1149 // Show in the appropriate browser UI. |
| 1150 // This includes buttons to save or cancel, for a dangerous download. |
| 1151 ShowDownloadInBrowser(download); |
| 1152 |
| 1153 // Inform interested objects about the new download. |
| 1154 NotifyModelChanged(); |
1168 } | 1155 } |
1169 | 1156 |
1170 // Once the new DownloadItem's creation info has been committed to the history | 1157 // Once the new DownloadItem's creation info has been committed to the history |
1171 // service, we associate the DownloadItem with the db handle, update our | 1158 // service, we associate the DownloadItem with the db handle, update our |
1172 // 'history_downloads_' map and inform observers. | 1159 // 'history_downloads_' map and inform observers. |
1173 void DownloadManager::OnCreateDownloadEntryComplete(int32 download_id, | 1160 void DownloadManager::OnCreateDownloadEntryComplete(int32 download_id, |
1174 int64 db_handle) { | 1161 int64 db_handle) { |
1175 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 1162 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
1176 DownloadItem* download = GetActiveDownloadItem(download_id); | 1163 DownloadItem* download = GetActiveDownloadItem(download_id); |
1177 if (!download) | 1164 if (!download) |
1178 return; | 1165 return; |
1179 | 1166 |
1180 VLOG(20) << __FUNCTION__ << "()" << " db_handle = " << db_handle | 1167 VLOG(20) << __FUNCTION__ << "()" << " db_handle = " << db_handle |
1181 << " download_id = " << download_id | 1168 << " download_id = " << download_id |
1182 << " download = " << download->DebugString(true); | 1169 << " download = " << download->DebugString(true); |
1183 | 1170 |
1184 AddDownloadItemToHistory(download, db_handle); | 1171 AddDownloadItemToHistory(download, db_handle); |
1185 | 1172 |
1186 // Show in the appropriate browser UI. | |
1187 // This includes buttons to save or cancel, for a dangerous download. | |
1188 ShowDownloadInBrowser(download); | |
1189 | |
1190 // Inform interested objects about the new download. | |
1191 NotifyModelChanged(); | |
1192 | |
1193 // If the download is still in progress, try to complete it. | 1173 // If the download is still in progress, try to complete it. |
1194 // | 1174 // |
1195 // Otherwise, download has been cancelled or interrupted before we've | 1175 // Otherwise, download has been cancelled or interrupted before we've |
1196 // received the DB handle. We post one final message to the history | 1176 // received the DB handle. We post one final message to the history |
1197 // service so that it can be properly in sync with the DownloadItem's | 1177 // service so that it can be properly in sync with the DownloadItem's |
1198 // completion status, and also inform any observers so that they get | 1178 // completion status, and also inform any observers so that they get |
1199 // more than just the start notification. | 1179 // more than just the start notification. |
1200 if (download->IsInProgress()) { | 1180 if (download->IsInProgress()) { |
1201 MaybeCompleteDownload(download); | 1181 MaybeCompleteDownload(download); |
1202 } else { | 1182 } else { |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1250 DownloadItem* download = active_downloads_[download_id]; | 1230 DownloadItem* download = active_downloads_[download_id]; |
1251 DCHECK(download != NULL); | 1231 DCHECK(download != NULL); |
1252 return download; | 1232 return download; |
1253 } | 1233 } |
1254 | 1234 |
1255 // Confirm that everything in all maps is also in |downloads_|, and that | 1235 // Confirm that everything in all maps is also in |downloads_|, and that |
1256 // everything in |downloads_| is also in some other map. | 1236 // everything in |downloads_| is also in some other map. |
1257 void DownloadManager::AssertContainersConsistent() const { | 1237 void DownloadManager::AssertContainersConsistent() const { |
1258 #if !defined(NDEBUG) | 1238 #if !defined(NDEBUG) |
1259 // Turn everything into sets. | 1239 // Turn everything into sets. |
1260 DownloadSet active_set, history_set; | 1240 const DownloadMap* input_maps[] = {&active_downloads_, |
1261 const DownloadMap* input_maps[] = {&active_downloads_, &history_downloads_}; | 1241 &history_downloads_, |
1262 DownloadSet* local_sets[] = {&active_set, &history_set}; | 1242 &save_page_downloads_}; |
1263 DCHECK_EQ(ARRAYSIZE_UNSAFE(input_maps), ARRAYSIZE_UNSAFE(local_sets)); | 1243 DownloadSet active_set, history_set, save_page_set; |
| 1244 DownloadSet* all_sets[] = {&active_set, &history_set, &save_page_set}; |
| 1245 DCHECK_EQ(ARRAYSIZE_UNSAFE(input_maps), ARRAYSIZE_UNSAFE(all_sets)); |
1264 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(input_maps); i++) { | 1246 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(input_maps); i++) { |
1265 for (DownloadMap::const_iterator it = input_maps[i]->begin(); | 1247 for (DownloadMap::const_iterator it = input_maps[i]->begin(); |
1266 it != input_maps[i]->end(); it++) { | 1248 it != input_maps[i]->end(); ++it) { |
1267 local_sets[i]->insert(&*it->second); | 1249 all_sets[i]->insert(&*it->second); |
1268 } | 1250 } |
1269 } | 1251 } |
1270 | 1252 |
1271 // Check if each set is fully present in downloads, and create a union. | 1253 // Check if each set is fully present in downloads, and create a union. |
1272 const DownloadSet* all_sets[] = {&active_set, &history_set, | |
1273 &save_page_as_downloads_}; | |
1274 DownloadSet downloads_union; | 1254 DownloadSet downloads_union; |
1275 for (int i = 0; i < static_cast<int>(ARRAYSIZE_UNSAFE(all_sets)); i++) { | 1255 for (int i = 0; i < static_cast<int>(ARRAYSIZE_UNSAFE(all_sets)); i++) { |
1276 DownloadSet remainder; | 1256 DownloadSet remainder; |
1277 std::insert_iterator<DownloadSet> insert_it(remainder, remainder.begin()); | 1257 std::insert_iterator<DownloadSet> insert_it(remainder, remainder.begin()); |
1278 std::set_difference(all_sets[i]->begin(), all_sets[i]->end(), | 1258 std::set_difference(all_sets[i]->begin(), all_sets[i]->end(), |
1279 downloads_.begin(), downloads_.end(), | 1259 downloads_.begin(), downloads_.end(), |
1280 insert_it); | 1260 insert_it); |
1281 DCHECK(remainder.empty()); | 1261 DCHECK(remainder.empty()); |
1282 std::insert_iterator<DownloadSet> | 1262 std::insert_iterator<DownloadSet> |
1283 insert_union(downloads_union, downloads_union.end()); | 1263 insert_union(downloads_union, downloads_union.end()); |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1318 observed_download_manager_->RemoveObserver(this); | 1298 observed_download_manager_->RemoveObserver(this); |
1319 } | 1299 } |
1320 | 1300 |
1321 void DownloadManager::OtherDownloadManagerObserver::ModelChanged() { | 1301 void DownloadManager::OtherDownloadManagerObserver::ModelChanged() { |
1322 observing_download_manager_->NotifyModelChanged(); | 1302 observing_download_manager_->NotifyModelChanged(); |
1323 } | 1303 } |
1324 | 1304 |
1325 void DownloadManager::OtherDownloadManagerObserver::ManagerGoingDown() { | 1305 void DownloadManager::OtherDownloadManagerObserver::ManagerGoingDown() { |
1326 observed_download_manager_ = NULL; | 1306 observed_download_manager_ = NULL; |
1327 } | 1307 } |
| 1308 |
| 1309 void DownloadManager::SavePageDownloadStarted(DownloadItem* download) { |
| 1310 DCHECK(!ContainsKey(save_page_downloads_, download->id())); |
| 1311 downloads_.insert(download); |
| 1312 save_page_downloads_[download->id()] = download; |
| 1313 |
| 1314 // Add this entry to the history service. |
| 1315 // Additionally, the UI is notified in the callback. |
| 1316 download_history_->AddEntry(download, |
| 1317 NewCallback(this, &DownloadManager::OnSavePageDownloadEntryAdded)); |
| 1318 } |
| 1319 |
| 1320 // SavePackage will call SavePageDownloadFinished upon completion/cancellation. |
| 1321 // The history callback will call OnSavePageDownloadEntryAdded. |
| 1322 // If the download finishes before the history callback, |
| 1323 // OnSavePageDownloadEntryAdded calls SavePageDownloadFinished, ensuring that |
| 1324 // the history event is update regardless of the order in which these two events |
| 1325 // complete. |
| 1326 // If something removes the download item from the download manager (Remove, |
| 1327 // Shutdown) the result will be that the SavePage system will not be able to |
| 1328 // properly update the download item (which no longer exists) or the download |
| 1329 // history, but the action will complete properly anyway. This may lead to the |
| 1330 // history entry being wrong on a reload of chrome (specifically in the case of |
| 1331 // Initiation -> History Callback -> Removal -> Completion), but there's no way |
| 1332 // to solve that without canceling on Remove (which would then update the DB). |
| 1333 |
| 1334 void DownloadManager::OnSavePageDownloadEntryAdded(int32 download_id, |
| 1335 int64 db_handle) { |
| 1336 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 1337 |
| 1338 DownloadMap::const_iterator it = save_page_downloads_.find(download_id); |
| 1339 // This can happen if the download manager is shutting down and all maps |
| 1340 // have been cleared. |
| 1341 if (it == save_page_downloads_.end()) |
| 1342 return; |
| 1343 |
| 1344 DownloadItem* download = it->second; |
| 1345 if (!download) { |
| 1346 NOTREACHED(); |
| 1347 return; |
| 1348 } |
| 1349 |
| 1350 AddDownloadItemToHistory(download, db_handle); |
| 1351 |
| 1352 // Finalize this download if it finished before the history callback. |
| 1353 if (!download->IsInProgress()) |
| 1354 SavePageDownloadFinished(download); |
| 1355 } |
| 1356 |
| 1357 void DownloadManager::SavePageDownloadFinished(DownloadItem* download) { |
| 1358 if (download->db_handle() != DownloadHistory::kUninitializedHandle) { |
| 1359 download_history_->UpdateEntry(download); |
| 1360 DCHECK(ContainsKey(save_page_downloads_, download->id())); |
| 1361 save_page_downloads_.erase(download->id()); |
| 1362 |
| 1363 if (download->IsComplete()) |
| 1364 NotificationService::current()->Notify( |
| 1365 content::NOTIFICATION_SAVE_PACKAGE_SUCCESSFULLY_FINISHED, |
| 1366 Source<DownloadManager>(this), |
| 1367 Details<DownloadItem>(download)); |
| 1368 } |
| 1369 } |
| 1370 |
| 1371 int32 DownloadManager::GetNextSavePageId() { |
| 1372 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 1373 return next_save_page_id_++; |
| 1374 } |
| 1375 |
OLD | NEW |