mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-11 12:25:53 +00:00
Bug 816254 - Add logging to Downloads Panel r=mak
This commit is contained in:
parent
26a7fd81d2
commit
371159a109
@ -306,6 +306,9 @@ pref("browser.urlbar.trimURLs", true);
|
||||
|
||||
pref("browser.altClickSave", false);
|
||||
|
||||
// Enable logging downloads operations to the Error Console.
|
||||
pref("browser.download.debug", false);
|
||||
|
||||
// Number of milliseconds to wait for the http headers (and thus
|
||||
// the Content-Disposition filename) before giving up and falling back to
|
||||
// picking a filename without that info in hand so that the user sees some
|
||||
|
@ -121,7 +121,9 @@ const DownloadsPanel = {
|
||||
*/
|
||||
initialize: function DP_initialize(aCallback)
|
||||
{
|
||||
DownloadsCommon.log("Attempting to initialize DownloadsPanel for a window.");
|
||||
if (this._state != this.kStateUninitialized) {
|
||||
DownloadsCommon.log("DownloadsPanel is already initialized.");
|
||||
DownloadsOverlayLoader.ensureOverlayLoaded(this.kDownloadsOverlay,
|
||||
aCallback);
|
||||
return;
|
||||
@ -137,11 +139,16 @@ const DownloadsPanel = {
|
||||
|
||||
// Now that data loading has eventually started, load the required XUL
|
||||
// elements and initialize our views.
|
||||
DownloadsCommon.log("Ensuring DownloadsPanel overlay loaded.");
|
||||
DownloadsOverlayLoader.ensureOverlayLoaded(this.kDownloadsOverlay,
|
||||
function DP_I_callback() {
|
||||
DownloadsViewController.initialize();
|
||||
DownloadsCommon.log("Attaching DownloadsView...");
|
||||
DownloadsCommon.getData(window).addView(DownloadsView);
|
||||
DownloadsCommon.log("DownloadsView attached - the panel for this window",
|
||||
"should now see download items come in.");
|
||||
DownloadsPanel._attachEventListeners();
|
||||
DownloadsCommon.log("DownloadsPanel initialized.");
|
||||
aCallback();
|
||||
});
|
||||
},
|
||||
@ -153,7 +160,9 @@ const DownloadsPanel = {
|
||||
*/
|
||||
terminate: function DP_terminate()
|
||||
{
|
||||
DownloadsCommon.log("Attempting to terminate DownloadsPanel for a window.");
|
||||
if (this._state == this.kStateUninitialized) {
|
||||
DownloadsCommon.log("DownloadsPanel was never initialized. Nothing to do.");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -169,6 +178,7 @@ const DownloadsPanel = {
|
||||
this._state = this.kStateUninitialized;
|
||||
|
||||
DownloadsSummary.active = false;
|
||||
DownloadsCommon.log("DownloadsPanel terminated.");
|
||||
},
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
@ -191,7 +201,10 @@ const DownloadsPanel = {
|
||||
*/
|
||||
showPanel: function DP_showPanel()
|
||||
{
|
||||
DownloadsCommon.log("Opening the downloads panel.");
|
||||
|
||||
if (this.isPanelShowing) {
|
||||
DownloadsCommon.log("Panel is already showing - focusing instead.");
|
||||
this._focusPanel();
|
||||
return;
|
||||
}
|
||||
@ -204,6 +217,7 @@ const DownloadsPanel = {
|
||||
setTimeout(function () DownloadsPanel._openPopupIfDataReady(), 0);
|
||||
}.bind(this));
|
||||
|
||||
DownloadsCommon.log("Waiting for the downloads panel to appear.");
|
||||
this._state = this.kStateWaitingData;
|
||||
},
|
||||
|
||||
@ -213,7 +227,10 @@ const DownloadsPanel = {
|
||||
*/
|
||||
hidePanel: function DP_hidePanel()
|
||||
{
|
||||
DownloadsCommon.log("Closing the downloads panel.");
|
||||
|
||||
if (!this.isPanelShowing) {
|
||||
DownloadsCommon.log("Downloads panel is not showing - nothing to do.");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -223,6 +240,7 @@ const DownloadsPanel = {
|
||||
// was open, then the onPopupHidden event handler has already updated the
|
||||
// current state, otherwise we must update the state ourselves.
|
||||
this._state = this.kStateHidden;
|
||||
DownloadsCommon.log("Downloads panel is now closed.");
|
||||
},
|
||||
|
||||
/**
|
||||
@ -298,6 +316,7 @@ const DownloadsPanel = {
|
||||
return;
|
||||
}
|
||||
|
||||
DownloadsCommon.log("Downloads panel has shown.");
|
||||
this._state = this.kStateShown;
|
||||
|
||||
// Since at most one popup is open at any given time, we can set globally.
|
||||
@ -319,6 +338,8 @@ const DownloadsPanel = {
|
||||
return;
|
||||
}
|
||||
|
||||
DownloadsCommon.log("Downloads panel has hidden.");
|
||||
|
||||
// Removes the keyfocus attribute so that we stop handling keyboard
|
||||
// navigation.
|
||||
this.keyFocusing = false;
|
||||
@ -341,6 +362,7 @@ const DownloadsPanel = {
|
||||
*/
|
||||
showDownloadsHistory: function DP_showDownloadsHistory()
|
||||
{
|
||||
DownloadsCommon.log("Showing download history.");
|
||||
// Hide the panel before showing another window, otherwise focus will return
|
||||
// to the browser window when the panel closes automatically.
|
||||
this.hidePanel();
|
||||
@ -445,6 +467,8 @@ const DownloadsPanel = {
|
||||
return;
|
||||
}
|
||||
|
||||
DownloadsCommon.log("Received a paste event.");
|
||||
|
||||
let trans = Cc["@mozilla.org/widget/transferable;1"]
|
||||
.createInstance(Ci.nsITransferable);
|
||||
trans.init(null);
|
||||
@ -464,6 +488,7 @@ const DownloadsPanel = {
|
||||
}
|
||||
|
||||
let uri = NetUtil.newURI(url);
|
||||
DownloadsCommon.log("Pasted URL seems valid. Starting download.");
|
||||
saveURL(uri.spec, name || uri.spec, null, true, true,
|
||||
undefined, document);
|
||||
} catch (ex) {}
|
||||
@ -525,9 +550,13 @@ const DownloadsPanel = {
|
||||
}
|
||||
|
||||
if (aAnchor) {
|
||||
DownloadsCommon.log("Opening downloads panel popup.");
|
||||
this.panel.openPopup(aAnchor, "bottomcenter topright", 0, 0, false,
|
||||
null);
|
||||
} else {
|
||||
DownloadsCommon.error("We can't find the anchor! Failure case - opening",
|
||||
"downloads panel on TabsToolbar. We should never",
|
||||
"get here!");
|
||||
Components.utils.reportError(
|
||||
"Downloads button cannot be found");
|
||||
}
|
||||
@ -597,6 +626,7 @@ const DownloadsOverlayLoader = {
|
||||
}
|
||||
|
||||
this._overlayLoading = true;
|
||||
DownloadsCommon.log("Loading overlay ", aOverlay);
|
||||
document.loadOverlay(aOverlay, DOL_EOL_loadCallback.bind(this));
|
||||
},
|
||||
|
||||
@ -663,12 +693,16 @@ const DownloadsView = {
|
||||
*/
|
||||
_itemCountChanged: function DV_itemCountChanged()
|
||||
{
|
||||
DownloadsCommon.log("The downloads item count has changed - we are tracking",
|
||||
this._dataItems.length, "downloads in total.");
|
||||
let count = this._dataItems.length;
|
||||
let hiddenCount = count - this.kItemCountLimit;
|
||||
|
||||
if (count > 0) {
|
||||
DownloadsCommon.log("Setting the panel's hasdownloads attribute to true.");
|
||||
DownloadsPanel.panel.setAttribute("hasdownloads", "true");
|
||||
} else {
|
||||
DownloadsCommon.log("Removing the panel's hasdownloads attribute.");
|
||||
DownloadsPanel.panel.removeAttribute("hasdownloads");
|
||||
}
|
||||
|
||||
@ -704,6 +738,7 @@ const DownloadsView = {
|
||||
*/
|
||||
onDataLoadStarting: function DV_onDataLoadStarting()
|
||||
{
|
||||
DownloadsCommon.log("onDataLoadStarting called for DownloadsView.");
|
||||
this.loading = true;
|
||||
},
|
||||
|
||||
@ -712,6 +747,8 @@ const DownloadsView = {
|
||||
*/
|
||||
onDataLoadCompleted: function DV_onDataLoadCompleted()
|
||||
{
|
||||
DownloadsCommon.log("onDataLoadCompleted called for DownloadsView.");
|
||||
|
||||
this.loading = false;
|
||||
|
||||
// We suppressed item count change notifications during the batch load, at
|
||||
@ -730,6 +767,9 @@ const DownloadsView = {
|
||||
*/
|
||||
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.
|
||||
@ -755,6 +795,9 @@ const DownloadsView = {
|
||||
*/
|
||||
onDataItemAdded: function DV_onDataItemAdded(aDataItem, aNewest)
|
||||
{
|
||||
DownloadsCommon.log("A new download data item was added - aNewest =",
|
||||
aNewest);
|
||||
|
||||
if (aNewest) {
|
||||
this._dataItems.unshift(aDataItem);
|
||||
} else {
|
||||
@ -790,6 +833,8 @@ const DownloadsView = {
|
||||
*/
|
||||
onDataItemRemoved: function DV_onDataItemRemoved(aDataItem)
|
||||
{
|
||||
DownloadsCommon.log("A download data item was removed.");
|
||||
|
||||
let itemIndex = this._dataItems.indexOf(aDataItem);
|
||||
this._dataItems.splice(itemIndex, 1);
|
||||
|
||||
@ -837,6 +882,9 @@ const DownloadsView = {
|
||||
*/
|
||||
_addViewItem: function DV_addViewItem(aDataItem, aNewest)
|
||||
{
|
||||
DownloadsCommon.log("Adding a new DownloadsViewItem to the downloads list.",
|
||||
"aNewest =", aNewest);
|
||||
|
||||
let element = document.createElement("richlistitem");
|
||||
let viewItem = new DownloadsViewItem(aDataItem, element);
|
||||
this._viewItems[aDataItem.downloadGuid] = viewItem;
|
||||
@ -852,6 +900,7 @@ const DownloadsView = {
|
||||
*/
|
||||
_removeViewItem: function DV_removeViewItem(aDataItem)
|
||||
{
|
||||
DownloadsCommon.log("Removing a DownloadsViewItem from the downloads list.");
|
||||
let element = this.getViewItem(aDataItem)._element;
|
||||
let previousSelectedIndex = this.richListBox.selectedIndex;
|
||||
this.richListBox.removeChild(element);
|
||||
|
@ -59,6 +59,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "RecentWindow",
|
||||
"resource:///modules/RecentWindow.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
|
||||
"resource://gre/modules/PlacesUtils.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "DownloadsLogger",
|
||||
"resource:///modules/DownloadsLogger.jsm");
|
||||
|
||||
const nsIDM = Ci.nsIDownloadManager;
|
||||
|
||||
@ -90,6 +92,22 @@ XPCOMUtils.defineLazyGetter(this, "DownloadsLocalFileCtor", function () {
|
||||
|
||||
const kPartialDownloadSuffix = ".part";
|
||||
|
||||
const kPrefDebug = "browser.download.debug";
|
||||
|
||||
let DebugPrefObserver = {
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
|
||||
Ci.nsISupportsWeakReference]),
|
||||
observe: function PDO_observe(aSubject, aTopic, aData) {
|
||||
this.debugEnabled = Services.prefs.getBoolPref(kPrefDebug);
|
||||
}
|
||||
}
|
||||
|
||||
XPCOMUtils.defineLazyGetter(DebugPrefObserver, "debugEnabled", function () {
|
||||
Services.prefs.addObserver(kPrefDebug, DebugPrefObserver, true);
|
||||
return Services.prefs.getBoolPref(kPrefDebug);
|
||||
});
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// DownloadsCommon
|
||||
|
||||
@ -98,6 +116,27 @@ const kPartialDownloadSuffix = ".part";
|
||||
* and provides shared methods for all the instances of the user interface.
|
||||
*/
|
||||
this.DownloadsCommon = {
|
||||
log: function DC_log(...aMessageArgs) {
|
||||
delete this.log;
|
||||
this.log = function DC_log(...aMessageArgs) {
|
||||
if (!DebugPrefObserver.debugEnabled) {
|
||||
return;
|
||||
}
|
||||
DownloadsLogger.log.apply(DownloadsLogger, aMessageArgs);
|
||||
}
|
||||
this.log.apply(this, aMessageArgs);
|
||||
},
|
||||
|
||||
error: function DC_error(...aMessageArgs) {
|
||||
delete this.error;
|
||||
this.error = function DC_error(...aMessageArgs) {
|
||||
if (!DebugPrefObserver.debugEnabled) {
|
||||
return;
|
||||
}
|
||||
DownloadsLogger.reportError.apply(DownloadsLogger, aMessageArgs);
|
||||
}
|
||||
this.error.apply(this, aMessageArgs);
|
||||
},
|
||||
/**
|
||||
* Returns an object whose keys are the string names from the downloads string
|
||||
* bundle, and whose values are either the translated strings or functions
|
||||
@ -687,7 +726,8 @@ DownloadsDataCtor.prototype = {
|
||||
return existingItem;
|
||||
}
|
||||
}
|
||||
|
||||
DownloadsCommon.log("Creating a new DownloadsDataItem with downloadGuid =",
|
||||
downloadGuid);
|
||||
let dataItem = new DownloadsDataItem(aSource);
|
||||
this.dataItems[downloadGuid] = dataItem;
|
||||
|
||||
@ -759,6 +799,7 @@ DownloadsDataCtor.prototype = {
|
||||
|
||||
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()
|
||||
@ -777,6 +818,7 @@ DownloadsDataCtor.prototype = {
|
||||
this._views.forEach(
|
||||
function (view) view.onDataLoadCompleted()
|
||||
);
|
||||
DownloadsCommon.log("Active downloads done loading.");
|
||||
}
|
||||
} else {
|
||||
if (this._loadState != this.kLoadAll) {
|
||||
@ -784,6 +826,7 @@ DownloadsDataCtor.prototype = {
|
||||
// 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, "
|
||||
@ -834,12 +877,14 @@ DownloadsDataCtor.prototype = {
|
||||
|
||||
handleError: function DD_handleError(aError)
|
||||
{
|
||||
Cu.reportError("Database statement execution error (" + aError.result +
|
||||
"): " + aError.message);
|
||||
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
|
||||
@ -868,13 +913,16 @@ DownloadsDataCtor.prototype = {
|
||||
case "download-manager-remove-download-guid":
|
||||
// If a single download was removed, remove the corresponding data item.
|
||||
if (aSubject) {
|
||||
this._removeDataItem(aSubject.QueryInterface(Ci.nsISupportsCString)
|
||||
.data);
|
||||
let downloadGuid = aSubject.data.QueryInterface(Ci.nsISupportsCString);
|
||||
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
|
||||
@ -883,6 +931,8 @@ DownloadsDataCtor.prototype = {
|
||||
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));
|
||||
@ -916,6 +966,7 @@ DownloadsDataCtor.prototype = {
|
||||
|
||||
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;
|
||||
@ -1034,7 +1085,9 @@ 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;
|
||||
}
|
||||
|
||||
@ -1048,6 +1101,7 @@ DownloadsDataCtor.prototype = {
|
||||
// For new downloads after the first one, don't show the panel
|
||||
// automatically, but provide a visible notification in the topmost
|
||||
// browser window, if the status indicator is already visible.
|
||||
DownloadsCommon.log("Showing new download notification.");
|
||||
browserWin.DownloadsIndicatorView.showEventNotification(aType);
|
||||
return;
|
||||
}
|
||||
|
76
browser/components/downloads/src/DownloadsLogger.jsm
Normal file
76
browser/components/downloads/src/DownloadsLogger.jsm
Normal file
@ -0,0 +1,76 @@
|
||||
/* -*- Mode: js2; js2-basic-offset: 2; indent-tabs-mode: nil; -*- */
|
||||
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
|
||||
/* 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/. */
|
||||
|
||||
/**
|
||||
* The contents of this file were copied almost entirely from
|
||||
* toolkit/identity/LogUtils.jsm. Until we've got a more generalized logging
|
||||
* mechanism for toolkit, I think this is going to be how we roll.
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["DownloadsLogger"];
|
||||
const PREF_DEBUG = "browser.download.debug";
|
||||
|
||||
const Cu = Components.utils;
|
||||
const Ci = Components.interfaces;
|
||||
const Cc = Components.classes;
|
||||
const Cr = Components.results;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
this.DownloadsLogger = {
|
||||
_generateLogMessage: function _generateLogMessage(args) {
|
||||
// create a string representation of a list of arbitrary things
|
||||
let strings = [];
|
||||
|
||||
for (let arg of args) {
|
||||
if (typeof arg === 'string') {
|
||||
strings.push(arg);
|
||||
} else if (arg === undefined) {
|
||||
strings.push('undefined');
|
||||
} else if (arg === null) {
|
||||
strings.push('null');
|
||||
} else {
|
||||
try {
|
||||
strings.push(JSON.stringify(arg, null, 2));
|
||||
} catch(err) {
|
||||
strings.push("<<something>>");
|
||||
}
|
||||
}
|
||||
};
|
||||
return 'Downloads: ' + strings.join(' ');
|
||||
},
|
||||
|
||||
/**
|
||||
* log() - utility function to print a list of arbitrary things
|
||||
*
|
||||
* Enable with about:config pref browser.download.debug
|
||||
*/
|
||||
log: function DL_log(...args) {
|
||||
let output = this._generateLogMessage(args);
|
||||
dump(output + "\n");
|
||||
|
||||
// Additionally, make the output visible in the Error Console
|
||||
Services.console.logStringMessage(output);
|
||||
},
|
||||
|
||||
/**
|
||||
* reportError() - report an error through component utils as well as
|
||||
* our log function
|
||||
*/
|
||||
reportError: function DL_reportError(...aArgs) {
|
||||
// Report the error in the browser
|
||||
let output = this._generateLogMessage(aArgs);
|
||||
Cu.reportError(output);
|
||||
dump("ERROR:" + output + "\n");
|
||||
for (let frame = Components.stack.caller; frame; frame = frame.caller) {
|
||||
dump("\t" + frame + "\n");
|
||||
}
|
||||
}
|
||||
|
||||
};
|
@ -18,8 +18,9 @@ EXTRA_PP_COMPONENTS = \
|
||||
DownloadsStartup.js \
|
||||
$(NULL)
|
||||
|
||||
EXTRA_PP_JS_MODULES = \
|
||||
EXTRA_JS_MODULES = \
|
||||
DownloadsCommon.jsm \
|
||||
DownloadsLogger.jsm \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
Loading…
Reference in New Issue
Block a user