Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(4656)

Unified Diff: chrome/browser/download/download_manager.cc

Issue 7277073: Support for adding save page download items into downloads history. (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 9 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/download/download_manager.cc
===================================================================
--- chrome/browser/download/download_manager.cc (revision 94744)
+++ chrome/browser/download/download_manager.cc (working copy)
@@ -40,6 +40,7 @@
#include "content/browser/renderer_host/resource_dispatcher_host.h"
#include "content/browser/tab_contents/tab_contents.h"
#include "content/common/content_notification_types.h"
+#include "content/common/notification_service.h"
#include "googleurl/src/gurl.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
@@ -52,7 +53,8 @@
: shutdown_needed_(false),
profile_(NULL),
file_manager_(NULL),
- status_updater_(status_updater->AsWeakPtr()) {
+ status_updater_(status_updater->AsWeakPtr()),
+ next_save_page_id_(0) {
if (status_updater_)
status_updater_->AddDelegate(this);
}
@@ -120,11 +122,10 @@
in_progress_.clear();
active_downloads_.clear();
history_downloads_.clear();
-#if !defined(NDEBUG)
- save_page_as_downloads_.clear();
-#endif
STLDeleteElements(&downloads_to_delete);
+ DCHECK(save_page_downloads_.empty());
+
file_manager_ = NULL;
download_history_.reset();
@@ -134,7 +135,7 @@
}
void DownloadManager::GetTemporaryDownloads(
- const FilePath& dir_path, std::vector<DownloadItem*>* result) {
+ const FilePath& dir_path, DownloadVector* result) {
DCHECK(result);
for (DownloadMap::iterator it = history_downloads_.begin();
@@ -146,7 +147,7 @@
}
void DownloadManager::GetAllDownloads(
- const FilePath& dir_path, std::vector<DownloadItem*>* result) {
+ const FilePath& dir_path, DownloadVector* result) {
DCHECK(result);
for (DownloadMap::iterator it = history_downloads_.begin();
@@ -158,7 +159,7 @@
}
void DownloadManager::GetCurrentDownloads(
- const FilePath& dir_path, std::vector<DownloadItem*>* result) {
+ const FilePath& dir_path, DownloadVector* result) {
DCHECK(result);
for (DownloadMap::iterator it = history_downloads_.begin();
@@ -187,7 +188,7 @@
}
void DownloadManager::SearchDownloads(const string16& query,
- std::vector<DownloadItem*>* result) {
+ DownloadVector* result) {
DCHECK(result);
string16 query_lower(base::i18n::ToLower(query));
@@ -875,6 +876,31 @@
status_updater_->Update();
}
+int DownloadManager::RemoveDownloadItems(
+ const DownloadVector& pending_deletes) {
+ if (pending_deletes.empty())
+ return 0;
+
+ // Delete from internal maps.
+ for (DownloadVector::const_iterator it = pending_deletes.begin();
+ it != pending_deletes.end();
+ ++it) {
+ DownloadItem* download = *it;
+ DCHECK(download);
+ history_downloads_.erase(download->db_handle());
+ save_page_downloads_.erase(download->id());
+ downloads_.erase(download);
+ }
+
+ // Tell observers to refresh their views.
+ NotifyModelChanged();
+
+ // Delete the download items themselves.
+ const int num_deleted = static_cast<int>(pending_deletes.size());
+ STLDeleteContainerPointers(pending_deletes.begin(), pending_deletes.end());
+ return num_deleted;
+}
+
void DownloadManager::RemoveDownload(int64 download_handle) {
DownloadMap::iterator it = history_downloads_.find(download_handle);
if (it == history_downloads_.end())
@@ -885,14 +911,8 @@
download_history_->RemoveEntry(download);
// Remove from our tables and delete.
- history_downloads_.erase(it);
- int downloads_count = downloads_.erase(download);
+ int downloads_count = RemoveDownloadItems(DownloadVector(1, download));
DCHECK_EQ(1, downloads_count);
-
- // Tell observers to refresh their views.
- NotifyModelChanged();
-
- delete download;
}
int DownloadManager::RemoveDownloadsBetween(const base::Time remove_begin,
@@ -901,49 +921,19 @@
// All downloads visible to the user will be in the history,
// so scan that map.
- DownloadMap::iterator it = history_downloads_.begin();
- std::vector<DownloadItem*> pending_deletes;
- while (it != history_downloads_.end()) {
+ DownloadVector pending_deletes;
+ for (DownloadMap::const_iterator it = history_downloads_.begin();
+ it != history_downloads_.end();
+ ++it) {
DownloadItem* download = it->second;
if (download->start_time() >= remove_begin &&
(remove_end.is_null() || download->start_time() < remove_end) &&
- (download->IsComplete() ||
- download->IsCancelled() ||
- download->IsInterrupted())) {
+ (download->IsComplete() || download->IsCancelled())) {
AssertQueueStateConsistent(download);
-
- // Remove from the map and move to the next in the list.
- history_downloads_.erase(it++);
-
- // Also remove it from any completed dangerous downloads.
pending_deletes.push_back(download);
-
- continue;
}
-
- ++it;
}
-
- // If we aren't deleting anything, we're done.
- if (pending_deletes.empty())
- return 0;
-
- // Remove the chosen downloads from the main owning container.
- for (std::vector<DownloadItem*>::iterator it = pending_deletes.begin();
- it != pending_deletes.end(); it++) {
- downloads_.erase(*it);
- }
-
- // Tell observers to refresh their views.
- NotifyModelChanged();
-
- // Delete the download items themselves.
- int num_deleted = static_cast<int>(pending_deletes.size());
-
- STLDeleteContainerPointers(pending_deletes.begin(), pending_deletes.end());
- pending_deletes.clear();
-
- return num_deleted;
+ return RemoveDownloadItems(pending_deletes);
}
int DownloadManager::RemoveDownloads(const base::Time remove_begin) {
@@ -960,16 +950,6 @@
return RemoveDownloadsBetween(base::Time(), base::Time());
}
-void DownloadManager::SavePageAsDownloadStarted(DownloadItem* download) {
-#if !defined(NDEBUG)
- save_page_as_downloads_.insert(download);
-#endif
- downloads_.insert(download);
- // Add to history and notify observers.
- AddDownloadItemToHistory(download, DownloadHistory::kUninitializedHandle);
- NotifyModelChanged();
-}
-
// Initiate a download of a specific URL. We send the request to the
// ResourceDispatcherHost, and let it send us responses like a regular
// download.
@@ -1163,6 +1143,13 @@
DCHECK(!ContainsKey(history_downloads_, download->db_handle()));
history_downloads_[download->db_handle()] = download;
+
+ // Show in the appropriate browser UI.
+ // This includes buttons to save or cancel, for a dangerous download.
+ ShowDownloadInBrowser(download);
+
+ // Inform interested objects about the new download.
+ NotifyModelChanged();
}
// Once the new DownloadItem's creation info has been committed to the history
@@ -1181,13 +1168,6 @@
AddDownloadItemToHistory(download, db_handle);
- // Show in the appropriate browser UI.
- // This includes buttons to save or cancel, for a dangerous download.
- ShowDownloadInBrowser(download);
-
- // Inform interested objects about the new download.
- NotifyModelChanged();
-
// If the download is still in progress, try to complete it.
//
// Otherwise, download has been cancelled or interrupted before we've
@@ -1257,20 +1237,20 @@
void DownloadManager::AssertContainersConsistent() const {
#if !defined(NDEBUG)
// Turn everything into sets.
- DownloadSet active_set, history_set;
- const DownloadMap* input_maps[] = {&active_downloads_, &history_downloads_};
- DownloadSet* local_sets[] = {&active_set, &history_set};
- DCHECK_EQ(ARRAYSIZE_UNSAFE(input_maps), ARRAYSIZE_UNSAFE(local_sets));
+ const DownloadMap* input_maps[] = {&active_downloads_,
+ &history_downloads_,
+ &save_page_downloads_};
+ DownloadSet active_set, history_set, save_page_set;
+ DownloadSet* all_sets[] = {&active_set, &history_set, &save_page_set};
+ DCHECK_EQ(ARRAYSIZE_UNSAFE(input_maps), ARRAYSIZE_UNSAFE(all_sets));
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(input_maps); i++) {
for (DownloadMap::const_iterator it = input_maps[i]->begin();
- it != input_maps[i]->end(); it++) {
- local_sets[i]->insert(&*it->second);
+ it != input_maps[i]->end(); ++it) {
+ all_sets[i]->insert(&*it->second);
}
}
// Check if each set is fully present in downloads, and create a union.
- const DownloadSet* all_sets[] = {&active_set, &history_set,
- &save_page_as_downloads_};
DownloadSet downloads_union;
for (int i = 0; i < static_cast<int>(ARRAYSIZE_UNSAFE(all_sets)); i++) {
DownloadSet remainder;
@@ -1325,3 +1305,71 @@
void DownloadManager::OtherDownloadManagerObserver::ManagerGoingDown() {
observed_download_manager_ = NULL;
}
+
+void DownloadManager::SavePageDownloadStarted(DownloadItem* download) {
+ DCHECK(!ContainsKey(save_page_downloads_, download->id()));
+ downloads_.insert(download);
+ save_page_downloads_[download->id()] = download;
+
+ // Add this entry to the history service.
+ // Additionally, the UI is notified in the callback.
+ download_history_->AddEntry(download,
+ NewCallback(this, &DownloadManager::OnSavePageDownloadEntryAdded));
+}
+
+// SavePackage will call SavePageDownloadFinished upon completion/cancellation.
+// The history callback will call OnSavePageDownloadEntryAdded.
+// If the download finishes before the history callback,
+// OnSavePageDownloadEntryAdded calls SavePageDownloadFinished, ensuring that
+// the history event is update regardless of the order in which these two events
+// complete.
+// If something removes the download item from the download manager (Remove,
+// Shutdown) the result will be that the SavePage system will not be able to
+// properly update the download item (which no longer exists) or the download
+// history, but the action will complete properly anyway. This may lead to the
+// history entry being wrong on a reload of chrome (specifically in the case of
+// Initiation -> History Callback -> Removal -> Completion), but there's no way
+// to solve that without canceling on Remove (which would then update the DB).
+
+void DownloadManager::OnSavePageDownloadEntryAdded(int32 download_id,
+ int64 db_handle) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ DownloadMap::const_iterator it = save_page_downloads_.find(download_id);
+ // This can happen if the download manager is shutting down and all maps
+ // have been cleared.
+ if (it == save_page_downloads_.end())
+ return;
+
+ DownloadItem* download = it->second;
+ if (!download) {
+ NOTREACHED();
+ return;
+ }
+
+ AddDownloadItemToHistory(download, db_handle);
+
+ // Finalize this download if it finished before the history callback.
+ if (!download->IsInProgress())
+ SavePageDownloadFinished(download);
+}
+
+void DownloadManager::SavePageDownloadFinished(DownloadItem* download) {
+ if (download->db_handle() != DownloadHistory::kUninitializedHandle) {
+ download_history_->UpdateEntry(download);
+ DCHECK(ContainsKey(save_page_downloads_, download->id()));
+ save_page_downloads_.erase(download->id());
+
+ if (download->IsComplete())
+ NotificationService::current()->Notify(
+ content::NOTIFICATION_SAVE_PACKAGE_SUCCESSFULLY_FINISHED,
+ Source<DownloadManager>(this),
+ Details<DownloadItem>(download));
+ }
+}
+
+int32 DownloadManager::GetNextSavePageId() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ return next_save_page_id_++;
+}
+

Powered by Google App Engine
This is Rietveld 408576698