Bug 899110 - Remove the code to switch between different back-ends from the Downloads Panel. r=enn

This commit is contained in:
Paolo Amadini 2013-11-04 19:21:13 +01:00
Родитель 85da3f1250
Коммит 147dff90bb
13 изменённых файлов: 115 добавлений и 1280 удалений

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

@ -351,18 +351,8 @@ pref("browser.download.debug", false);
pref("browser.download.saveLinkAsFilenameTimeout", 4000);
pref("browser.download.useDownloadDir", true);
pref("browser.download.folderList", 1);
pref("browser.download.manager.showAlertOnComplete", true);
pref("browser.download.manager.showAlertInterval", 2000);
pref("browser.download.manager.retention", 2);
pref("browser.download.manager.showWhenStarting", true);
pref("browser.download.manager.closeWhenDone", false);
pref("browser.download.manager.focusWhenStarting", false);
pref("browser.download.manager.flashCount", 2);
pref("browser.download.manager.addToRecentDocs", true);
pref("browser.download.manager.quitBehavior", 0);
pref("browser.download.manager.scanWhenDone", true);
pref("browser.download.manager.resumeOnWakeDelay", 10000);
// This allows disabling the animated notifications shown by
@ -372,10 +362,6 @@ pref("browser.download.animateNotifications", true);
// This records whether or not the panel has been shown at least once.
pref("browser.download.panel.shown", false);
// This records whether or not at least one session with the Downloads Panel
// enabled has been completed already.
pref("browser.download.panel.firstSessionCompleted", false);
#ifndef XP_MACOSX
pref("browser.helperApps.deleteTempFileOnExit", true);
#endif
@ -1019,10 +1005,6 @@ pref("services.sync.prefs.sync.addons.ignoreUserEnabledChanges", true);
// source, and this would propagate automatically to other,
// uncompromised Sync-connected devices.
pref("services.sync.prefs.sync.app.update.mode", true);
pref("services.sync.prefs.sync.browser.download.manager.closeWhenDone", true);
pref("services.sync.prefs.sync.browser.download.manager.retention", true);
pref("services.sync.prefs.sync.browser.download.manager.scanWhenDone", true);
pref("services.sync.prefs.sync.browser.download.manager.showWhenStarting", true);
pref("services.sync.prefs.sync.browser.formfill.enable", true);
pref("services.sync.prefs.sync.browser.link.open_newwindow", true);
pref("services.sync.prefs.sync.browser.offline-apps.notify", true);

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

@ -1084,24 +1084,13 @@ var gBrowserInit = {
// auto-resume downloads begin (such as after crashing or quitting with
// active downloads) and speeds up the first-load of the download manager UI.
// If the user manually opens the download manager before the timeout, the
// downloads will start right away, and getting the service again won't hurt.
// downloads will start right away, and initializing again won't hurt.
setTimeout(function() {
try {
let DownloadsCommon =
Cu.import("resource:///modules/DownloadsCommon.jsm", {}).DownloadsCommon;
if (DownloadsCommon.useJSTransfer) {
// Open the data link without initalizing nsIDownloadManager.
DownloadsCommon.initializeAllDataLinks();
let DownloadsTaskbar =
Cu.import("resource:///modules/DownloadsTaskbar.jsm", {}).DownloadsTaskbar;
DownloadsTaskbar.registerIndicator(window);
} else {
// Initalizing nsIDownloadManager will trigger the data link.
Services.downloads;
let DownloadTaskbarProgress =
Cu.import("resource://gre/modules/DownloadTaskbarProgress.jsm", {}).DownloadTaskbarProgress;
DownloadTaskbarProgress.onBrowserWindowLoad(window);
}
Cu.import("resource:///modules/DownloadsCommon.jsm", {})
.DownloadsCommon.initializeAllDataLinks();
Cu.import("resource:///modules/DownloadsTaskbar.jsm", {})
.DownloadsTaskbar.registerIndicator(window);
} catch (ex) {
Cu.reportError(ex);
}

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

@ -316,48 +316,25 @@ Sanitizer.prototype = {
downloads: {
clear: function ()
{
if (DownloadsCommon.useJSTransfer) {
Task.spawn(function () {
let filterByTime = null;
if (this.range) {
// Convert microseconds back to milliseconds for date comparisons.
let rangeBeginMs = this.range[0] / 1000;
let rangeEndMs = this.range[1] / 1000;
filterByTime = download => download.startTime >= rangeBeginMs &&
download.startTime <= rangeEndMs;
}
// Clear all completed/cancelled downloads
let list = yield Downloads.getList(Downloads.ALL);
list.removeFinished(filterByTime);
}.bind(this)).then(null, Components.utils.reportError);
}
else {
var dlMgr = Components.classes["@mozilla.org/download-manager;1"]
.getService(Components.interfaces.nsIDownloadManager);
Task.spawn(function () {
let filterByTime = null;
if (this.range) {
// First, remove the completed/cancelled downloads
dlMgr.removeDownloadsByTimeframe(this.range[0], this.range[1]);
// Convert microseconds back to milliseconds for date comparisons.
let rangeBeginMs = this.range[0] / 1000;
let rangeEndMs = this.range[1] / 1000;
filterByTime = download => download.startTime >= rangeBeginMs &&
download.startTime <= rangeEndMs;
}
else {
// Clear all completed/cancelled downloads
dlMgr.cleanUp();
dlMgr.cleanUpPrivate();
}
}
// Clear all completed/cancelled downloads
let list = yield Downloads.getList(Downloads.ALL);
list.removeFinished(filterByTime);
}.bind(this)).then(null, Components.utils.reportError);
},
canClear : function(aCallback, aArg)
{
if (DownloadsCommon.useJSTransfer) {
aCallback("downloads", true, aArg);
}
else {
var dlMgr = Components.classes["@mozilla.org/download-manager;1"]
.getService(Components.interfaces.nsIDownloadManager);
aCallback("downloads", dlMgr.canCleanUp || dlMgr.canCleanUpPrivate, aArg);
}
aCallback("downloads", true, aArg);
return false;
}
},

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

@ -134,14 +134,9 @@ const DownloadsPanel = {
window.addEventListener("unload", this.onWindowUnload, false);
// Ensure that the Download Manager service is running. This resumes
// active downloads if required. If there are downloads to be shown in the
// panel, starting the service will make us load their data asynchronously.
if (DownloadsCommon.useJSTransfer) {
DownloadsCommon.initializeAllDataLinks();
} else {
Services.downloads;
}
// Load and resume active downloads if required. If there are downloads to
// be shown in the panel, they will be loaded asynchronously.
DownloadsCommon.initializeAllDataLinks();
// Now that data loading has eventually started, load the required XUL
// elements and initialize our views.
@ -789,26 +784,6 @@ const DownloadsView = {
DownloadsPanel.onViewLoadCompleted();
},
/**
* Called when the downloads database becomes unavailable (for example,
* entering Private Browsing Mode). References to existing data should be
* discarded.
*/
onDataInvalidated: function DV_onDataInvalidated()
{
DownloadsCommon.log("Downloads data has been invalidated. Cleaning up",
"DownloadsView.");
DownloadsPanel.terminate();
// Clear the list by replacing with a shallow copy.
let emptyView = this.richListBox.cloneNode(false);
this.richListBox.parentNode.replaceChild(emptyView, this.richListBox);
this.richListBox = emptyView;
this._viewItems = {};
this._dataItems = [];
},
/**
* Called when a new download data item is available, either during the
* asynchronous data load or when a new download is started.
@ -1486,7 +1461,8 @@ DownloadsViewItemController.prototype = {
downloadsCmd_open: function DVIC_downloadsCmd_open()
{
this.dataItem.openLocalFile(window);
this.dataItem.openLocalFile();
// We explicitly close the panel here to give the user the feedback that
// their click has been received, and we're handling the action.
// Otherwise, we'd have to wait for the file-type handler to execute

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

@ -56,16 +56,11 @@ const DownloadsButton = {
* This function is called asynchronously just after window initialization.
*
* NOTE: This function should limit the input/output it performs to improve
* startup time, and in particular should not cause the Download Manager
* service to start.
* startup time.
*/
initializeIndicator: function DB_initializeIndicator()
{
if (!DownloadsCommon.useToolkitUI) {
DownloadsIndicatorView.ensureInitialized();
} else {
DownloadsIndicatorView.ensureTerminated();
}
DownloadsIndicatorView.ensureInitialized();
},
/**
@ -95,11 +90,7 @@ const DownloadsButton = {
customizeDone: function DB_customizeDone()
{
this._customizing = false;
if (!DownloadsCommon.useToolkitUI) {
DownloadsIndicatorView.afterCustomize();
} else {
DownloadsIndicatorView.ensureTerminated();
}
DownloadsIndicatorView.afterCustomize();
},
/**
@ -490,14 +481,7 @@ const DownloadsIndicatorView = {
onCommand: function DIV_onCommand(aEvent)
{
if (DownloadsCommon.useToolkitUI) {
// The panel won't suppress attention for us, we need to clear now.
DownloadsCommon.getIndicatorData(window).attention = false;
BrowserDownloadsUI();
} else {
DownloadsPanel.showPanel();
}
DownloadsPanel.showPanel();
aEvent.stopPropagation();
},

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

@ -63,8 +63,6 @@ XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils",
"resource://gre/modules/PrivateBrowsingUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "RecentWindow",
"resource:///modules/RecentWindow.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
"resource://gre/modules/PlacesUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Promise",
"resource://gre/modules/Promise.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "DownloadsLogger",
@ -75,9 +73,6 @@ const nsIDM = Ci.nsIDownloadManager;
const kDownloadsStringBundleUrl =
"chrome://browser/locale/downloads/downloads.properties";
const kPrefBdmScanWhenDone = "browser.download.manager.scanWhenDone";
const kPrefBdmAlertOnExeOpen = "browser.download.manager.alertOnEXEOpen";
const kDownloadsStringsRequiringFormatting = {
sizeWithUnits: true,
shortTimeLeftSeconds: true,
@ -234,16 +229,6 @@ this.DownloadsCommon = {
return DownloadsCommon.strings["shortTimeLeftDays"](Math.min(days, 99));
},
/**
* Indicates that we should show the simplified panel interface instead of the
* full Download Manager window interface. The code associated with the
* Download Manager window interface will be removed in bug 899110.
*/
get useToolkitUI()
{
return false;
},
/**
* Indicates whether we should show visual notification on the indicator
* when a download event is triggered.
@ -269,39 +254,12 @@ this.DownloadsCommon = {
},
/**
* Initializes the data link for both the private and non-private downloads
* data objects.
*
* @param aDownloadManagerService
* Reference to the service implementing nsIDownloadManager. We need
* this because getService isn't available for us when this method is
* called, and we must ensure to register our listeners before the
* getService call for the Download Manager returns.
* Initializes the Downloads back-end and starts receiving events for both the
* private and non-private downloads data objects.
*/
initializeAllDataLinks: function DC_initializeAllDataLinks(aDownloadManagerService) {
DownloadsData.initializeDataLink(aDownloadManagerService);
PrivateDownloadsData.initializeDataLink(aDownloadManagerService);
},
/**
* Terminates the data link for both the private and non-private downloads
* data objects.
*/
terminateAllDataLinks: function DC_terminateAllDataLinks() {
DownloadsData.terminateDataLink();
PrivateDownloadsData.terminateDataLink();
},
/**
* Reloads the specified kind of downloads from the non-private store.
* This method must only be called when Private Browsing Mode is disabled.
*
* @param aActiveOnly
* True to load only active downloads from the database.
*/
ensureAllPersistentDataLoaded:
function DC_ensureAllPersistentDataLoaded(aActiveOnly) {
DownloadsData.ensurePersistentDataLoaded(aActiveOnly);
initializeAllDataLinks: function () {
DownloadsData.initializeDataLink();
PrivateDownloadsData.initializeDataLink();
},
/**
@ -566,15 +524,6 @@ XPCOMUtils.defineLazyGetter(DownloadsCommon, "isWinVistaOrHigher", function () {
return parseFloat(sysInfo.getProperty("version")) >= 6;
});
/**
* Returns true to indicate that we should hook the panel to the JavaScript API
* for downloads instead of the nsIDownloadManager back-end. The code
* associated with nsIDownloadManager will be removed in bug 899110.
*/
XPCOMUtils.defineLazyGetter(DownloadsCommon, "useJSTransfer", function () {
return true;
});
////////////////////////////////////////////////////////////////////////////////
//// DownloadsData
@ -611,76 +560,36 @@ function DownloadsDataCtor(aPrivate) {
// data changes.
this._views = [];
if (DownloadsCommon.useJSTransfer) {
// Maps Download objects to DownloadDataItem objects.
this._downloadToDataItemMap = new Map();
}
// Maps Download objects to DownloadDataItem objects.
this._downloadToDataItemMap = new Map();
}
DownloadsDataCtor.prototype = {
/**
* Starts receiving events for current downloads.
*
* @param aDownloadManagerService
* Reference to the service implementing nsIDownloadManager. We need
* this because getService isn't available for us when this method is
* called, and we must ensure to register our listeners before the
* getService call for the Download Manager returns.
*/
initializeDataLink: function DD_initializeDataLink(aDownloadManagerService)
initializeDataLink: function ()
{
// Start receiving real-time events.
if (DownloadsCommon.useJSTransfer) {
if (!this._dataLinkInitialized) {
let promiseList = Downloads.getList(this._isPrivate ? Downloads.PRIVATE
: Downloads.PUBLIC);
promiseList.then(list => list.addView(this)).then(null, Cu.reportError);
this._dataLinkInitialized = true;
}
} else {
aDownloadManagerService.addPrivacyAwareListener(this);
Services.obs.addObserver(this, "download-manager-remove-download-guid",
false);
if (!this._dataLinkInitialized) {
let promiseList = Downloads.getList(this._isPrivate ? Downloads.PRIVATE
: Downloads.PUBLIC);
promiseList.then(list => list.addView(this)).then(null, Cu.reportError);
this._dataLinkInitialized = true;
}
},
_dataLinkInitialized: false,
/**
* Stops receiving events for current downloads and cancels any pending read.
*/
terminateDataLink: function DD_terminateDataLink()
{
if (DownloadsCommon.useJSTransfer) {
Cu.reportError("terminateDataLink not applicable with useJSTransfer");
return;
}
this._terminateDataAccess();
// Stop receiving real-time events.
Services.obs.removeObserver(this, "download-manager-remove-download-guid");
Services.downloads.removeListener(this);
},
/**
* True if there are finished downloads that can be removed from the list.
*/
get canRemoveFinished()
{
if (DownloadsCommon.useJSTransfer) {
for (let [, dataItem] of Iterator(this.dataItems)) {
if (dataItem && !dataItem.inProgress) {
return true;
}
}
return false;
} else {
if (this._isPrivate) {
return Services.downloads.canCleanUpPrivate;
} else {
return Services.downloads.canCleanUp;
for (let [, dataItem] of Iterator(this.dataItems)) {
if (dataItem && !dataItem.inProgress) {
return true;
}
}
return false;
},
/**
@ -688,18 +597,10 @@ DownloadsDataCtor.prototype = {
*/
removeFinished: function DD_removeFinished()
{
if (DownloadsCommon.useJSTransfer) {
let promiseList = Downloads.getList(this._isPrivate ? Downloads.PRIVATE
: Downloads.PUBLIC);
promiseList.then(list => list.removeFinished())
.then(null, Cu.reportError);
} else {
if (this._isPrivate) {
Services.downloads.cleanUpPrivate();
} else {
Services.downloads.cleanUp();
}
}
let promiseList = Downloads.getList(this._isPrivate ? Downloads.PRIVATE
: Downloads.PUBLIC);
promiseList.then(list => list.removeFinished())
.then(null, Cu.reportError);
},
//////////////////////////////////////////////////////////////////////////////
@ -753,7 +654,7 @@ DownloadsDataCtor.prototype = {
let wasInProgress = aDataItem.inProgress;
let wasDone = aDataItem.done;
aDataItem.updateFromJSDownload();
aDataItem.updateFromDownload();
if (wasInProgress && !aDataItem.inProgress) {
aDataItem.endTime = Date.now();
@ -835,394 +736,10 @@ DownloadsDataCtor.prototype = {
function (dataItem) aView.onDataItemAdded(dataItem, false)
);
// Notify the view that all data is available unless loading is in progress.
if (!this._pendingStatement) {
aView.onDataLoadCompleted();
}
// Notify the view that all data is available.
aView.onDataLoadCompleted();
},
//////////////////////////////////////////////////////////////////////////////
//// In-memory downloads data store
/**
* Clears the loaded data.
*/
clear: function DD_clear()
{
this._terminateDataAccess();
this.dataItems = {};
},
/**
* Returns the data item associated with the provided source object. The
* source can be a download object that we received from the Download Manager
* because of a real-time notification, or a row from the downloads database,
* during the asynchronous data load.
*
* In case we receive download status notifications while we are still
* populating the list of downloads from the database, we want the real-time
* status to take precedence over the state that is read from the database,
* which might be older. This is achieved by creating the download item if
* it's not already in the list, but never updating the returned object using
* the data from the database, if the object already exists.
*
* @param aSource
* Object containing the data with which the item should be initialized
* if it doesn't already exist in the list. This should implement
* either nsIDownload or mozIStorageRow. If the item exists, this
* argument is only used to retrieve the download identifier.
* @param aMayReuseGUID
* If false, indicates that the download should not be added if a
* download with the same identifier was removed in the meantime. This
* ensures that, while loading the list asynchronously, downloads that
* have been removed in the meantime do no reappear inadvertently.
*
* @return New or existing data item, or null if the item was deleted from the
* list of available downloads.
*/
_getOrAddDataItem: function DD_getOrAddDataItem(aSource, aMayReuseGUID)
{
let downloadGuid = (aSource instanceof Ci.nsIDownload)
? aSource.guid
: aSource.getResultByName("guid");
if (downloadGuid in this.dataItems) {
let existingItem = this.dataItems[downloadGuid];
if (existingItem || !aMayReuseGUID) {
// Returns null if the download was removed and we can't reuse the item.
return existingItem;
}
}
DownloadsCommon.log("Creating a new DownloadsDataItem with downloadGuid =",
downloadGuid);
let dataItem = new DownloadsDataItem(aSource);
this.dataItems[downloadGuid] = dataItem;
// Create the view items before returning.
let addToStartOfList = aSource instanceof Ci.nsIDownload;
this._views.forEach(
function (view) view.onDataItemAdded(dataItem, addToStartOfList)
);
return dataItem;
},
/**
* Removes the data item with the specified identifier.
*
* This method can be called at most once per download identifier.
*/
_removeDataItem: function DD_removeDataItem(aDownloadId)
{
if (aDownloadId in this.dataItems) {
let dataItem = this.dataItems[aDownloadId];
this.dataItems[aDownloadId] = null;
this._views.forEach(
function (view) view.onDataItemRemoved(dataItem)
);
}
},
//////////////////////////////////////////////////////////////////////////////
//// Persistent data loading
/**
* Represents an executing statement, allowing its cancellation.
*/
_pendingStatement: null,
/**
* Indicates which kind of items from the persistent downloads database have
* been fully loaded in memory and are available to the views. This can
* assume the value of one of the kLoad constants.
*/
_loadState: 0,
/** No downloads have been fully loaded yet. */
get kLoadNone() 0,
/** All the active downloads in the database are loaded in memory. */
get kLoadActive() 1,
/** All the downloads in the database are loaded in memory. */
get kLoadAll() 2,
/**
* Reloads the specified kind of downloads from the persistent database. This
* method must only be called when Private Browsing Mode is disabled.
*
* @param aActiveOnly
* True to load only active downloads from the database.
*/
ensurePersistentDataLoaded:
function DD_ensurePersistentDataLoaded(aActiveOnly)
{
if (this == PrivateDownloadsData) {
Cu.reportError("ensurePersistentDataLoaded should not be called on PrivateDownloadsData");
return;
}
if (this._pendingStatement) {
// We are already in the process of reloading all downloads.
return;
}
if (aActiveOnly) {
if (this._loadState == this.kLoadNone) {
DownloadsCommon.log("Loading only active downloads from the persistence database");
// Indicate to the views that a batch loading operation is in progress.
this._views.forEach(
function (view) view.onDataLoadStarting()
);
// Reload the list using the Download Manager service. The list is
// returned in no particular order.
let downloads = Services.downloads.activeDownloads;
while (downloads.hasMoreElements()) {
let download = downloads.getNext().QueryInterface(Ci.nsIDownload);
this._getOrAddDataItem(download, true);
}
this._loadState = this.kLoadActive;
// Indicate to the views that the batch loading operation is complete.
this._views.forEach(
function (view) view.onDataLoadCompleted()
);
DownloadsCommon.log("Active downloads done loading.");
}
} else {
if (this._loadState != this.kLoadAll) {
// Load only the relevant columns from the downloads database. The
// columns are read in the _initFromDataRow method of DownloadsDataItem.
// Order by descending download identifier so that the most recent
// downloads are notified first to the listening views.
DownloadsCommon.log("Loading all downloads from the persistence database.");
let dbConnection = Services.downloads.DBConnection;
let statement = dbConnection.createAsyncStatement(
"SELECT guid, target, name, source, referrer, state, "
+ "startTime, endTime, currBytes, maxBytes "
+ "FROM moz_downloads "
+ "ORDER BY startTime DESC"
);
try {
this._pendingStatement = statement.executeAsync(this);
} finally {
statement.finalize();
}
}
}
},
/**
* Cancels any pending data access and ensures views are notified.
*/
_terminateDataAccess: function DD_terminateDataAccess()
{
if (this._pendingStatement) {
this._pendingStatement.cancel();
this._pendingStatement = null;
}
// Close all the views on the current data. Create a copy of the array
// because some views might unregister while processing this event.
Array.slice(this._views, 0).forEach(
function (view) view.onDataInvalidated()
);
},
//////////////////////////////////////////////////////////////////////////////
//// mozIStorageStatementCallback
handleResult: function DD_handleResult(aResultSet)
{
for (let row = aResultSet.getNextRow();
row;
row = aResultSet.getNextRow()) {
// Add the download to the list and initialize it with the data we read,
// unless we already received a notification providing more reliable
// information for this download.
this._getOrAddDataItem(row, false);
}
},
handleError: function DD_handleError(aError)
{
DownloadsCommon.error("Database statement execution error (",
aError.result, "): ", aError.message);
},
handleCompletion: function DD_handleCompletion(aReason)
{
DownloadsCommon.log("Loading all downloads from database completed with reason:",
aReason);
this._pendingStatement = null;
// To ensure that we don't inadvertently delete more downloads from the
// database than needed on shutdown, we should update the load state only if
// the operation completed successfully.
if (aReason == Ci.mozIStorageStatementCallback.REASON_FINISHED) {
this._loadState = this.kLoadAll;
}
// Indicate to the views that the batch loading operation is complete, even
// if the lookup failed or was canceled. The only possible glitch happens
// in case the database backend changes while loading data, when the views
// would open and immediately close. This case is rare enough not to need a
// special treatment.
this._views.forEach(
function (view) view.onDataLoadCompleted()
);
},
//////////////////////////////////////////////////////////////////////////////
//// nsIObserver
observe: function DD_observe(aSubject, aTopic, aData)
{
switch (aTopic) {
case "download-manager-remove-download-guid":
// If a single download was removed, remove the corresponding data item.
if (aSubject) {
let downloadGuid = aSubject.QueryInterface(Ci.nsISupportsCString).data;
DownloadsCommon.log("A single download with id",
downloadGuid, "was removed.");
this._removeDataItem(downloadGuid);
break;
}
// Multiple downloads have been removed. Iterate over known downloads
// and remove those that don't exist anymore.
DownloadsCommon.log("Multiple downloads were removed.");
for each (let dataItem in this.dataItems) {
if (dataItem) {
// Bug 449811 - We have to bind to the dataItem because Javascript
// doesn't do fresh let-bindings per loop iteration.
let dataItemBinding = dataItem;
Services.downloads.getDownloadByGUID(dataItemBinding.downloadGuid,
function(aStatus, aResult) {
if (aStatus == Components.results.NS_ERROR_NOT_AVAILABLE) {
DownloadsCommon.log("Removing download with id",
dataItemBinding.downloadGuid);
this._removeDataItem(dataItemBinding.downloadGuid);
}
}.bind(this));
}
}
break;
}
},
//////////////////////////////////////////////////////////////////////////////
//// nsIDownloadProgressListener
onDownloadStateChange: function DD_onDownloadStateChange(aOldState, aDownload)
{
if (aDownload.isPrivate != this._isPrivate) {
// Ignore the downloads with a privacy status other than what we are
// tracking.
return;
}
// When a new download is added, it may have the same identifier of a
// download that we previously deleted during this session, and we also
// want to provide a visible indication that the download started.
let isNew = aOldState == nsIDM.DOWNLOAD_NOTSTARTED ||
aOldState == nsIDM.DOWNLOAD_QUEUED;
let dataItem = this._getOrAddDataItem(aDownload, isNew);
if (!dataItem) {
return;
}
let wasInProgress = dataItem.inProgress;
DownloadsCommon.log("A download changed its state to:", aDownload.state);
dataItem.state = aDownload.state;
dataItem.referrer = aDownload.referrer && aDownload.referrer.spec;
dataItem.resumable = aDownload.resumable;
dataItem.startTime = Math.round(aDownload.startTime / 1000);
dataItem.currBytes = aDownload.amountTransferred;
dataItem.maxBytes = aDownload.size;
if (wasInProgress && !dataItem.inProgress) {
dataItem.endTime = Date.now();
}
// When a download is retried, we create a different download object from
// the database with the same ID as before. This means that the nsIDownload
// that the dataItem holds might now need updating.
//
// We only overwrite this in the event that _download exists, because if it
// doesn't, that means that no caller ever tried to get the nsIDownload,
// which means it was never retrieved and doesn't need to be overwritten.
if (dataItem._download) {
dataItem._download = aDownload;
}
for (let view of this._views) {
try {
view.getViewItem(dataItem).onStateChange(aOldState);
} catch (ex) {
Cu.reportError(ex);
}
}
if (isNew && !dataItem.newDownloadNotified) {
dataItem.newDownloadNotified = true;
this._notifyDownloadEvent("start");
}
// This is a final state of which we are only notified once.
if (dataItem.done) {
this._notifyDownloadEvent("finish");
}
// TODO Bug 830415: this isn't the right place to set these annotation.
// It should be set it in places' nsIDownloadHistory implementation.
if (!this._isPrivate && !dataItem.inProgress) {
let downloadMetaData = { state: dataItem.state,
endTime: dataItem.endTime };
if (dataItem.done)
downloadMetaData.fileSize = dataItem.maxBytes;
try {
PlacesUtils.annotations.setPageAnnotation(
NetUtil.newURI(dataItem.uri), "downloads/metaData", JSON.stringify(downloadMetaData), 0,
PlacesUtils.annotations.EXPIRE_WITH_HISTORY);
}
catch(ex) {
Cu.reportError(ex);
}
}
},
onProgressChange: function DD_onProgressChange(aWebProgress, aRequest,
aCurSelfProgress,
aMaxSelfProgress,
aCurTotalProgress,
aMaxTotalProgress, aDownload)
{
if (aDownload.isPrivate != this._isPrivate) {
// Ignore the downloads with a privacy status other than what we are
// tracking.
return;
}
let dataItem = this._getOrAddDataItem(aDownload, false);
if (!dataItem) {
return;
}
dataItem.currBytes = aDownload.amountTransferred;
dataItem.maxBytes = aDownload.size;
dataItem.speed = aDownload.speed;
dataItem.percentComplete = aDownload.percentComplete;
this._views.forEach(
function (view) view.getViewItem(dataItem).onProgressChange()
);
},
onStateChange: function () { },
onSecurityChange: function () { },
//////////////////////////////////////////////////////////////////////////////
//// Notifications sent to the most recent browser window only
@ -1252,10 +769,6 @@ DownloadsDataCtor.prototype = {
_notifyDownloadEvent: function DD_notifyDownloadEvent(aType)
{
DownloadsCommon.log("Attempting to notify that a new download has started or finished.");
if (DownloadsCommon.useToolkitUI) {
DownloadsCommon.log("Cancelling notification - we're using the toolkit downloads manager.");
return;
}
// Show the panel in the most recent browser window, if present.
let browserWin = RecentWindow.getMostRecentBrowserWindow({ private: this._isPrivate });
@ -1288,25 +801,24 @@ XPCOMUtils.defineLazyGetter(this, "DownloadsData", function() {
//// DownloadsDataItem
/**
* Represents a single item in the list of downloads. This object either wraps
* an existing nsIDownload from the Download Manager, or provides the same
* information read directly from the downloads database, with the possibility
* of querying the nsIDownload lazily, for performance reasons.
* Represents a single item in the list of downloads.
*
* @param aSource
* Object containing the data with which the item should be initialized.
* This should implement either nsIDownload or mozIStorageRow. If the
* JavaScript API for downloads is enabled, this is a Download object.
* The endTime property is initialized to the current date and time.
*
* @param aDownload
* The Download object with the current state.
*/
function DownloadsDataItem(aSource)
function DownloadsDataItem(aDownload)
{
if (DownloadsCommon.useJSTransfer) {
this._initFromJSDownload(aSource);
} else if (aSource instanceof Ci.nsIDownload) {
this._initFromDownload(aSource);
} else {
this._initFromDataRow(aSource);
}
this._download = aDownload;
this.downloadGuid = "id:" + this._autoIncrementId;
this.file = aDownload.target.path;
this.target = OS.Path.basename(aDownload.target.path);
this.uri = aDownload.source.url;
this.endTime = Date.now();
this.updateFromDownload();
}
DownloadsDataItem.prototype = {
@ -1318,30 +830,9 @@ DownloadsDataItem.prototype = {
__lastId: 0,
/**
* Initializes this object from the JavaScript API for downloads.
*
* The endTime property is initialized to the current date and time.
*
* @param aDownload
* The Download object with the current state.
* Updates this object from the underlying Download object.
*/
_initFromJSDownload: function (aDownload)
{
this._download = aDownload;
this.downloadGuid = "id:" + this._autoIncrementId;
this.file = aDownload.target.path;
this.target = OS.Path.basename(aDownload.target.path);
this.uri = aDownload.source.url;
this.endTime = Date.now();
this.updateFromJSDownload();
},
/**
* Updates this object from the JavaScript API for downloads.
*/
updateFromJSDownload: function ()
updateFromDownload: function ()
{
// Collapse state using the correct priority.
if (this._download.succeeded) {
@ -1370,115 +861,6 @@ DownloadsDataItem.prototype = {
this.percentComplete = this._download.progress;
},
/**
* Initializes this object from a download object of the Download Manager.
*
* The endTime property is initialized to the current date and time.
*
* @param aDownload
* The nsIDownload with the current state.
*/
_initFromDownload: function DDI_initFromDownload(aDownload)
{
this._download = aDownload;
// Fetch all the download properties eagerly.
this.downloadGuid = aDownload.guid;
this.file = aDownload.target.spec;
this.target = aDownload.displayName;
this.uri = aDownload.source.spec;
this.referrer = aDownload.referrer && aDownload.referrer.spec;
this.state = aDownload.state;
this.startTime = Math.round(aDownload.startTime / 1000);
this.endTime = Date.now();
this.currBytes = aDownload.amountTransferred;
this.maxBytes = aDownload.size;
this.resumable = aDownload.resumable;
this.speed = aDownload.speed;
this.percentComplete = aDownload.percentComplete;
},
/**
* Initializes this object from a data row in the downloads database, without
* querying the associated nsIDownload object, to improve performance when
* loading the list of downloads asynchronously.
*
* When this object is initialized in this way, accessing the "download"
* property loads the underlying nsIDownload object synchronously, and should
* be avoided unless the object is really required.
*
* @param aStorageRow
* The mozIStorageRow from the downloads database.
*/
_initFromDataRow: function DDI_initFromDataRow(aStorageRow)
{
// Get the download properties from the data row.
this._download = null;
this.downloadGuid = aStorageRow.getResultByName("guid");
this.file = aStorageRow.getResultByName("target");
this.target = aStorageRow.getResultByName("name");
this.uri = aStorageRow.getResultByName("source");
this.referrer = aStorageRow.getResultByName("referrer");
this.state = aStorageRow.getResultByName("state");
this.startTime = Math.round(aStorageRow.getResultByName("startTime") / 1000);
this.endTime = Math.round(aStorageRow.getResultByName("endTime") / 1000);
this.currBytes = aStorageRow.getResultByName("currBytes");
this.maxBytes = aStorageRow.getResultByName("maxBytes");
// Now we have to determine if the download is resumable, but don't want to
// access the underlying download object unnecessarily. The only case where
// the property is relevant is when we are currently downloading data, and
// in this case the download object is already loaded in memory or will be
// loaded very soon in any case. In all the other cases, including a paused
// download, we assume that the download is resumable. The property will be
// updated as soon as the underlying download state changes.
// We'll start by assuming we're resumable, and then if we're downloading,
// update resumable property in case we were wrong.
this.resumable = true;
if (this.state == nsIDM.DOWNLOAD_DOWNLOADING) {
this.getDownload(function(aDownload) {
this.resumable = aDownload.resumable;
}.bind(this));
}
// Compute the other properties without accessing the download object.
this.speed = 0;
this.percentComplete = this.maxBytes <= 0
? -1
: Math.round(this.currBytes / this.maxBytes * 100);
},
/**
* Asynchronous getter for the download object corresponding to this data item.
*
* @param aCallback
* A callback function which will be called when the download object is
* available. It should accept one argument which will be the download
* object.
*/
getDownload: function DDI_getDownload(aCallback) {
if (this._download) {
// Return the download object asynchronously to the caller
let download = this._download;
Services.tm.mainThread.dispatch(function () aCallback(download),
Ci.nsIThread.DISPATCH_NORMAL);
} else {
Services.downloads.getDownloadByGUID(this.downloadGuid,
function(aStatus, aResult) {
if (!Components.isSuccessCode(aStatus)) {
Cu.reportError(
new Components.Exception("Cannot retrieve download for GUID: " +
this.downloadGuid));
} else {
this._download = aResult;
aCallback(aResult);
}
}.bind(this));
}
},
/**
* Indicates whether the download is proceeding normally, and not finished
* yet. This includes paused downloads. When this property is true, the
@ -1600,22 +982,9 @@ DownloadsDataItem.prototype = {
/**
* Open the target file for this download.
*
* @param aOwnerWindow
* The window with which the required action is associated.
* @throws if the file cannot be opened.
*/
openLocalFile: function DDI_openLocalFile(aOwnerWindow) {
if (DownloadsCommon.useJSTransfer) {
this._download.launch().then(null, Cu.reportError);
return;
}
this.getDownload(function(aDownload) {
DownloadsCommon.openDownloadedFile(this.localFile,
aDownload.MIMEInfo,
aOwnerWindow);
}.bind(this));
openLocalFile: function () {
this._download.launch().then(null, Cu.reportError);
},
/**
@ -1630,26 +999,11 @@ DownloadsDataItem.prototype = {
* @throws if the download is not resumable or if has already done.
*/
togglePauseResume: function DDI_togglePauseResume() {
if (DownloadsCommon.useJSTransfer) {
if (this._download.stopped) {
this._download.start();
} else {
this._download.cancel();
}
return;
if (this._download.stopped) {
this._download.start();
} else {
this._download.cancel();
}
if (!this.inProgress || !this.resumable)
throw new Error("The given download cannot be paused or resumed");
this.getDownload(function(aDownload) {
if (this.inProgress) {
if (this.paused)
aDownload.resume();
else
aDownload.pause();
}
}.bind(this));
},
/**
@ -1657,73 +1011,25 @@ DownloadsDataItem.prototype = {
* @throws if we cannot.
*/
retry: function DDI_retry() {
if (DownloadsCommon.useJSTransfer) {
this._download.start();
return;
}
if (!this.canRetry)
throw new Error("Cannot retry this download");
this.getDownload(function(aDownload) {
aDownload.retry();
});
},
/**
* Support function that deletes the local file for a download. This is
* used in cases where the Download Manager service doesn't delete the file
* from disk when cancelling. See bug 732924.
*/
_ensureLocalFileRemoved: function DDI__ensureLocalFileRemoved()
{
try {
let localFile = this.localFile;
if (localFile.exists()) {
localFile.remove(false);
}
} catch (ex) { }
this._download.start();
},
/**
* Cancels the download.
* @throws if the download is already done.
*/
cancel: function() {
if (DownloadsCommon.useJSTransfer) {
this._download.cancel();
this._download.removePartialData().then(null, Cu.reportError);
return;
}
if (!this.inProgress)
throw new Error("Cannot cancel this download");
this.getDownload(function (aDownload) {
aDownload.cancel();
this._ensureLocalFileRemoved();
}.bind(this));
this._download.cancel();
this._download.removePartialData().then(null, Cu.reportError);
},
/**
* Remove the download.
*/
remove: function DDI_remove() {
if (DownloadsCommon.useJSTransfer) {
Downloads.getList(Downloads.ALL)
.then(list => list.remove(this._download))
.then(() => this._download.finalize(true))
.then(null, Cu.reportError);
return;
}
this.getDownload(function (aDownload) {
if (this.inProgress) {
aDownload.cancel();
this._ensureLocalFileRemoved();
}
aDownload.remove();
}.bind(this));
Downloads.getList(Downloads.ALL)
.then(list => list.remove(this._download))
.then(() => this._download.finalize(true))
.then(null, Cu.reportError);
}
};
@ -1838,18 +1144,6 @@ const DownloadsViewPrototype = {
this._loading = false;
},
/**
* Called when the downloads database becomes unavailable (for example, we
* entered Private Browsing Mode and the database backend changed).
* References to existing data should be discarded.
*
* @note Subclasses should override this.
*/
onDataInvalidated: function DVP_onDataInvalidated()
{
throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
},
/**
* Called when a new download data item is available, either during the
* asynchronous data load or when a new download is started.
@ -1968,16 +1262,6 @@ DownloadsIndicatorDataCtor.prototype = {
this._updateViews();
},
/**
* Called when the downloads database becomes unavailable (for example, we
* entered Private Browsing Mode and the database backend changed).
* References to existing data should be discarded.
*/
onDataInvalidated: function DID_onDataInvalidated()
{
this._itemCount = 0;
},
/**
* Called when a new download data item is available, either during the
* asynchronous data load or when a new download is started.
@ -2271,11 +1555,6 @@ DownloadsSummaryData.prototype = {
this._updateViews();
},
onDataInvalidated: function DSD_onDataInvalidated()
{
this._dataItems = [];
},
onDataItemAdded: function DSD_onDataItemAdded(aDataItem, aNewest)
{
if (aNewest) {

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

@ -1,16 +1,13 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* vim: set ts=2 et sw=2 tw=80 filetype=javascript: */
/* 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/. */
* 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 component listens to notifications for startup, shutdown and session
* restore, controlling which downloads should be loaded from the database.
*
* To avoid affecting startup performance, this component monitors the current
* session restore state, but defers the actual downloads data manipulation
* until the Download Manager service is loaded.
* This component enables the JavaScript API for downloads at startup. This
* will eventually be removed when nsIDownloadManager will not be available
* anymore (bug 851471).
*/
"use strict";
@ -23,44 +20,18 @@ const Ci = Components.interfaces;
const Cu = Components.utils;
const Cr = Components.results;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "DownloadsCommon",
"resource:///modules/DownloadsCommon.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "gSessionStartup",
"@mozilla.org/browser/sessionstartup;1",
"nsISessionStartup");
const kObservedTopics = [
"sessionstore-windows-restored",
"sessionstore-browser-state-restored",
"download-manager-initialized",
"download-manager-change-retention",
"last-pb-context-exited",
"browser-lastwindow-close-granted",
"quit-application",
"profile-change-teardown",
];
/**
* CID of our implementation of nsIDownloadManagerUI.
* CID and Contract ID of our implementation of nsIDownloadManagerUI.
*/
const kDownloadsUICid = Components.ID("{4d99321e-d156-455b-81f7-e7aa2308134f}");
/**
* Contract ID of the service implementing nsIDownloadManagerUI.
*/
const kDownloadsUIContractId = "@mozilla.org/download-manager-ui;1";
/**
* CID of the JavaScript implementation of nsITransfer.
* CID and Contract ID of the JavaScript implementation of nsITransfer.
*/
const kTransferCid = Components.ID("{1b4c85df-cbdd-4bb6-b04e-613caece083c}");
/**
* Contract ID of the service implementing nsITransfer.
*/
const kTransferContractId = "@mozilla.org/transfer;1";
////////////////////////////////////////////////////////////////////////////////
@ -76,204 +47,31 @@ DownloadsStartup.prototype = {
//////////////////////////////////////////////////////////////////////////////
//// nsISupports
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
Ci.nsISupportsWeakReference]),
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]),
//////////////////////////////////////////////////////////////////////////////
//// nsIObserver
observe: function DS_observe(aSubject, aTopic, aData)
{
switch (aTopic) {
case "profile-after-change":
// Override Toolkit's nsIDownloadManagerUI implementation with our own.
// This must be done at application startup and not in the manifest to
// ensure that our implementation overrides the original one.
Components.manager.QueryInterface(Ci.nsIComponentRegistrar)
.registerFactory(kDownloadsUICid, "",
kDownloadsUIContractId, null);
// Override Toolkit's nsITransfer implementation with the one from the
// JavaScript API for downloads. This will eventually be removed when
// nsIDownloadManager will not be available anymore (bug 851471). The
// old code in this module will be removed in bug 899110.
Components.manager.QueryInterface(Ci.nsIComponentRegistrar)
.registerFactory(kTransferCid, "",
kTransferContractId, null);
break;
case "sessionstore-windows-restored":
case "sessionstore-browser-state-restored":
// Unless there is no saved session, there is a chance that we are
// starting up after a restart or a crash. We should check the disk
// database to see if there are completed downloads to recover and show
// in the panel, in addition to in-progress downloads.
if (gSessionStartup.sessionType != Ci.nsISessionStartup.NO_SESSION) {
this._restoringSession = true;
}
this._ensureDataLoaded();
break;
case "download-manager-initialized":
// Don't initialize the JavaScript data and user interface layer if we
// are initializing the Download Manager service during shutdown.
if (this._shuttingDown) {
break;
}
// Start receiving events for active and new downloads before we return
// from this observer function. We can't defer the execution of this
// step, to ensure that we don't lose events raised in the meantime.
DownloadsCommon.initializeAllDataLinks(
aSubject.QueryInterface(Ci.nsIDownloadManager));
this._downloadsServiceInitialized = true;
// Since this notification is generated during the getService call and
// we need to get the Download Manager service ourselves, we must post
// the handler on the event queue to be executed later.
Services.tm.mainThread.dispatch(this._ensureDataLoaded.bind(this),
Ci.nsIThread.DISPATCH_NORMAL);
break;
case "download-manager-change-retention":
// If we're using the Downloads Panel, we override the retention
// preference to always retain downloads on completion.
if (!DownloadsCommon.useToolkitUI) {
aSubject.QueryInterface(Ci.nsISupportsPRInt32).data = 2;
}
break;
case "browser-lastwindow-close-granted":
// When using the panel interface, downloads that are already completed
// should be removed when the last full browser window is closed. This
// event is invoked only if the application is not shutting down yet.
// If the Download Manager service is not initialized, we don't want to
// initialize it just to clean up completed downloads, because they can
// be present only in case there was a browser crash or restart.
if (this._downloadsServiceInitialized &&
!DownloadsCommon.useToolkitUI) {
Services.downloads.cleanUp();
}
break;
case "last-pb-context-exited":
// Similar to the above notification, but for private downloads.
if (this._downloadsServiceInitialized &&
!DownloadsCommon.useToolkitUI) {
Services.downloads.cleanUpPrivate();
}
break;
case "quit-application":
// When the application is shutting down, we must free all resources in
// addition to cleaning up completed downloads. If the Download Manager
// service is not initialized, we don't want to initialize it just to
// clean up completed downloads, because they can be present only in
// case there was a browser crash or restart.
this._shuttingDown = true;
if (!this._downloadsServiceInitialized) {
break;
}
DownloadsCommon.terminateAllDataLinks();
// When using the panel interface, downloads that are already completed
// should be removed when quitting the application.
if (!DownloadsCommon.useToolkitUI && aData != "restart") {
this._cleanupOnShutdown = true;
}
break;
case "profile-change-teardown":
// If we need to clean up, we must do it synchronously after all the
// "quit-application" listeners are invoked, so that the Download
// Manager service has a chance to pause or cancel in-progress downloads
// before we remove completed downloads from the list. Note that, since
// "quit-application" was invoked, we've already exited Private Browsing
// Mode, thus we are always working on the disk database.
if (this._cleanupOnShutdown) {
Services.downloads.cleanUp();
}
if (!DownloadsCommon.useToolkitUI) {
// If we got this far, that means that we finished our first session
// with the Downloads Panel without crashing. This means that we don't
// have to force displaying only active downloads on the next startup
// now.
this._firstSessionCompleted = true;
}
break;
}
},
//////////////////////////////////////////////////////////////////////////////
//// Private
/**
* Indicates whether we're restoring a previous session. This is used by
* _recoverAllDownloads to determine whether or not we should load and
* display all downloads data, or restrict it to only the active downloads.
*/
_restoringSession: false,
/**
* Indicates whether the Download Manager service has been initialized. This
* flag is required because we want to avoid accessing the service immediately
* at browser startup. The service will start when the user first requests a
* download, or some time after browser startup.
*/
_downloadsServiceInitialized: false,
/**
* True while we are processing the "quit-application" event, and later.
*/
_shuttingDown: false,
/**
* True during shutdown if we need to remove completed downloads.
*/
_cleanupOnShutdown: false,
/**
* True if we should display all downloads, as opposed to just active
* downloads. We decide to display all downloads if we're restoring a session,
* or if we're using the Downloads Panel anytime after the first session with
* it has completed.
*/
get _recoverAllDownloads() {
return this._restoringSession ||
(!DownloadsCommon.useToolkitUI && this._firstSessionCompleted);
},
/**
* True if we've ever completed a session with the Downloads Panel enabled.
*/
get _firstSessionCompleted() {
return Services.prefs
.getBoolPref("browser.download.panel.firstSessionCompleted");
},
set _firstSessionCompleted(aValue) {
Services.prefs.setBoolPref("browser.download.panel.firstSessionCompleted",
aValue);
return aValue;
},
/**
* Ensures that persistent download data is reloaded at the appropriate time.
*/
_ensureDataLoaded: function DS_ensureDataLoaded()
{
if (!this._downloadsServiceInitialized) {
if (aTopic != "profile-after-change") {
Cu.reportError("Unexpected observer notification.");
return;
}
// If the previous session has been already restored, then we ensure that
// all the downloads are loaded. Otherwise, we only ensure that the active
// downloads from the previous session are loaded.
DownloadsCommon.ensureAllPersistentDataLoaded(!this._recoverAllDownloads);
}
// Override Toolkit's nsIDownloadManagerUI implementation with our own.
// This must be done at application startup and not in the manifest to
// ensure that our implementation overrides the original one.
Components.manager.QueryInterface(Ci.nsIComponentRegistrar)
.registerFactory(kDownloadsUICid, "",
kDownloadsUIContractId, null);
// Override Toolkit's nsITransfer implementation with the one from the
// JavaScript API for downloads.
Components.manager.QueryInterface(Ci.nsIComponentRegistrar)
.registerFactory(kTransferCid, "",
kTransferContractId, null);
},
};
////////////////////////////////////////////////////////////////////////////////

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

@ -1,15 +1,12 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* vim: set ts=2 et sw=2 tw=80 filetype=javascript: */
/* 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/. */
* 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 component implements the nsIDownloadManagerUI interface and opens the
* downloads panel in the most recent browser window when requested.
*
* If a specific preference is set, this component transparently forwards all
* calls to the original implementation in Toolkit, that shows the window UI.
* Downloads view for the most recent browser window when requested.
*/
"use strict";
@ -40,11 +37,6 @@ XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils",
function DownloadsUI()
{
XPCOMUtils.defineLazyGetter(this, "_toolkitUI", function () {
// Create Toolkit's nsIDownloadManagerUI implementation.
return Components.classesByID["{7dfdf0d1-aff6-4a34-bad1-d0fe74601642}"]
.getService(Ci.nsIDownloadManagerUI);
});
}
DownloadsUI.prototype = {
@ -62,11 +54,6 @@ DownloadsUI.prototype = {
show: function DUI_show(aWindowContext, aDownload, aReason, aUsePrivateUI)
{
if (DownloadsCommon.useToolkitUI) {
this._toolkitUI.show(aWindowContext, aDownload, aReason, aUsePrivateUI);
return;
}
if (!aReason) {
aReason = Ci.nsIDownloadManagerUI.REASON_USER_INTERACTED;
}
@ -92,27 +79,17 @@ DownloadsUI.prototype = {
}
},
get visible()
{
// If we're still using the toolkit downloads manager, delegate the call
// to it. Otherwise, return true for now, until we decide on how we want
// to indicate that a new download has started if a browser window is
// not available or minimized.
return DownloadsCommon.useToolkitUI ? this._toolkitUI.visible : true;
},
get visible() true,
getAttention: function DUI_getAttention()
{
if (DownloadsCommon.useToolkitUI) {
this._toolkitUI.getAttention();
}
},
getAttention: function () {},
//////////////////////////////////////////////////////////////////////////////
//// Private
/**
* Helper function that opens the download manager UI.
*/
_showDownloadManagerUI:
function DUI_showDownloadManagerUI(aWindowContext, aUsePrivateUI)
_showDownloadManagerUI: function (aWindowContext, aUsePrivateUI)
{
// If we weren't given a window context, try to find a browser window
// to use as our parent - and if that doesn't work, error out and give up.

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

@ -17,8 +17,6 @@ var gMainPane = {
this.updateBrowserStartupLastSession();
this.setupDownloadsWindowOptions();
// Notify observers that the UI is now ready
Components.classes["@mozilla.org/observer-service;1"]
.getService(Components.interfaces.nsIObserverService)
@ -39,17 +37,6 @@ var gMainPane = {
},
setupDownloadsWindowOptions: function ()
{
let showWhenDownloading = document.getElementById("showWhenDownloading");
let closeWhenDone = document.getElementById("closeWhenDone");
// These radio buttons should be hidden when the Downloads Panel is enabled.
let shouldHide = !DownloadsCommon.useToolkitUI;
showWhenDownloading.hidden = shouldHide;
closeWhenDone.hidden = shouldHide;
},
// HOME PAGE
/*
@ -201,12 +188,6 @@ var gMainPane = {
/*
* Preferences:
*
* browser.download.showWhenStarting - bool
* True if the Download Manager should be opened when a download is
* started, false if it shouldn't be opened.
* browser.download.closeWhenDone - bool
* True if the Download Manager should be closed when all downloads
* complete, false if it should be left open.
* browser.download.useDownloadDir - bool
* True - Save files directly to the folder configured via the
* browser.download.folderList preference.
@ -234,30 +215,6 @@ var gMainPane = {
* deprecated.
*/
/**
* Updates preferences which depend upon the value of the preference which
* determines whether the Downloads manager is opened at the start of a
* download.
*/
readShowDownloadsWhenStarting: function ()
{
this.showDownloadsWhenStartingPrefChanged();
// don't override the preference's value in UI
return undefined;
},
/**
* Enables or disables the "close Downloads manager when downloads finished"
* preference element, consequently updating the associated UI.
*/
showDownloadsWhenStartingPrefChanged: function ()
{
var showWhenStartingPref = document.getElementById("browser.download.manager.showWhenStarting");
var closeWhenDonePref = document.getElementById("browser.download.manager.closeWhenDone");
closeWhenDonePref.disabled = !showWhenStartingPref.value;
},
/**
* Enables/disables the folder field and Browse button based on whether a
* default download directory is being used.

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

@ -31,13 +31,6 @@
onchange="gMainPane.updateBrowserStartupLastSession();"/>
<!-- Downloads -->
<preference id="browser.download.manager.showWhenStarting"
name="browser.download.manager.showWhenStarting"
type="bool"
onchange="gMainPane.showDownloadsWhenStartingPrefChanged();"/>
<preference id="browser.download.manager.closeWhenDone"
name="browser.download.manager.closeWhenDone"
type="bool"/>
<preference id="browser.download.useDownloadDir"
name="browser.download.useDownloadDir"
type="bool"/>
@ -160,19 +153,6 @@
<groupbox id="downloadsGroup" data-category="paneGeneral" hidden="true">
<caption label="&downloads.label;"/>
<checkbox id="showWhenDownloading"
label="&showWhenDownloading.label;"
accesskey="&showWhenDownloading.accesskey;"
preference="browser.download.manager.showWhenStarting"
onsyncfrompreference="return gMainPane.readShowDownloadsWhenStarting();"/>
<checkbox id="closeWhenDone"
label="&closeWhenDone.label;"
accesskey="&closeWhenDone.accesskey;"
class="indent"
preference="browser.download.manager.closeWhenDone"/>
<separator class="thin"/>
<radiogroup id="saveWhere"
preference="browser.download.useDownloadDir"
onsyncfrompreference="return gMainPane.readUseDownloadDir();">

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

@ -23,25 +23,12 @@ var gMainPane = {
this.updateBrowserStartupLastSession();
this.setupDownloadsWindowOptions();
// Notify observers that the UI is now ready
Components.classes["@mozilla.org/observer-service;1"]
.getService(Components.interfaces.nsIObserverService)
.notifyObservers(window, "main-pane-loaded", null);
},
setupDownloadsWindowOptions: function ()
{
let showWhenDownloading = document.getElementById("showWhenDownloading");
let closeWhenDone = document.getElementById("closeWhenDone");
// These radio buttons should be hidden when the Downloads Panel is enabled.
let shouldHide = !DownloadsCommon.useToolkitUI;
showWhenDownloading.hidden = shouldHide;
closeWhenDone.hidden = shouldHide;
},
// HOME PAGE
/*
@ -185,12 +172,6 @@ var gMainPane = {
/*
* Preferences:
*
* browser.download.showWhenStarting - bool
* True if the Download Manager should be opened when a download is
* started, false if it shouldn't be opened.
* browser.download.closeWhenDone - bool
* True if the Download Manager should be closed when all downloads
* complete, false if it should be left open.
* browser.download.useDownloadDir - bool
* True - Save files directly to the folder configured via the
* browser.download.folderList preference.
@ -218,30 +199,6 @@ var gMainPane = {
* deprecated.
*/
/**
* Updates preferences which depend upon the value of the preference which
* determines whether the Downloads manager is opened at the start of a
* download.
*/
readShowDownloadsWhenStarting: function ()
{
this.showDownloadsWhenStartingPrefChanged();
// don't override the preference's value in UI
return undefined;
},
/**
* Enables or disables the "close Downloads manager when downloads finished"
* preference element, consequently updating the associated UI.
*/
showDownloadsWhenStartingPrefChanged: function ()
{
var showWhenStartingPref = document.getElementById("browser.download.manager.showWhenStarting");
var closeWhenDonePref = document.getElementById("browser.download.manager.closeWhenDone");
closeWhenDonePref.disabled = !showWhenStartingPref.value;
},
/**
* Enables/disables the folder field and Browse button based on whether a
* default download directory is being used.

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

@ -50,13 +50,6 @@
onchange="gMainPane.updateBrowserStartupLastSession();"/>
<!-- Downloads -->
<preference id="browser.download.manager.showWhenStarting"
name="browser.download.manager.showWhenStarting"
type="bool"
onchange="gMainPane.showDownloadsWhenStartingPrefChanged();"/>
<preference id="browser.download.manager.closeWhenDone"
name="browser.download.manager.closeWhenDone"
type="bool"/>
<preference id="browser.download.useDownloadDir"
name="browser.download.useDownloadDir"
type="bool"/>
@ -117,16 +110,6 @@
<groupbox id="downloadsGroup">
<caption label="&downloads.label;"/>
<checkbox id="showWhenDownloading" label="&showWhenDownloading.label;"
accesskey="&showWhenDownloading.accesskey;"
preference="browser.download.manager.showWhenStarting"
onsyncfrompreference="return gMainPane.readShowDownloadsWhenStarting();"/>
<checkbox id="closeWhenDone" label="&closeWhenDone.label;"
accesskey="&closeWhenDone.accesskey;" class="indent"
preference="browser.download.manager.closeWhenDone"/>
<separator class="thin"/>
<radiogroup id="saveWhere"
preference="browser.download.useDownloadDir"
onsyncfrompreference="return gMainPane.readUseDownloadDir();">

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

@ -22,10 +22,6 @@
<!ENTITY downloads.label "Downloads">
<!ENTITY showWhenDownloading.label "Show the Downloads window when downloading a file">
<!ENTITY showWhenDownloading.accesskey "D">
<!ENTITY closeWhenDone.label "Close it when all downloads are finished">
<!ENTITY closeWhenDone.accesskey "w">
<!ENTITY saveTo.label "Save files to">
<!ENTITY saveTo.accesskey "v">
<!ENTITY chooseFolderWin.label "Browse…">