Bug 474492: Update the downloads manager UI, r=gavin

This commit is contained in:
Mark Finkle 2009-04-22 10:59:52 -04:00
Родитель ae1c66c29d
Коммит 9abad7a202
11 изменённых файлов: 890 добавлений и 6 удалений

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

@ -0,0 +1,158 @@
<?xml version="1.0"?>
<!DOCTYPE bindings [
<!ENTITY % browserDTD SYSTEM "chrome://browser/locale/browser.dtd">
%browserDTD;
]>
<bindings
xmlns="http://www.mozilla.org/xbl"
xmlns:xbl="http://www.mozilla.org/xbl"
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<binding id="download-base" extends="chrome://global/content/bindings/richlistbox.xml#richlistitem">
<implementation>
<field name="nsIDLMgr">Components.interfaces.nsIDownloadManager</field>
<property name="paused">
<getter>
<![CDATA[
return parseInt(this.getAttribute("state")) == this.nsIDLMgr.DOWNLOAD_PAUSED;
]]>
</getter>
</property>
<property name="openable">
<getter>
<![CDATA[
return parseInt(this.getAttribute("state")) == this.nsIDLMgr.DOWNLOAD_FINISHED;
]]>
</getter>
</property>
<property name="inProgress">
<getter>
<![CDATA[
var state = parseInt(this.getAttribute("state"));
return state == this.nsIDLMgr.DOWNLOAD_NOTSTARTED ||
state == this.nsIDLMgr.DOWNLOAD_QUEUED ||
state == this.nsIDLMgr.DOWNLOAD_DOWNLOADING ||
state == this.nsIDLMgr.DOWNLOAD_PAUSED ||
state == this.nsIDLMgr.DOWNLOAD_SCANNING;
]]>
</getter>
</property>
<property name="removable">
<getter>
<![CDATA[
var state = parseInt(this.getAttribute("state"));
return state == this.nsIDLMgr.DOWNLOAD_FINISHED ||
state == this.nsIDLMgr.DOWNLOAD_CANCELED ||
state == this.nsIDLMgr.DOWNLOAD_BLOCKED_PARENTAL ||
state == this.nsIDLMgr.DOWNLOAD_BLOCKED_POLICY ||
state == this.nsIDLMgr.DOWNLOAD_DIRTY ||
state == this.nsIDLMgr.DOWNLOAD_FAILED;
]]>
</getter>
</property>
</implementation>
</binding>
<binding id="download-downloading" extends="chrome://browser/content/bindings/downloads.xml#download-base">
<content orient="horizontal" align="start">
<xul:image validate="always" xbl:inherits="src=iconURL"/>
<xul:vbox flex="1">
<xul:hbox align="center">
<xul:label class="title" xbl:inherits="value=target" crop="center" flex="1"/>
<xul:label class="normal" xbl:inherits="value=datetime"/>
</xul:hbox>
<xul:hbox align="center">
<xul:progressmeter anonid="progressmeter" mode="normal" value="0" flex="1" xbl:inherits="value=progress,mode=progressmode"/>
<xul:button class="download-pause" label="&downloadPause.label;"
oncommand="DownloadsView.pauseDownload(document.getBindingParent(this));"/>
<xul:button class="download-cancel" label="&downloadCancel.label;"
oncommand="DownloadsView.cancelDownload(document.getBindingParent(this));"/>
</xul:hbox>
<xul:label class="normal" xbl:inherits="value=status" crop="end"/>
</xul:vbox>
</content>
</binding>
<binding id="download-paused" extends="chrome://browser/content/bindings/downloads.xml#download-base">
<content orient="horizontal" align="start">
<xul:image validate="always" xbl:inherits="src=iconURL"/>
<xul:vbox flex="1">
<xul:hbox align="center">
<xul:label class="title" xbl:inherits="value=target" crop="center" flex="1"/>
<xul:label class="normal" xbl:inherits="value=datetime"/>
</xul:hbox>
<xul:hbox align="center">
<xul:progressmeter anonid="progressmeter" mode="normal" value="0" flex="1" xbl:inherits="value=progress,mode=progressmode"/>
<xul:button class="download-resume" label="&downloadResume.label;"
oncommand="DownloadsView.resumeDownload(document.getBindingParent(this));"/>
<xul:button class="download-cancel" label="&downloadCancel.label;"
oncommand="DownloadsView.cancelDownload(document.getBindingParent(this));"/>
</xul:hbox>
<xul:label class="normal" xbl:inherits="value=status" crop="end"/>
</xul:vbox>
</content>
</binding>
<binding id="download-retry" extends="chrome://browser/content/bindings/downloads.xml#download-base">
<content orient="horizontal" align="start">
<xul:image validate="always" xbl:inherits="src=iconURL"/>
<xul:vbox flex="1">
<xul:hbox align="center">
<xul:label class="title" xbl:inherits="value=target" crop="center" flex="1"/>
<xul:label class="normal" xbl:inherits="value=datetime"/>
</xul:hbox>
<xul:hbox>
<xul:label class="normal" xbl:inherits="value=status" crop="end" flex="1"/>
<xul:button class="download-retry" label="&downloadRetry.label;"
oncommand="DownloadsView.retryDownload(document.getBindingParent(this));"/>
</xul:hbox>
</xul:vbox>
</content>
</binding>
<binding id="download-done" extends="chrome://browser/content/bindings/downloads.xml#download-base">
<content orient="horizontal" align="start">
<xul:image validate="always" xbl:inherits="src=iconURL"/>
<xul:vbox flex="1">
<xul:hbox align="center">
<xul:label class="title" xbl:inherits="value=target" crop="center" flex="1"/>
<xul:label class="normal" xbl:inherits="value=datetime"/>
</xul:hbox>
<xul:hbox>
<xul:label class="normal" xbl:inherits="value=status"/>
</xul:hbox>
<xul:hbox class="show-on-select" align="center">
<xul:button anonid="showpage-button" label="&downloadShowPage.label;"
oncommand="DownloadsView.showPage(document.getBindingParent(this));"/>
<xul:spacer flex="1"/>
<xul:button anonid="show-button" label="&downloadShow.label;"
oncommand="DownloadsView.showDownload(document.getBindingParent(this));"/>
<xul:button anonid="open-button" label="&downloadOpen.label;"
oncommand="DownloadsView.openDownload(document.getBindingParent(this));"/>
<xul:image anonid="remove-button" class="close-button"
onmousedown="DownloadsView.removeDownload(document.getBindingParent(this))"/>
</xul:hbox>
</xul:vbox>
</content>
<implementation>
<constructor>
<![CDATA[
let referrer = this.hasAttribute("referrer");
if (!referrer)
document.getAnonymousElementByAttribute(this, "anonid", "showpage-button").setAttribute("disabled", "true");
let file = DownloadsView._getLocalFile(this.getAttribute("file"));
if (!file.exists()) {
document.getAnonymousElementByAttribute(this, "anonid", "open-button").setAttribute("disabled", "true");
document.getAnonymousElementByAttribute(this, "anonid", "show-button").setAttribute("disabled", "true");
}
]]>
</constructor>
</implementation>
</binding>
</bindings>

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

@ -234,6 +234,9 @@ var BrowserUI = {
browsers.addEventListener("DOMLinkAdded", this, true);
document.getElementById("tabs").addEventListener("TabSelect", this, true);
ExtensionsView.init();
DownloadsView.init();
},
update : function(aState) {
@ -454,11 +457,6 @@ var BrowserUI = {
panelUI.width = container.boxObject.width;
panelUI.height = container.boxObject.height;
ExtensionsView.init();
let dloads = document.getElementById("downloads-container");
if (!dloads.hasAttribute("src"))
dloads.setAttribute("src", "chrome://mozapps/content/downloads/downloads.xul");
if (aPage != undefined)
this.switchPane(aPage);
},

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

@ -125,6 +125,23 @@ richlistitem[selected="true"].section-header {
background-color: lightgray;
}
richlistitem[typeName="download"] {
-moz-binding: url("chrome://browser/content/bindings/downloads.xml#download-downloading");
}
richlistitem[typeName="download"][state="1"] {
-moz-binding: url("chrome://browser/content/bindings/downloads.xml#download-done");
}
richlistitem[typeName="download"][state="2"],
richlistitem[typeName="download"][state="3"] {
-moz-binding: url("chrome://browser/content/bindings/downloads.xml#download-retry");
}
richlistitem[typeName="download"][state="4"] {
-moz-binding: url("chrome://browser/content/bindings/downloads.xml#download-paused");
}
/* addons states ----------------------------------------------------------- */
.hide-on-enable,
.show-on-uninstall,

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

@ -1013,6 +1013,12 @@ function getNotificationBox(aWindow) {
return Browser.getNotificationBox();
}
function showDownloadsManager(aWindowContext, aID, aReason) {
BrowserUI.show(UIMODE_PANEL);
BrowserUI.switchPane("downloads-container");
// TODO: select the download with aID
}
var AlertsHelper = {
_timeoutID: -1,
_listener: null,

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

@ -75,6 +75,7 @@
<script type="application/x-javascript" src="chrome://browser/content/browser-ui.js"/>
<script type="application/x-javascript" src="chrome://browser/content/sanitize.js"/>
<script type="application/x-javascript" src="chrome://browser/content/extensions.js"/>
<script type="application/x-javascript" src="chrome://browser/content/downloads.js"/>
<script type="application/x-javascript" src="chrome://browser/content/WidgetStack.js"/>
<script type="application/x-javascript" src="chrome://browser/content/CanvasBrowser.js"/>
<script type="application/x-javascript" src="chrome://browser/content/InputHandler.js"/>
@ -315,7 +316,24 @@
</notificationbox>
</vbox>
<iframe id="downloads-container" flex="1"/>
<vbox id="downloads-container" flex="1">
<vbox id="downloads-header">
<hbox align="center">
<label value="&downloadsHeader.label;" flex="1"/>
<radiogroup id="downloads-sort-mode" oncommand="DownloadsView.toggleMode();">
<radio label="&downloadsSortDate.label;" value="date" selected="true"/>
<radio label="&downloadsSortSite.label;" value="site"/>
<radio label="&downloadsSortName.label;" value="name"/>
<radio label="&downloadsSearch.label;" value="search"/>
</radiogroup>
</hbox>
<hbox id="downloads-search-box" pack="end" collapsed="true">
<textbox id="downloads-search-text" emptytext="&downloadsSearch.emptytext;" type="search" searchbutton="false"
oncommand="DownloadsView.getDownloads();"/>
</hbox>
</vbox>
<richlistbox id="downloads-list" flex="1"/>
</vbox>
<vbox id="prefs-container" flex="1">
<hbox pack="center" id="buttons"/>

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

@ -0,0 +1,572 @@
// -*- Mode: js2; tab-width: 2; indent-tabs-mode: nil; js2-basic-offset: 2; js2-skip-preprocessor-directives: t; -*-
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Mobile Browser.
*
* The Initial Developer of the Original Code is Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2009
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Mark Finkle <mfinkle@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
Components.utils.import("resource://gre/modules/DownloadUtils.jsm");
const URI_GENERIC_ICON_DOWNLOAD = "chrome://mozapps/skin/downloads/downloadIcon.png";
var DownloadsView = {
_pref: null,
_list: null,
_dlmgr: null,
_progress: null,
_initStatement: function dv__initStatement(aMode) {
aMode = aMode || "date";
if (this._stmt)
this._stmt.finalize();
let order = "endTime DESC, startTime DESC";
if (aMode == "name")
order = "name ASC";
else if (aMode == "site")
order = "REPLACE(REPLACE(REPLACE(source, \"http://\", \"\"), \"https://\", \"\"), \"ftp://\", \"\") ASC";
this._stmt = this._dlmgr.DBConnection.createStatement(
"SELECT id, target, name, source, state, startTime, endTime, referrer, " +
"currBytes, maxBytes, state IN (?1, ?2, ?3, ?4, ?5) isActive " +
"FROM moz_downloads " +
"ORDER BY isActive DESC, " + order);
},
_getLocalFile: function dv__getLocalFile(aFileURI) {
// if this is a URL, get the file from that
let ios = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
// XXX it's possible that using a null char-set here is bad
const fileUrl = ios.newURI(aFileURI, null, null).QueryInterface(Ci.nsIFileURL);
return fileUrl.file.clone().QueryInterface(Ci.nsILocalFile);
},
_getReferrerOrSource: function dv__getReferrerOrSource(aItem) {
// Give the referrer if we have it set, otherwise, provide the source
return aItem.getAttribute("referrer") || aItem.getAttribute("uri");
},
_createItem: function dv__createItem(aAttrs) {
let item = document.createElement("richlistitem");
// Copy the attributes from the argument into the item
for (let attr in aAttrs)
item.setAttribute(attr, aAttrs[attr]);
// Initialize other attributes
item.setAttribute("typeName", "download");
item.setAttribute("id", "dl-" + aAttrs.id);
item.setAttribute("downloadID", aAttrs.id);
item.setAttribute("iconURL", "moz-icon://" + aAttrs.file + "?size=32");
item.setAttribute("lastSeconds", Infinity);
// Initialize more complex attributes
this._updateTime(item);
this._updateStatus(item);
return item;
},
_removeItem: function dv__removeItem(aItem) {
// Make sure we have an item to remove
if (!aItem)
return;
let index = this._list.selectedIndex;
this._list.removeChild(aItem);
this._list.selectedIndex = Math.min(index, this._list.itemCount - 1);
},
_clearList: function dv__clearList() {
// Clear the list by replacing with a shallow copy
let empty = this._list.cloneNode(false);
this._list.parentNode.replaceChild(empty, this._list);
this._list = empty;
},
get visible() {
let panel = document.getElementById("panel-container");
let items = document.getElementById("panel-items");
if (panel.hidden == false && items.selectedPanel.id == "downloads-container")
return true;
return false;
},
init: function dv_init() {
if (this._dlmgr)
return;
this._dlmgr = Cc["@mozilla.org/download-manager;1"].getService(Ci.nsIDownloadManager);
this._pref = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch2);
this._progress = new DownloadProgressListener();
this._dlmgr.addListener(this._progress);
var os = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
os.addObserver(this, "download-manager-remove-download", false);
let self = this;
let panels = document.getElementById("panel-items");
panels.addEventListener("select",
function(aEvent) {
if (panels.selectedPanel.id == "downloads-container")
self.show();
},
false);
},
show: function dv_show() {
if (this._list)
return;
this._list = document.getElementById("downloads-list");
this._initStatement();
this.getDownloads();
},
getDownloads: function dv_getDownloads() {
clearTimeout(this._timeoutID);
this._stmt.reset();
// Array of space-separated lower-case search terms
let search = document.getElementById("downloads-search-text");
this._searchTerms = search.value.trim().toLowerCase().split(/\s+/);
// Clear the list before adding items
this._clearList();
this._stmt.bindInt32Parameter(0, Ci.nsIDownloadManager.DOWNLOAD_NOTSTARTED);
this._stmt.bindInt32Parameter(1, Ci.nsIDownloadManager.DOWNLOAD_DOWNLOADING);
this._stmt.bindInt32Parameter(2, Ci.nsIDownloadManager.DOWNLOAD_PAUSED);
this._stmt.bindInt32Parameter(3, Ci.nsIDownloadManager.DOWNLOAD_QUEUED);
this._stmt.bindInt32Parameter(4, Ci.nsIDownloadManager.DOWNLOAD_SCANNING);
// Take a quick break before we actually start building the list
let self = this;
this._timeoutID = setTimeout(function() {
// Start building the list and select the first item
self._stepDownloads(1);
self._list.selectedIndex = 0;
}, 0);
},
_stepDownloads: function dv__stepDownloads(aNumItems) {
try {
// If we're done adding all items, we can quit
if (!this._stmt.executeStep()) {
// Send a notification that we finished, but wait for clear list to update
setTimeout(function() {
let os = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
os.notifyObservers(window, "download-manager-ui-done", null);
}, 0);
return;
}
// Try to get the attribute values from the statement
let attrs = {
id: this._stmt.getInt64(0),
file: this._stmt.getString(1),
target: this._stmt.getString(2),
uri: this._stmt.getString(3),
state: this._stmt.getInt32(4),
startTime: Math.round(this._stmt.getInt64(5) / 1000),
endTime: Math.round(this._stmt.getInt64(6) / 1000),
currBytes: this._stmt.getInt64(8),
maxBytes: this._stmt.getInt64(9)
};
// Only add the referrer if it's not null
let (referrer = this._stmt.getString(7)) {
if (referrer)
attrs.referrer = referrer;
}
// If the download is active, grab the real progress, otherwise default 100
let isActive = this._stmt.getInt32(10);
attrs.progress = isActive ? this._dlmgr.getDownload(attrs.id).percentComplete : 100;
// Make the item and add it to the end if it's active or matches the search
let item = this._createItem(attrs);
if (item && (isActive || this._matchesSearch(item))) {
// Add item to the end
this._list.appendChild(item);
}
else {
// We didn't add an item, so bump up the number of items to process, but
// not a whole number so that we eventually do pause for a chunk break
aNumItems += .9;
}
}
catch (e) {
// Something went wrong when stepping or getting values, so clear and quit
this._stmt.reset();
return;
}
// Add another item to the list if we should; otherwise, let the UI update
// and continue later
if (aNumItems > 1) {
this._stepDownloads(aNumItems - 1);
}
else {
// Use a shorter delay for earlier downloads to display them faster
let delay = Math.min(this._list.itemCount * 10, 300);
let self = this;
this._timeoutID = setTimeout(function() { self._stepDownloads(5); }, delay);
}
},
_matchesSearch: function dv__matchesSearch(aItem) {
const searchAttributes = ["target", "status", "datetime"];
// Return early if we have no search terms
if (this._searchTerms.length == 0)
return true;
// Search through the download attributes that are shown to the user and
// make it into one big string for easy combined searching
let combinedSearch = "";
for each (let attr in searchAttributes)
combinedSearch += aItem.getAttribute(attr).toLowerCase() + " ";
// Make sure each of the terms are found
for each (let term in this._searchTerms)
if (combinedSearch.search(term) == -1)
return false;
return true;
},
downloadStarted: function dv_downloadStarted(aDownload) {
let attrs = {
id: aDownload.id,
file: aDownload.target.spec,
target: aDownload.displayName,
uri: aDownload.source.spec,
state: aDownload.state,
progress: aDownload.percentComplete,
startTime: Math.round(aDownload.startTime / 1000),
endTime: Date.now(),
currBytes: aDownload.amountTransferred,
maxBytes: aDownload.size
};
// Make the item and add it to the beginning
let item = this._createItem(attrs);
if (item) {
// Add item to the beginning
this._list.insertBefore(item, this._list.firstChild);
}
if (this.visible)
return;
let strings = document.getElementById("bundle_browser");
var notifier = Cc["@mozilla.org/alerts-service;1"].getService(Ci.nsIAlertsService);
notifier.showAlertNotification(URI_GENERIC_ICON_DOWNLOAD, strings.getString("alertDownloads"),
strings.getFormattedString("alertDownloadsStart", [attrs.target]), true, "", this);
},
downloadCompleted: function dv_downloadCompleted(aDownload) {
let element = this.getElementForDownload(aDownload.id);
// Move the download below active if it should stay in the list
if (this._matchesSearch(element)) {
// Iterate down until we find a non-active download
let next = element.nextSibling;
while (next && next.inProgress)
next = next.nextSibling;
// Move the item
this._list.insertBefore(element, next);
}
else {
this._removeItem(element);
}
if (this.visible)
return;
let target = element.getAttribute("target");
let strings = document.getElementById("bundle_browser");
var notifier = Cc["@mozilla.org/alerts-service;1"].getService(Ci.nsIAlertsService);
notifier.showAlertNotification(URI_GENERIC_ICON_DOWNLOAD, strings.getString("alertDownloads"),
strings.getFormattedString("alertDownloadsDone", [target]), true, "", this);
},
_updateStatus: function dv__updateStatus(aItem) {
let strings = document.getElementById("bundle_browser");
let status = "";
let state = Number(aItem.getAttribute("state"));
// Display the file size, but show "Unknown" for negative sizes
let fileSize = Number(aItem.getAttribute("maxBytes"));
let sizeText = strings.getString("downloadsUnknownSize");
if (fileSize >= 0) {
let [size, unit] = DownloadUtils.convertByteUnits(fileSize);
sizeText = this._replaceInsert(strings.getString("downloadsKnownSize"), 1, size);
sizeText = this._replaceInsert(sizeText, 2, unit);
}
// Insert 1 is the download size or download state
status = this._replaceInsert(strings.getString("downloadsStatus"), 1, sizeText);
// Insert 2 is the eTLD + 1 or other variations of the host
let [displayHost, fullHost] = DownloadUtils.getURIHost(this._getReferrerOrSource(aItem));
status = this._replaceInsert(status, 2, displayHost);
aItem.setAttribute("status", status);
},
_updateTime: function dv__updateTime(aItem) {
// Don't bother updating for things that aren't finished
if (aItem.inProgress)
return;
let dts = Cc["@mozilla.org/intl/scriptabledateformat;1"].getService(Ci.nsIScriptableDateFormat);
// Figure out when today begins
let now = new Date();
let today = new Date(now.getFullYear(), now.getMonth(), now.getDate());
// Get the end time to display
let end = new Date(parseInt(aItem.getAttribute("endTime")));
// Figure out if the end time is from today, yesterday, this week, etc.
let dateTime;
if (end >= today) {
// Download finished after today started, show the time
dateTime = dts.FormatTime("", dts.timeFormatNoSeconds, end.getHours(), end.getMinutes(), 0);
}
else if (today - end < (24 * 60 * 60 * 1000)) {
// Download finished after yesterday started, show yesterday
dateTime = "Yesterday";//gStr.yesterday;
}
else if (today - end < (6 * 24 * 60 * 60 * 1000)) {
// Download finished after last week started, show day of week
dateTime = end.toLocaleFormat("%A");
}
else {
// Download must have been from some time ago.. show month/day
let month = end.toLocaleFormat("%B");
// Remove leading 0 by converting the date string to a number
let date = Number(end.toLocaleFormat("%d"));
//dateTime = this._replaceInsert(gStr.monthDate, 1, month);
dateTime = this._replaceInsert("#1 #2", 1, month);
dateTime = this._replaceInsert(dateTime, 2, date);
}
aItem.setAttribute("datetime", dateTime);
},
_replaceInsert: function dv__replaceInsert(aText, aIndex, aValue) {
return aText.replace("#" + aIndex, aValue);
},
toggleMode: function dv_toggleMode() {
let mode = document.getElementById("downloads-sort-mode");
if (mode.value == "search") {
document.getElementById("downloads-search-box").collapsed = false;
document.getElementById("downloads-search-text").value = "";
}
else {
document.getElementById("downloads-search-box").collapsed = true;
this._initStatement(mode.value);
this.getDownloads();
}
},
getElementForDownload: function dv_getElementFromDownload(aID) {
return document.getElementById("dl-" + aID);
},
openDownload: function dv_openDownload(aItem) {
let f = this._getLocalFile(aItem.getAttribute("file"));
try {
f.launch();
} catch (ex) { }
// TODO: add back the code for "dontAsk"?
},
showDownload: function dv_showDownload(aItem) {
let f = this._getLocalFile(aItem.getAttribute("file"));
try {
f.reveal();
} catch (ex) { }
// TODO: add back the extra code?
},
removeDownload: function dv_removeDownload(aItem) {
this._dlmgr.removeDownload(aItem.getAttribute("downloadID"));
},
cancelDownload: function dv_cancelDownload(aItem) {
this._dlmgr.cancelDownload(aItem.getAttribute("downloadID"));
var f = this._getLocalFile(aItem.getAttribute("file"));
if (f.exists())
f.remove(false);
},
pauseDownload: function dv_pauseDownload(aItem) {
this._dlmgr.pauseDownload(aItem.getAttribute("downloadID"));
},
resumeDownload: function dv_resumeDownload(aItem) {
this._dlmgr.resumeDownload(aItem.getAttribute("downloadID"));
},
retryDownload: function dv_retryDownload(aItem) {
this._removeItem(aItem);
this._dlmgr.retryDownload(aItem.getAttribute("downloadID"));
},
showPage: function dv_showPage(aItem) {
BrowserUI.goToURI(this._getReferrerOrSource(aItem));
},
observe: function (aSubject, aTopic, aData) {
switch (aTopic) {
case "download-manager-remove-download":
// A null subject here indicates "remove multiple", so we just rebuild.
if (!aSubject) {
// Rebuild the default view
this.getDownloads();
break;
}
// Otherwise, remove a single download
let id = aSubject.QueryInterface(Ci.nsISupportsPRUint32);
let element = this.getElementForDownload(id.data);
this._removeItem(element);
break;
}
},
QueryInterface: function (aIID) {
if (!aIID.equals(Ci.nsIObserver) &&
!aIID.equals(Ci.nsISupports))
throw Components.results.NS_ERROR_NO_INTERFACE;
return this;
}
};
function DownloadProgressListener() { }
DownloadProgressListener.prototype = {
//////////////////////////////////////////////////////////////////////////////
//// nsIDownloadProgressListener
onDownloadStateChange: function dlPL_onDownloadStateChange(aState, aDownload) {
let state = aDownload.state;
switch (state) {
case Ci.nsIDownloadManager.DOWNLOAD_QUEUED:
DownloadsView.downloadStarted(aDownload);
break;
case Ci.nsIDownloadManager.DOWNLOAD_BLOCKED_POLICY:
DownloadsView.downloadStarted(aDownload);
// Should fall through, this is a final state but DOWNLOAD_QUEUED
// is skipped. See nsDownloadManager::AddDownload.
case Ci.nsIDownloadManager.DOWNLOAD_FAILED:
case Ci.nsIDownloadManager.DOWNLOAD_CANCELED:
case Ci.nsIDownloadManager.DOWNLOAD_BLOCKED_PARENTAL:
case Ci.nsIDownloadManager.DOWNLOAD_DIRTY:
case Ci.nsIDownloadManager.DOWNLOAD_FINISHED:
DownloadsView.downloadCompleted(aDownload);
break;
}
let element = DownloadsView.getElementForDownload(aDownload.id);
// We should eventually know the referrer at some point
let referrer = aDownload.referrer;
if (referrer && element.getAttribute("referrer") != referrer.spec)
element.setAttribute("referrer", referrer.spec);
// Update to the new state
element.setAttribute("state", state);
element.setAttribute("currBytes", aDownload.amountTransferred);
element.setAttribute("maxBytes", aDownload.size);
element.setAttribute("endTime", Date.now());
// Update ui text values after switching states
DownloadsView._updateTime(element);
DownloadsView._updateStatus(element);
},
onProgressChange: function(aWebProgress, aRequest, aCurSelfProgress, aMaxSelfProgress, aCurTotalProgress, aMaxTotalProgress, aDownload) {
let element = DownloadsView.getElementForDownload(aDownload.id);
if (!element)
return;
// Update this download's progressmeter
if (aDownload.percentComplete == -1) {
element.setAttribute("progressmode", "undetermined");
}
else {
element.setAttribute("progressmode", "normal");
element.setAttribute("progress", aDownload.percentComplete);
}
// Dispatch ValueChange for a11y
let event = document.createEvent("Events");
event.initEvent("ValueChange", true, true);
let progmeter = document.getAnonymousElementByAttribute(element, "anonid", "progressmeter");
if (progmeter)
progmeter.dispatchEvent(event);
// Update the progress so the status can be correctly updated
element.setAttribute("currBytes", aDownload.amountTransferred);
element.setAttribute("maxBytes", aDownload.size);
// Update the rest of the UI
DownloadsView._updateStatus(element);
},
onStateChange: function(aWebProgress, aRequest, aState, aStatus, aDownload) { },
onSecurityChange: function(aWebProgress, aRequest, aState, aDownload) { },
//////////////////////////////////////////////////////////////////////////////
//// nsISupports
QueryInterface: function (aIID) {
if (!aIID.equals(Ci.nsIDownloadProgressListener) &&
!aIID.equals(Ci.nsISupports))
throw Components.results.NS_ERROR_NO_INTERFACE;
return this;
}
};

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

@ -11,6 +11,7 @@ browser.jar:
content/checkbox.xml (content/checkbox.xml)
content/notification.xml (content/notification.xml)
content/bindings/extensions.xml (content/bindings/extensions.xml)
content/bindings/downloads.xml (content/bindings/downloads.xml)
content/browser.css (content/browser.css)
content/scrollbars.css (content/scrollbars.css)
content/content.css (content/content.css)
@ -23,3 +24,4 @@ browser.jar:
content/CanvasBrowser.js (content/CanvasBrowser.js)
content/InputHandler.js (content/InputHandler.js)
content/extensions.js (content/extensions.js)
content/downloads.js (content/downloads.js)

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

@ -54,6 +54,7 @@ EXTRA_COMPONENTS = \
geolocationPrompt.js \
alertsService.js \
xpiDialogService.js \
downloadManagerUI.js \
$(NULL)
DIRS = protocols \

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

@ -0,0 +1,84 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Alerts Service.
*
* The Initial Developer of the Original Code is Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2009
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Mark Finkle <mfinkle@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
const Cc = Components.classes;
const Ci = Components.interfaces;
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
// -----------------------------------------------------------------------
// Download Manager UI
// -----------------------------------------------------------------------
function DownloadManagerUI() { }
DownloadManagerUI.prototype = {
classDescription: "Download Manager UI",
contractID: "@mozilla.org/download-manager-ui;1",
classID: Components.ID("{93db15b1-b408-453e-9a2b-6619e168324a}"),
show: function show(aWindowContext, aID, aReason) {
if (!aReason)
aReason = Ci.nsIDownloadManagerUI.REASON_USER_INTERACTED;
let wm = Cc["@mozilla.org/appshell/window-mediator;1"].getService(Ci.nsIWindowMediator);
let browser = wm.getMostRecentWindow("navigator:browser");
if (browser)
browser.showDownloadManager(aWindowContext, aID, aReason);
},
get visible() {
let wm = Cc["@mozilla.org/appshell/window-mediator;1"].getService(Ci.nsIWindowMediator);
let browser = wm.getMostRecentWindow("navigator:browser");
if (browser) {
return browser.DownloadsView.visible;
}
return false;
},
getAttention: function getAttention() {
if (this.visible)
this.show(null, null, null);
else
throw Cr.NS_ERROR_UNEXPECTED;
},
QueryInterface: XPCOMUtils.generateQI([Ci.nsIDownloadManagerUI])
};
function NSGetModule(aCompMgr, aFileSpec) {
return XPCOMUtils.generateModule([DownloadManagerUI]);
}

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

@ -63,6 +63,21 @@
<!ENTITY addonUninstall.label "Uninstall">
<!ENTITY addonCancel.label "Cancel">
<!ENTITY downloadsHeader.label "Downloads">
<!ENTITY downloadsSortDate.label "By Date">
<!ENTITY downloadsSortSite.label "By Site">
<!ENTITY downloadsSortName.label "By Name">
<!ENTITY downloadsSearch.label "Search">
<!ENTITY downloadsSearch.emptytext "Search for downloaded file">
<!ENTITY downloadShowPage.label "Go to Page">
<!ENTITY downloadShow.label "Find File">
<!ENTITY downloadOpen.label "Open File">
<!ENTITY downloadCancel.label "Cancel">
<!ENTITY downloadPause.label "Pause">
<!ENTITY downloadResume.label "Resume">
<!ENTITY downloadRetry.label "Retry">
<!ENTITY identity.unverifiedsite2 "This web site does not supply identity information.">
<!ENTITY identity.connectedTo "You are connected to">
<!-- Localization note (identity.runBy) : This string appears between a

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

@ -12,12 +12,25 @@ addonsSearchNone.button=OK
addonsSearchFail.label=%S couldn't retrieve add-ons
addonsSearchFail.button=OK
# Download Manager
# LOCALIZATION NOTE (Status): — is the "em dash" (long dash)
# #1 download size for FINISHED or download state; #2 host (e.g., eTLD + 1, IP)
downloadsStatus=#1 — #2
downloadsUnknownSize=Unknown size
# LOCALIZATION NOTE (KnownSize): #1 size number; #2 size unit
downloadsKnownSize=#1 #2
donwloadsYesterday=Yesterday
# LOCALIZATION NOTE (MonthDate): #1 month name; #2 date number; e.g., January 22
downloadsMonthDate=#1 #2
# Alerts
alertAddons=Add-ons
alertAddonsStart=Installing addons
alertAddonsDone=Installation complete
alertAddonsFail=Installation failed
alertDownloads=Downloads
alertDownloadsStart=Downloading: %S
alertDownloadsDone=%S has finished downloading
# Popup Blocker
popupWarning=%S prevented this site from opening a pop-up window.