Backout f077ad362ca3 (bug 722859) for bustage

This commit is contained in:
Ed Morley 2012-11-16 10:44:20 +00:00
Родитель 6371de55a7
Коммит 4290399916
12 изменённых файлов: 347 добавлений и 697 удалений

Просмотреть файл

@ -269,36 +269,33 @@ Sanitizer.prototype = {
var dlMgr = Components.classes["@mozilla.org/download-manager;1"] var dlMgr = Components.classes["@mozilla.org/download-manager;1"]
.getService(Components.interfaces.nsIDownloadManager); .getService(Components.interfaces.nsIDownloadManager);
var dlsToRemove = []; var dlIDsToRemove = [];
if (this.range) { if (this.range) {
// First, remove the completed/cancelled downloads // First, remove the completed/cancelled downloads
dlMgr.removeDownloadsByTimeframe(this.range[0], this.range[1]); dlMgr.removeDownloadsByTimeframe(this.range[0], this.range[1]);
// Queue up any active downloads that started in the time span as well // Queue up any active downloads that started in the time span as well
for (let dlsEnum of [dlMgr.activeDownloads, dlMgr.activePrivateDownloads]) { var dlsEnum = dlMgr.activeDownloads;
while (dlsEnum.hasMoreElements()) { while(dlsEnum.hasMoreElements()) {
var dl = dlsEnum.next(); var dl = dlsEnum.next();
if (dl.startTime >= this.range[0]) if(dl.startTime >= this.range[0])
dlsToRemove.push(dl); dlIDsToRemove.push(dl.id);
}
} }
} }
else { else {
// Clear all completed/cancelled downloads // Clear all completed/cancelled downloads
dlMgr.cleanUp(); dlMgr.cleanUp();
dlMgr.cleanUpPrivate();
// Queue up all active ones as well // Queue up all active ones as well
for (let dlsEnum of [dlMgr.activeDownloads, dlMgr.activePrivateDownloads]) { var dlsEnum = dlMgr.activeDownloads;
while (dlsEnum.hasMoreElements()) { while(dlsEnum.hasMoreElements()) {
dlsToRemove.push(dlsEnum.next()); dlIDsToRemove.push(dlsEnum.next().id);
}
} }
} }
// Remove any queued up active downloads // Remove any queued up active downloads
dlsToRemove.forEach(function (dl) { dlIDsToRemove.forEach(function(id) {
dl.remove(); dlMgr.removeDownload(id);
}); });
}, },
@ -306,7 +303,7 @@ Sanitizer.prototype = {
{ {
var dlMgr = Components.classes["@mozilla.org/download-manager;1"] var dlMgr = Components.classes["@mozilla.org/download-manager;1"]
.getService(Components.interfaces.nsIDownloadManager); .getService(Components.interfaces.nsIDownloadManager);
return dlMgr.canCleanUp || dlMgr.canCleanUpPrivate; return dlMgr.canCleanUp;
} }
}, },

Просмотреть файл

@ -339,9 +339,6 @@ PrivateBrowsingService.prototype = {
createInstance(Ci.nsISupportsPRBool); createInstance(Ci.nsISupportsPRBool);
cancelLeave.data = false; cancelLeave.data = false;
this._obs.notifyObservers(cancelLeave, "private-browsing-cancel-vote", "exit"); this._obs.notifyObservers(cancelLeave, "private-browsing-cancel-vote", "exit");
if (!cancelLeave.data) {
this._obs.notifyObservers(cancelLeave, "last-pb-context-exiting", null);
}
return !cancelLeave.data; return !cancelLeave.data;
}, },

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -53,24 +53,30 @@ public:
static nsDownloadManager *GetSingleton(); static nsDownloadManager *GetSingleton();
virtual ~nsDownloadManager(); virtual ~nsDownloadManager();
nsDownloadManager() nsDownloadManager() :
mDBType(DATABASE_DISK)
, mInPrivateBrowsing(false)
#ifdef DOWNLOAD_SCANNER #ifdef DOWNLOAD_SCANNER
: mScanner(nullptr) , mScanner(nullptr)
#endif #endif
{ {
} }
protected: protected:
enum DatabaseType
{
DATABASE_DISK = 0, // default
DATABASE_MEMORY
};
nsresult InitDB(); nsresult InitDB();
nsresult InitFileDB(); nsresult InitFileDB();
void CloseAllDBs(); void CloseDB();
void CloseDB(mozIStorageConnection* aDBConn, nsresult InitMemoryDB();
mozIStorageStatement* aUpdateStmt,
mozIStorageStatement* aGetIdsStmt);
nsresult InitPrivateDB();
already_AddRefed<mozIStorageConnection> GetFileDBConnection(nsIFile *dbFile) const; already_AddRefed<mozIStorageConnection> GetFileDBConnection(nsIFile *dbFile) const;
already_AddRefed<mozIStorageConnection> GetPrivateDBConnection() const; already_AddRefed<mozIStorageConnection> GetMemoryDBConnection() const;
nsresult CreateTable(mozIStorageConnection* aDBConn); nsresult SwitchDatabaseTypeTo(enum DatabaseType aType);
nsresult CreateTable();
/** /**
* Fix up the database after a crash such as dealing with previously-active * Fix up the database after a crash such as dealing with previously-active
@ -87,9 +93,7 @@ protected:
nsresult GetDownloadFromDB(const nsACString& aGUID, nsDownload **retVal); nsresult GetDownloadFromDB(const nsACString& aGUID, nsDownload **retVal);
nsresult GetDownloadFromDB(uint32_t aID, nsDownload **retVal); nsresult GetDownloadFromDB(uint32_t aID, nsDownload **retVal);
nsresult GetDownloadFromDB(mozIStorageConnection* aDBConn, nsresult GetDownloadFromDB(mozIStorageStatement* stmt, nsDownload **retVal);
mozIStorageStatement* stmt,
nsDownload **retVal);
/** /**
* Specially track the active downloads so that we don't need to check * Specially track the active downloads so that we don't need to check
@ -113,23 +117,22 @@ protected:
const nsACString &aMimeType, const nsACString &aMimeType,
const nsACString &aPreferredApp, const nsACString &aPreferredApp,
nsHandlerInfoAction aPreferredAction, nsHandlerInfoAction aPreferredAction,
bool aPrivate,
nsACString &aNewGUID); nsACString &aNewGUID);
void NotifyListenersOnDownloadStateChange(int16_t aOldState, void NotifyListenersOnDownloadStateChange(int16_t aOldState,
nsDownload *aDownload); nsIDownload *aDownload);
void NotifyListenersOnProgressChange(nsIWebProgress *aProgress, void NotifyListenersOnProgressChange(nsIWebProgress *aProgress,
nsIRequest *aRequest, nsIRequest *aRequest,
int64_t aCurSelfProgress, int64_t aCurSelfProgress,
int64_t aMaxSelfProgress, int64_t aMaxSelfProgress,
int64_t aCurTotalProgress, int64_t aCurTotalProgress,
int64_t aMaxTotalProgress, int64_t aMaxTotalProgress,
nsDownload *aDownload); nsIDownload *aDownload);
void NotifyListenersOnStateChange(nsIWebProgress *aProgress, void NotifyListenersOnStateChange(nsIWebProgress *aProgress,
nsIRequest *aRequest, nsIRequest *aRequest,
uint32_t aStateFlags, uint32_t aStateFlags,
nsresult aStatus, nsresult aStatus,
nsDownload *aDownload); nsIDownload *aDownload);
nsDownload *FindDownload(const nsACString& aGUID); nsDownload *FindDownload(const nsACString& aGUID);
nsDownload *FindDownload(uint32_t aID); nsDownload *FindDownload(uint32_t aID);
@ -224,8 +227,6 @@ protected:
nsresult RemoveDownload(const nsACString& aGUID); nsresult RemoveDownload(const nsACString& aGUID);
nsresult NotifyDownloadRemoval(nsDownload* aRemoved);
// Virus scanner for windows // Virus scanner for windows
#ifdef DOWNLOAD_SCANNER #ifdef DOWNLOAD_SCANNER
private: private:
@ -233,31 +234,18 @@ private:
#endif #endif
private: private:
nsresult CleanUp(mozIStorageConnection* aDBConn);
nsresult InitStatements(mozIStorageConnection* aDBConn,
mozIStorageStatement** aUpdateStatement,
mozIStorageStatement** aGetIdsStatement);
nsresult RemoveAllDownloads(nsCOMArray<nsDownload>& aDownloads);
nsresult PauseAllDownloads(nsCOMArray<nsDownload>& aDownloads, bool aSetResume);
nsresult ResumeAllDownloads(nsCOMArray<nsDownload>& aDownloads, bool aResumeAll);
nsresult RemoveDownloadsForURI(mozIStorageStatement* aStatement, nsIURI *aURI);
bool IsInGlobalPrivateBrowsing();
nsCOMArray<nsIDownloadProgressListener> mListeners; nsCOMArray<nsIDownloadProgressListener> mListeners;
nsCOMArray<nsIDownloadProgressListener> mPrivacyAwareListeners;
nsCOMPtr<nsIStringBundle> mBundle; nsCOMPtr<nsIStringBundle> mBundle;
nsCOMPtr<mozIStorageConnection> mDBConn; nsCOMPtr<mozIStorageConnection> mDBConn;
nsCOMPtr<mozIStorageConnection> mPrivateDBConn;
nsCOMArray<nsDownload> mCurrentDownloads; nsCOMArray<nsDownload> mCurrentDownloads;
nsCOMArray<nsDownload> mCurrentPrivateDownloads;
nsCOMPtr<nsIObserverService> mObserverService; nsCOMPtr<nsIObserverService> mObserverService;
nsCOMPtr<mozIStorageStatement> mUpdateDownloadStatement; nsCOMPtr<mozIStorageStatement> mUpdateDownloadStatement;
nsCOMPtr<mozIStorageStatement> mUpdatePrivateDownloadStatement;
nsCOMPtr<mozIStorageStatement> mGetIdsForURIStatement; nsCOMPtr<mozIStorageStatement> mGetIdsForURIStatement;
nsCOMPtr<mozIStorageStatement> mGetPrivateIdsForURIStatement;
nsAutoPtr<mozStorageTransaction> mHistoryTransaction; nsAutoPtr<mozStorageTransaction> mHistoryTransaction;
enum DatabaseType mDBType;
bool mInPrivateBrowsing;
static nsDownloadManager *gDownloadManagerService; static nsDownloadManager *gDownloadManagerService;
friend class nsDownload; friend class nsDownload;

Просмотреть файл

@ -88,13 +88,7 @@ interface nsIDownload : nsITransfer {
readonly attribute nsIMIMEInfo MIMEInfo; readonly attribute nsIMIMEInfo MIMEInfo;
/** /**
* The id of the download that is stored in the database - not globally unique. * The id of the download that is stored in the database.
* For example, a private download and a public one might have identical ids.
* Can only be safely used for direct database manipulation in the database that
* contains this download. Use the guid property instead for safe, database-agnostic
* searching and manipulation.
*
* @deprecated
*/ */
readonly attribute unsigned long id; readonly attribute unsigned long id;

Просмотреть файл

@ -29,7 +29,7 @@ interface nsIDownloadManagerResult : nsISupports {
void handleResult(in nsresult aStatus, in nsIDownload aDownload); void handleResult(in nsresult aStatus, in nsIDownload aDownload);
}; };
[scriptable, uuid(b29aac15-7ec4-4ab3-a53b-08f78aed3b34)] [scriptable, uuid(c2ac096c-53f9-4ef4-85f4-b920a9cc1de5)]
interface nsIDownloadManager : nsISupports { interface nsIDownloadManager : nsISupports {
/** /**
* Download type for generic file download. * Download type for generic file download.
@ -179,14 +179,9 @@ interface nsIDownloadManager : nsISupports {
* in-progress. Whereas cancelDownload simply cancels the transfer, but * in-progress. Whereas cancelDownload simply cancels the transfer, but
* retains information about it, removeDownload removes all knowledge of it. * retains information about it, removeDownload removes all knowledge of it.
* *
* Also notifies observers of the "download-manager-remove-download-guid" * Also notifies observers of the "download-manager-remove-download" topic
* topic with the download guid as the subject to allow any DM consumers to * with the download id as the subject to allow any DM consumers to react to
* react to the removal. * the removal.
*
* Also may notify observers of the "download-manager-remove-download" topic
* with the download id as the subject, if the download removed is public
* or if global private browsing mode is in use. This notification is deprecated;
* the guid notification should be relied upon instead.
* *
* @param aID The unique ID of the download. * @param aID The unique ID of the download.
* @throws NS_ERROR_FAILURE if the download is active. * @throws NS_ERROR_FAILURE if the download is active.
@ -236,88 +231,36 @@ interface nsIDownloadManager : nsISupports {
* The database connection to the downloads database. * The database connection to the downloads database.
*/ */
readonly attribute mozIStorageConnection DBConnection; readonly attribute mozIStorageConnection DBConnection;
readonly attribute mozIStorageConnection privateDBConnection;
/** /**
* Whether or not there are downloads that can be cleaned up (removed) * Whether or not there are downloads that can be cleaned up (removed)
* i.e. downloads that have completed, have failed or have been canceled. * i.e. downloads that have completed, have failed or have been canceled.
* In global private browsing mode, this reports the status of the relevant
* private or public downloads. In per-window mode, it only reports for
* public ones.
*/ */
readonly attribute boolean canCleanUp; readonly attribute boolean canCleanUp;
/**
* Whether or not there are private downloads that can be cleaned up (removed)
* i.e. downloads that have completed, have failed or have been canceled.
*/
readonly attribute boolean canCleanUpPrivate;
/** /**
* Removes completed, failed, and canceled downloads from the list. * Removes completed, failed, and canceled downloads from the list.
* In global private browsing mode, this operates on the relevant
* private or public downloads. In per-window mode, it only operates
* on public ones.
* *
* Also notifies observers of the "download-manager-remove-download-gui" * Also notifies observers of the "download-manager-remove-download" topic
* and "download-manager-remove-download" topics with a null subject to * with a null subject to allow any DM consumers to react to the removals.
* allow any DM consumers to react to the removals.
*/ */
void cleanUp(); void cleanUp();
/**
* Removes completed, failed, and canceled downloads from the list
* of private downloads.
*
* Also notifies observers of the "download-manager-remove-download-gui"
* and "download-manager-remove-download" topics with a null subject to
* allow any DM consumers to react to the removals.
*/
void cleanUpPrivate();
/** /**
* The number of files currently being downloaded. * The number of files currently being downloaded.
*
* In global private browsing mode, this reports the status of the relevant
* private or public downloads. In per-window mode, it only reports public
* ones.
*/ */
readonly attribute long activeDownloadCount; readonly attribute long activeDownloadCount;
/**
* The number of private files currently being downloaded.
*/
readonly attribute long activePrivateDownloadCount;
/** /**
* An enumeration of active nsIDownloads * An enumeration of active nsIDownloads
*
* In global private browsing mode, this reports the status of the relevant
* private or public downloads. In per-window mode, it only reports public
* ones.
*/ */
readonly attribute nsISimpleEnumerator activeDownloads; readonly attribute nsISimpleEnumerator activeDownloads;
/** /**
* An enumeration of active private nsIDownloads * Adds a listener from the download manager.
*/
readonly attribute nsISimpleEnumerator activePrivateDownloads;
/**
* Adds a listener to the download manager. It is expected that this
* listener will only access downloads via their deprecated integer id attribute,
* and when global private browsing compatibility mode is disabled, this listener
* will receive no notifications for downloads marked private.
*/ */
void addListener(in nsIDownloadProgressListener aListener); void addListener(in nsIDownloadProgressListener aListener);
/**
* Adds a listener to the download manager. This listener must be able to
* understand and use the guid attribute of downloads for all interactions
* with the download manager.
*/
void addPrivacyAwareListener(in nsIDownloadProgressListener aListener);
/** /**
* Removes a listener from the download manager. * Removes a listener from the download manager.
*/ */

Просмотреть файл

@ -89,15 +89,15 @@ function run_test()
// Look for the removed download notification // Look for the removed download notification
let obs = Cc["@mozilla.org/observer-service;1"]. let obs = Cc["@mozilla.org/observer-service;1"].
getService(Ci.nsIObserverService); getService(Ci.nsIObserverService);
const kRemoveTopic = "download-manager-remove-download-guid"; const kRemoveTopic = "download-manager-remove-download";
let testObs = { let testObs = {
observe: function(aSubject, aTopic, aData) { observe: function(aSubject, aTopic, aData) {
if (aTopic != kRemoveTopic) if (aTopic != kRemoveTopic)
return; return;
// Make sure the removed/expired download was the one we added // Make sure the removed/expired download was the one we added
let id = aSubject.QueryInterface(Ci.nsISupportsCString); let id = aSubject.QueryInterface(Ci.nsISupportsPRUint32);
do_check_eq(id.data, theGUID); do_check_eq(id.data, theId);
// We're done! // We're done!
histobs.onEndUpdateBatch(); histobs.onEndUpdateBatch();

Просмотреть файл

@ -0,0 +1,52 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// This tests the switching of the download manager database types between disk
// and memory based databases. This feature was added in bug 457110.
const nsIDownloadManager = Ci.nsIDownloadManager;
const dm = Cc["@mozilla.org/download-manager;1"].getService(nsIDownloadManager);
function run_test() {
let observer = dm.QueryInterface(Ci.nsIObserver);
// make sure the initial disk-based DB is initialized correctly
let connDisk = dm.DBConnection;
do_check_true(connDisk.connectionReady);
do_check_neq(connDisk.databaseFile, null);
// switch to a disk DB -- should be a no-op
observer.observe(null, "dlmgr-switchdb", "disk");
// make sure that the database has not changed
do_check_true(dm.DBConnection.connectionReady);
do_check_neq(dm.DBConnection.databaseFile, null);
do_check_true(connDisk.databaseFile.equals(dm.DBConnection.databaseFile));
connDisk = dm.DBConnection;
let oldFile = connDisk.databaseFile;
// switch to a memory DB
observer.observe(null, "dlmgr-switchdb", "memory");
// make sure the DB is has been switched correctly
let connMemory = dm.DBConnection;
do_check_true(connMemory.connectionReady);
do_check_eq(connMemory.databaseFile, null);
// switch to a memory DB -- should be a no-op
observer.observe(null, "dlmgr-switchdb", "memory");
// make sure that the database is still memory based
connMemory = dm.DBConnection;
do_check_true(connMemory.connectionReady);
do_check_eq(connMemory.databaseFile, null);
// switch back to the disk DB
observer.observe(null, "dlmgr-switchdb", "disk");
// make sure that the disk database is initialized correctly
do_check_true(dm.DBConnection.connectionReady);
do_check_neq(dm.DBConnection.databaseFile, null);
do_check_true(oldFile.equals(dm.DBConnection.databaseFile));
}

Просмотреть файл

@ -207,9 +207,6 @@ function run_test() {
do_check_true(promptService.wasCalled()); do_check_true(promptService.wasCalled());
do_check_false(pb.privateBrowsingEnabled); do_check_false(pb.privateBrowsingEnabled);
// Simulate leaving PB mode
Services.obs.notifyObservers(null, "last-pb-context-exited", null);
// Check that Download-F is canceled and not accessible // Check that Download-F is canceled and not accessible
do_check_eq(dlF.state, dm.DOWNLOAD_PAUSED); do_check_eq(dlF.state, dm.DOWNLOAD_PAUSED);

Просмотреть файл

@ -19,6 +19,7 @@ skip-if = os == "android"
skip-if = os == "android" skip-if = os == "android"
[test_guid.js] [test_guid.js]
[test_history_expiration.js] [test_history_expiration.js]
[test_memory_db_support.js]
[test_offline_support.js] [test_offline_support.js]
[test_old_download_files_removed.js] [test_old_download_files_removed.js]
[test_private_resume.js] [test_private_resume.js]

Просмотреть файл

@ -101,41 +101,36 @@ this.ForgetAboutSite = {
let (dm = Cc["@mozilla.org/download-manager;1"]. let (dm = Cc["@mozilla.org/download-manager;1"].
getService(Ci.nsIDownloadManager)) { getService(Ci.nsIDownloadManager)) {
// Active downloads // Active downloads
for (let enumerator of [dm.activeDownloads, dm.activePrivateDownloads]) { let enumerator = dm.activeDownloads;
while (enumerator.hasMoreElements()) { while (enumerator.hasMoreElements()) {
let dl = enumerator.getNext().QueryInterface(Ci.nsIDownload); let dl = enumerator.getNext().QueryInterface(Ci.nsIDownload);
if (hasRootDomain(dl.source.host, aDomain)) { if (hasRootDomain(dl.source.host, aDomain)) {
dl.cancel(); dm.cancelDownload(dl.id);
dl.remove(); dm.removeDownload(dl.id);
}
}
}
function deleteAllLike(db) {
// NOTE: This is lossy, but we feel that it is OK to be lossy here and not
// invoke the cost of creating a URI for each download entry and
// ensure that the hostname matches.
let stmt = db.createStatement(
"DELETE FROM moz_downloads " +
"WHERE source LIKE ?1 ESCAPE '/' " +
"AND state NOT IN (?2, ?3, ?4)"
);
let pattern = stmt.escapeStringForLIKE(aDomain, "/");
stmt.bindByIndex(0, "%" + pattern + "%");
stmt.bindByIndex(1, Ci.nsIDownloadManager.DOWNLOAD_DOWNLOADING);
stmt.bindByIndex(2, Ci.nsIDownloadManager.DOWNLOAD_PAUSED);
stmt.bindByIndex(3, Ci.nsIDownloadManager.DOWNLOAD_QUEUED);
try {
stmt.execute();
}
finally {
stmt.finalize();
} }
} }
// Completed downloads // Completed downloads
deleteAllLike(dm.DBConnection); let db = dm.DBConnection;
deleteAllLike(dm.privateDBConnection); // NOTE: This is lossy, but we feel that it is OK to be lossy here and not
// invoke the cost of creating a URI for each download entry and
// ensure that the hostname matches.
let stmt = db.createStatement(
"DELETE FROM moz_downloads " +
"WHERE source LIKE ?1 ESCAPE '/' " +
"AND state NOT IN (?2, ?3, ?4)"
);
let pattern = stmt.escapeStringForLIKE(aDomain, "/");
stmt.bindByIndex(0, "%" + pattern + "%");
stmt.bindByIndex(1, Ci.nsIDownloadManager.DOWNLOAD_DOWNLOADING);
stmt.bindByIndex(2, Ci.nsIDownloadManager.DOWNLOAD_PAUSED);
stmt.bindByIndex(3, Ci.nsIDownloadManager.DOWNLOAD_QUEUED);
try {
stmt.execute();
}
finally {
stmt.finalize();
}
// We want to rebuild the list if the UI is showing, so dispatch the // We want to rebuild the list if the UI is showing, so dispatch the
// observer topic // observer topic

Просмотреть файл

@ -22,7 +22,6 @@ cannotPause=This download cannot be paused
downloadErrorAlertTitle=Download Error downloadErrorAlertTitle=Download Error
downloadErrorGeneric=The download cannot be saved because an unknown error occurred.\n\nPlease try again. downloadErrorGeneric=The download cannot be saved because an unknown error occurred.\n\nPlease try again.
# LOCALIZATION NOTE: we don't have proper plural support in the CPP code; bug 463102
quitCancelDownloadsAlertTitle=Cancel All Downloads? quitCancelDownloadsAlertTitle=Cancel All Downloads?
quitCancelDownloadsAlertMsg=If you exit now, 1 download will be canceled. Are you sure you want to exit? quitCancelDownloadsAlertMsg=If you exit now, 1 download will be canceled. Are you sure you want to exit?
quitCancelDownloadsAlertMsgMultiple=If you exit now, %S downloads will be canceled. Are you sure you want to exit? quitCancelDownloadsAlertMsgMultiple=If you exit now, %S downloads will be canceled. Are you sure you want to exit?
@ -37,8 +36,6 @@ enterPrivateBrowsingCancelDownloadsAlertMsgMultiple=If you enter the Private Bro
leavePrivateBrowsingCancelDownloadsAlertTitle=Cancel All Downloads? leavePrivateBrowsingCancelDownloadsAlertTitle=Cancel All Downloads?
leavePrivateBrowsingCancelDownloadsAlertMsg=If you leave the Private Browsing mode now, 1 download will be canceled. Are you sure you want to leave the Private Browsing mode? leavePrivateBrowsingCancelDownloadsAlertMsg=If you leave the Private Browsing mode now, 1 download will be canceled. Are you sure you want to leave the Private Browsing mode?
leavePrivateBrowsingCancelDownloadsAlertMsgMultiple=If you leave the Private Browsing mode now, %S downloads will be canceled. Are you sure you want to leave the Private Browsing mode? leavePrivateBrowsingCancelDownloadsAlertMsgMultiple=If you leave the Private Browsing mode now, %S downloads will be canceled. Are you sure you want to leave the Private Browsing mode?
leavePrivateBrowsingWindowsCancelDownloadsAlertMsg=If you close all Private Browsing windows now, 1 download will be canceled. Are you sure you want to leave the Private Browsing mode?
leavePrivateBrowsingWindowsCancelDownloadsAlertMsgMultiple=If you close all Private Browsing windows now, %S downloads will be canceled. Are you sure you want to leave the Private Browsing mode?
cancelDownloadsOKText=Cancel 1 Download cancelDownloadsOKText=Cancel 1 Download
cancelDownloadsOKTextMultiple=Cancel %S Downloads cancelDownloadsOKTextMultiple=Cancel %S Downloads
dontQuitButtonWin=Don't Exit dontQuitButtonWin=Don't Exit