зеркало из https://github.com/mozilla/gecko-dev.git
Bug 695178 - Download Manager. r=mfinkle,wesj
This commit is contained in:
Родитель
91df92bc66
Коммит
17b4366fa5
|
@ -517,8 +517,7 @@ abstract public class GeckoApp
|
|||
loadUrlInTab("about:addons");
|
||||
return true;
|
||||
case R.id.downloads:
|
||||
intent = new Intent(DownloadManager.ACTION_VIEW_DOWNLOADS);
|
||||
startActivity(intent);
|
||||
loadUrlInTab("about:downloads");
|
||||
return true;
|
||||
case R.id.char_encoding:
|
||||
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("CharEncoding:Get", null));
|
||||
|
|
|
@ -178,7 +178,6 @@ FENNEC_PP_JAVA_FILES = \
|
|||
FENNEC_PP_XML_FILES = \
|
||||
res/layout/abouthome_content.xml \
|
||||
res/menu/gecko_menu.xml \
|
||||
res/menu-v11/gecko_menu.xml \
|
||||
$(NULL)
|
||||
|
||||
|
||||
|
|
|
@ -1,48 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<item android:id="@+id/reload"
|
||||
android:icon="@drawable/ic_menu_reload"
|
||||
android:title="@string/reload"/>
|
||||
|
||||
<item android:id="@+id/forward"
|
||||
android:icon="@drawable/ic_menu_forward"
|
||||
android:title="@string/forward"/>
|
||||
|
||||
<item android:id="@+id/bookmark"
|
||||
android:icon="@drawable/ic_menu_bookmark_add"
|
||||
android:title="@string/bookmark"/>
|
||||
|
||||
<item android:id="@+id/share"
|
||||
android:icon="@drawable/ic_menu_share"
|
||||
android:title="@string/share" />
|
||||
|
||||
<item android:id="@+id/save_as_pdf"
|
||||
android:icon="@drawable/ic_menu_save_as_pdf"
|
||||
android:title="@string/save_as_pdf" />
|
||||
|
||||
<item android:id="@+id/site_settings"
|
||||
android:title="@string/site_settings_title" />
|
||||
|
||||
<item android:id="@+id/addons"
|
||||
android:title="@string/addons"/>
|
||||
|
||||
<item android:id="@+id/downloads"
|
||||
android:title="@string/downloads"/>
|
||||
|
||||
<item android:id="@+id/char_encoding"
|
||||
android:visible="false"
|
||||
android:title="@string/char_encoding"/>
|
||||
|
||||
<item android:id="@+id/settings"
|
||||
android:title="@string/settings" />
|
||||
|
||||
#ifdef MOZ_PROFILING
|
||||
<item android:id="@+id/toggle_profiling"
|
||||
android:title="@string/toggle_profiling" />
|
||||
#endif
|
||||
|
||||
<item android:id="@+id/quit"
|
||||
android:title="@string/quit"
|
||||
android:orderInCategory="10" />
|
||||
</menu>
|
|
@ -28,8 +28,7 @@
|
|||
android:title="@string/addons"/>
|
||||
|
||||
<item android:id="@+id/downloads"
|
||||
android:title="@string/downloads"
|
||||
android:visible="false"/>
|
||||
android:title="@string/downloads"/>
|
||||
|
||||
<item android:id="@+id/char_encoding"
|
||||
android:visible="false"
|
||||
|
|
|
@ -0,0 +1,221 @@
|
|||
/* 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/. */
|
||||
|
||||
let Ci = Components.interfaces, Cc = Components.classes, Cu = Components.utils;
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/DownloadUtils.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
let gStrings = Services.strings.createBundle("chrome://browser/locale/aboutDownloads.properties");
|
||||
|
||||
let downloadTemplate =
|
||||
"<li downloadID='{id}' role='button' mozDownload=''>" +
|
||||
"<img class='icon' src='{icon}'/>" +
|
||||
"<div class='details'>" +
|
||||
"<div class='row'>" +
|
||||
// This is a hack so that we can crop this label in its center
|
||||
"<xul:label class='title' crop='center' value='{target}'/>" +
|
||||
"<div class='date'>{date}</div>" +
|
||||
"</div>" +
|
||||
"<div class='size'>{size}</div>" +
|
||||
"<div class='domain'>{domain}</div>" +
|
||||
"</div>" +
|
||||
"</li>";
|
||||
|
||||
XPCOMUtils.defineLazyGetter(window, "gChromeWin", function ()
|
||||
window.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIWebNavigation)
|
||||
.QueryInterface(Ci.nsIDocShellTreeItem)
|
||||
.rootTreeItem
|
||||
.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDOMWindow)
|
||||
.QueryInterface(Ci.nsIDOMChromeWindow));
|
||||
|
||||
let Downloads = {
|
||||
init: function () {
|
||||
this._list = document.getElementById("downloads-list");
|
||||
this._list.addEventListener("click", function (event) {
|
||||
let target = event.target;
|
||||
while (target && target.nodeName != "li") {
|
||||
target = target.parentNode;
|
||||
}
|
||||
|
||||
Downloads.openDownload(target);
|
||||
}, false);
|
||||
|
||||
let contextmenus = gChromeWin.NativeWindow.contextmenus;
|
||||
Downloads.openMenuItem = contextmenus.add(gStrings.GetStringFromName("downloadAction.open"),
|
||||
contextmenus.SelectorContext("li[mozDownload]"),
|
||||
function (aTarget) {
|
||||
Downloads.openDownload(aTarget);
|
||||
}
|
||||
);
|
||||
Downloads.removeMenuItem = contextmenus.add(gStrings.GetStringFromName("downloadAction.remove"),
|
||||
contextmenus.SelectorContext("li[mozDownload]"),
|
||||
function (aTarget) {
|
||||
Downloads.removeDownload(aTarget);
|
||||
}
|
||||
);
|
||||
|
||||
Services.obs.addObserver(this, "dl-failed", false);
|
||||
Services.obs.addObserver(this, "dl-done", false);
|
||||
Services.obs.addObserver(this, "dl-cancel", false);
|
||||
|
||||
this.getDownloads();
|
||||
},
|
||||
|
||||
uninit: function () {
|
||||
let contextmenus = gChromeWin.NativeWindow.contextmenus;
|
||||
contextmenus.remove(this.openMenuItem);
|
||||
contextmenus.remove(this.removeMenuItem);
|
||||
|
||||
Services.obs.removeObserver(this, "dl-failed");
|
||||
Services.obs.removeObserver(this, "dl-done");
|
||||
Services.obs.removeObserver(this, "dl-cancel");
|
||||
},
|
||||
|
||||
observe: function (aSubject, aTopic, aData) {
|
||||
let download = aSubject.QueryInterface(Ci.nsIDownload);
|
||||
switch (aTopic) {
|
||||
case "dl-failed":
|
||||
case "dl-cancel":
|
||||
case "dl-done":
|
||||
if (!this._getElementForDownload(download.id)) {
|
||||
let item = this._createItem(downloadTemplate, {
|
||||
id: download.id,
|
||||
target: download.displayName,
|
||||
icon: "moz-icon://" + download.displayName + "?size=64",
|
||||
date: DownloadUtils.getReadableDates(new Date())[0],
|
||||
domain: DownloadUtils.getURIHost(download.source.spec)[0],
|
||||
size: DownloadUtils.convertByteUnits(download.size).join(""),
|
||||
});
|
||||
this._list.insertAdjacentHTML("afterbegin", item);
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_initStatement: function dv__initStatement() {
|
||||
if (this._stmt)
|
||||
this._stmt.finalize();
|
||||
|
||||
this._stmt = this._dlmgr.DBConnection.createStatement(
|
||||
"SELECT id, name, source, state, startTime, endTime, referrer, " +
|
||||
"currBytes, maxBytes, state IN (?1, ?2, ?3, ?4, ?5) isActive " +
|
||||
"FROM moz_downloads " +
|
||||
"WHERE NOT isActive " +
|
||||
"ORDER BY endTime DESC");
|
||||
},
|
||||
|
||||
_createItem: function (aTemplate, aValues) {
|
||||
let t = aTemplate;
|
||||
for (let i in aValues) {
|
||||
let regEx = new RegExp("{" + i + "}", "g");
|
||||
t = t.replace(regEx, aValues[i]);
|
||||
}
|
||||
return t;
|
||||
},
|
||||
|
||||
_stepDownloads: function dv__stepDownloads(aNumItems) {
|
||||
try {
|
||||
if (!this._stmt.executeStep()) {
|
||||
this._stmt.finalize();
|
||||
this._stmt = null;
|
||||
return;
|
||||
}
|
||||
|
||||
// Try to get the attribute values from the statement
|
||||
let attrs = {
|
||||
id: this._stmt.row.id,
|
||||
target: this._stmt.row.name,
|
||||
icon: "moz-icon://" + this._stmt.row.name + "?size=64",
|
||||
date: DownloadUtils.getReadableDates(new Date(this._stmt.row.endTime/1000))[0],
|
||||
domain: DownloadUtils.getURIHost(this._stmt.row.source)[0],
|
||||
size: DownloadUtils.convertByteUnits(this._stmt.row.maxBytes).join(""),
|
||||
};
|
||||
|
||||
let item = this._createItem(downloadTemplate, attrs);
|
||||
this._list.insertAdjacentHTML("beforeend", item);
|
||||
} catch (e) {
|
||||
// Something went wrong when stepping or getting values, so clear and quit
|
||||
console.log("Error: " + e);
|
||||
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);
|
||||
}
|
||||
},
|
||||
|
||||
getDownloads: function () {
|
||||
this._dlmgr = Cc["@mozilla.org/download-manager;1"].getService(Ci.nsIDownloadManager);
|
||||
|
||||
this._initStatement();
|
||||
|
||||
clearTimeout(this._timeoutID);
|
||||
|
||||
this._stmt.reset();
|
||||
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 () {
|
||||
self._stepDownloads(1);
|
||||
}, 0);
|
||||
},
|
||||
|
||||
_getElementForDownload: function (aKey) {
|
||||
return this._list.querySelector("li[downloadID='" + aKey + "']");
|
||||
},
|
||||
|
||||
_getDownloadForElement: function (aElement) {
|
||||
let id = parseInt(aElement.getAttribute("downloadID"));
|
||||
return this._dlmgr.getDownload(id);
|
||||
},
|
||||
|
||||
openDownload: function (aItem) {
|
||||
let f = null;
|
||||
try {
|
||||
let download = this._getDownloadForElement(aItem);
|
||||
f = download.targetFile;
|
||||
} catch(ex) { }
|
||||
|
||||
try {
|
||||
if (f) f.launch();
|
||||
} catch (ex) { }
|
||||
},
|
||||
|
||||
removeDownload: function (aItem) {
|
||||
let f = null;
|
||||
try {
|
||||
let download = this._getDownloadForElement(aItem);
|
||||
f = download.targetFile;
|
||||
} catch(ex) {
|
||||
// even if there is no file, pretend that there is so that we can remove
|
||||
// it from the list
|
||||
f = { leafName: "" };
|
||||
}
|
||||
|
||||
this._dlmgr.removeDownload(aItem.getAttribute("downloadID"));
|
||||
|
||||
this._list.removeChild(aItem);
|
||||
|
||||
try {
|
||||
if (f) f.remove(false);
|
||||
} catch(ex) { }
|
||||
},
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
|
||||
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd" [
|
||||
<!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd" >
|
||||
%brandDTD;
|
||||
<!ENTITY % globalDTD SYSTEM "chrome://global/locale/global.dtd" >
|
||||
%globalDTD;
|
||||
<!ENTITY % downloadsDTD SYSTEM "chrome://browser/locale/aboutDownloads.dtd" >
|
||||
%downloadsDTD;
|
||||
]>
|
||||
|
||||
<!-- 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/. -->
|
||||
|
||||
<html xmlns="http://www.w3.org/1999/xhtml"
|
||||
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
<head>
|
||||
<title>&aboutDownloads.title;</title>
|
||||
<meta name="viewport" content="width=480; initial-scale=.6667; user-scalable=0" />
|
||||
<link rel="icon" type="image/png" href="chrome://branding/content/favicon32.png" />
|
||||
<link rel="stylesheet" href="chrome://browser/skin/aboutDownloads.css" type="text/css"/>
|
||||
</head>
|
||||
|
||||
<body dir="&locale.dir;" onload="Downloads.init();" onunload="Downloads.uninit();">
|
||||
<div class="header">
|
||||
<div>&aboutDownloads.header;</div>
|
||||
</div>
|
||||
<ul id="downloads-list"></ul>
|
||||
<span id="no-downloads-indicator">&aboutDownloads.empty;</span>
|
||||
<script type="application/javascript;version=1.8" src="chrome://browser/content/aboutDownloads.js"/>
|
||||
</body>
|
||||
</html>
|
|
@ -8,6 +8,8 @@ chrome.jar:
|
|||
content/aboutAddons.xhtml (content/aboutAddons.xhtml)
|
||||
content/aboutAddons.js (content/aboutAddons.js)
|
||||
content/aboutCertError.xhtml (content/aboutCertError.xhtml)
|
||||
content/aboutDownloads.xhtml (content/aboutDownloads.xhtml)
|
||||
content/aboutDownloads.js (content/aboutDownloads.js)
|
||||
content/aboutHome.xhtml (content/aboutHome.xhtml)
|
||||
* content/aboutRights.xhtml (content/aboutRights.xhtml)
|
||||
* content/aboutApps.xhtml (content/aboutApps.xhtml)
|
||||
|
|
|
@ -89,6 +89,10 @@ let modules = {
|
|||
apps: {
|
||||
uri: "chrome://browser/content/aboutApps.xhtml",
|
||||
privileged: true
|
||||
},
|
||||
downloads: {
|
||||
uri: "chrome://browser/content/aboutDownloads.xhtml",
|
||||
privileged: true
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ contract @mozilla.org/network/protocol/about;1?what=rights {322ba47e-7047-4f71-a
|
|||
contract @mozilla.org/network/protocol/about;1?what=certerror {322ba47e-7047-4f71-aebf-cb7d69325cd9}
|
||||
contract @mozilla.org/network/protocol/about;1?what=home {322ba47e-7047-4f71-aebf-cb7d69325cd9}
|
||||
contract @mozilla.org/network/protocol/about;1?what=apps {322ba47e-7047-4f71-aebf-cb7d69325cd9}
|
||||
contract @mozilla.org/network/protocol/about;1?what=downloads {322ba47e-7047-4f71-aebf-cb7d69325cd9}
|
||||
#ifdef MOZ_SAFE_BROWSING
|
||||
contract @mozilla.org/network/protocol/about;1?what=blocked {322ba47e-7047-4f71-aebf-cb7d69325cd9}
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
<!ENTITY aboutDownloads.title "Downloads">
|
||||
<!ENTITY aboutDownloads.header "Your Downloads">
|
||||
<!ENTITY aboutDownloads.empty "No Downloads">
|
|
@ -0,0 +1,2 @@
|
|||
downloadAction.open=Open
|
||||
downloadAction.remove=Delete
|
|
@ -8,6 +8,8 @@
|
|||
locale/@AB_CD@/browser/aboutApps.dtd (%chrome/aboutApps.dtd)
|
||||
locale/@AB_CD@/browser/aboutApps.properties (%chrome/aboutApps.properties)
|
||||
locale/@AB_CD@/browser/aboutCertError.dtd (%chrome/aboutCertError.dtd)
|
||||
locale/@AB_CD@/browser/aboutDownloads.dtd (%chrome/aboutDownloads.dtd)
|
||||
locale/@AB_CD@/browser/aboutDownloads.properties (%chrome/aboutDownloads.properties)
|
||||
locale/@AB_CD@/browser/browser.properties (%chrome/browser.properties)
|
||||
locale/@AB_CD@/browser/config.dtd (%chrome/config.dtd)
|
||||
locale/@AB_CD@/browser/config.properties (%chrome/config.properties)
|
||||
|
|
|
@ -0,0 +1,120 @@
|
|||
/* 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/. */
|
||||
|
||||
%filter substitution
|
||||
%include defines.inc
|
||||
|
||||
html {
|
||||
font-family: "Droid Sans",helvetica,arial,clean,sans-serif;
|
||||
font-size: 18px;
|
||||
background-image: url("chrome://browser/skin/images/about-bg-lightblue.png");
|
||||
-moz-text-size-adjust: none;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
li > a {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.header {
|
||||
color: black;
|
||||
padding: 10px;
|
||||
-moz-padding-start: 25px;
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
border-bottom: 2px solid;
|
||||
-moz-border-bottom-colors: #ff9100 #f27900;
|
||||
}
|
||||
|
||||
.header > div {
|
||||
width: 100%;
|
||||
height: 45px;
|
||||
display: -moz-box;
|
||||
-moz-box-align: center;
|
||||
}
|
||||
|
||||
ul {
|
||||
padding: 0px;
|
||||
margin: 0px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
li {
|
||||
color: black;
|
||||
background-image: url("chrome://browser/skin/images/row-bg-normal.png");
|
||||
border-bottom: 2px solid;
|
||||
-moz-border-bottom-colors: #ffffff #bac2ac;
|
||||
position: relative;
|
||||
list-style-type: none;
|
||||
list-style-image: none;
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
color: black;
|
||||
height: 86px;
|
||||
font-size: 18px !important;
|
||||
}
|
||||
|
||||
li:active {
|
||||
background-color: @color_background_highlight_overlay@;
|
||||
background-image: none;
|
||||
}
|
||||
|
||||
li:active .details {
|
||||
background-image: none;
|
||||
}
|
||||
|
||||
.icon {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
position: absolute;
|
||||
top: 27px;
|
||||
left: 27px;
|
||||
}
|
||||
|
||||
.details {
|
||||
margin-left: 86px;
|
||||
padding: 10px;
|
||||
min-height: 66px;
|
||||
background-image: url("chrome://browser/skin/images/row-bg-light.png");
|
||||
}
|
||||
|
||||
.row {
|
||||
display: -moz-box;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 22px;
|
||||
font-weight: bold;
|
||||
overflow: hidden;
|
||||
-moz-box-flex: 1;
|
||||
}
|
||||
|
||||
.date {
|
||||
color: gray;
|
||||
}
|
||||
|
||||
.domain,
|
||||
.size {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.size:after {
|
||||
content: " - ";
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
#no-downloads-indicator {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#downloads-list:empty + #no-downloads-indicator {
|
||||
display: block;
|
||||
text-align: center;
|
||||
padding-top: 70px;
|
||||
}
|
|
@ -6,6 +6,7 @@ chrome.jar:
|
|||
skin/about.css (about.css)
|
||||
skin/aboutAddons.css (aboutAddons.css)
|
||||
skin/aboutApps.css (aboutApps.css)
|
||||
* skin/aboutDownloads.css (aboutDownloads.css)
|
||||
* skin/browser.css (browser.css)
|
||||
* skin/content.css (content.css)
|
||||
skin/config.css (config.css)
|
||||
|
|
Загрузка…
Ссылка в новой задаче