Bug 411490: Add about:crashes for easier access to crash reports. r=mano, a=beltzner
authordtownsend@oxymoronical.com
Thu, 24 Jan 2008 08:11:09 -0800
changeset 10628 7fefda4b80d4c6424fe1919c9d88de314e908331
parent 10627 bfe134e3e27496961dbe317bcdeead9460601c1d
child 10629 6262b6c25cdd897b8336886a47edf969e19f04ea
push idunknown
push userunknown
push dateunknown
reviewersmano, beltzner
bugs411490
milestone1.9b3pre
Bug 411490: Add about:crashes for easier access to crash reports. r=mano, a=beltzner
docshell/base/nsAboutRedirector.cpp
docshell/build/nsDocShellModule.cpp
toolkit/crashreporter/content/crashes.xhtml
toolkit/crashreporter/jar.mn
toolkit/locales/en-US/crashreporter/crashes.dtd
toolkit/locales/en-US/crashreporter/crashes.properties
toolkit/locales/jar.mn
--- a/docshell/base/nsAboutRedirector.cpp
+++ b/docshell/base/nsAboutRedirector.cpp
@@ -65,16 +65,19 @@ struct RedirEntry {
  */
 static RedirEntry kRedirMap[] = {
     { "credits", "http://www.mozilla.org/credits/",
       nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT },
     { "mozilla", "chrome://global/content/mozilla.xhtml",
       nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT },
     { "plugins", "chrome://global/content/plugins.html", 0 },
     { "config", "chrome://global/content/config.xul", 0 },
+#ifdef MOZ_CRASHREPORTER
+    { "crashes", "chrome://global/content/crashes.xhtml", 0 },
+#endif
 #ifdef MOZ_XUL_APP
     { "logo", "chrome://branding/content/about.png",
 #else
     { "logo", "chrome://global/content/logo.gif",
 #endif
       nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT},
     { "buildconfig", "chrome://global/content/buildconfig.html",
       nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT },
--- a/docshell/build/nsDocShellModule.cpp
+++ b/docshell/build/nsDocShellModule.cpp
@@ -151,16 +151,23 @@ static const nsModuleComponentInfo gDocS
     },
 
     // about redirector
     { "about:config",
       NS_ABOUT_REDIRECTOR_MODULE_CID,
       NS_ABOUT_MODULE_CONTRACTID_PREFIX "config",
       nsAboutRedirector::Create
     },
+#ifdef MOZ_CRASHREPORTER
+    { "about:crashes",
+      NS_ABOUT_REDIRECTOR_MODULE_CID,
+      NS_ABOUT_MODULE_CONTRACTID_PREFIX "crashes",
+      nsAboutRedirector::Create
+    },
+#endif
     { "about:credits",
       NS_ABOUT_REDIRECTOR_MODULE_CID,
       NS_ABOUT_MODULE_CONTRACTID_PREFIX "credits",
       nsAboutRedirector::Create
     },
     { "about:plugins",
       NS_ABOUT_REDIRECTOR_MODULE_CID,
       NS_ABOUT_MODULE_CONTRACTID_PREFIX "plugins",
new file mode 100644
--- /dev/null
+++ b/toolkit/crashreporter/content/crashes.xhtml
@@ -0,0 +1,206 @@
+<?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 % globalDTD SYSTEM "chrome://global/locale/global.dtd">
+  <!ENTITY % crashesDTD SYSTEM "chrome://global/locale/crashes.dtd">
+  %globalDTD;
+  %crashesDTD;
+]>
+
+#ifdef MOZ_THUNDERBIRD
+#ifdef XP_MACOSX
+#define FORCE_DIR
+#endif
+#endif
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<style type="text/css">
+:root {
+  font-family: sans-serif;
+}
+table {
+  padding-bottom: 2em;
+}
+th {
+  text-align: left;
+  white-space: nowrap;
+}
+/* name */
+th:first-child {
+  -moz-padding-end: 2em;
+}
+/* date */
+td:first-child + td {
+  -moz-padding-start: 1em;
+  -moz-padding-end: .5em;
+  white-space: nowrap;
+}
+/* time */
+td:last-child {
+  -moz-padding-start: .5em;
+  white-space: nowrap;
+}
+.clear-reports {
+  float: right;
+}
+
+th[chromedir="rtl"] {
+  text-align: right;
+}
+.clear-reports[chromedir="rtl"] {
+  float: left;
+}
+</style>
+<link rel="stylesheet" media="screen, projection" type="text/css"
+      href="chrome://global/skin/dirListing/dirListing.css"/>
+<script type="application/javascript">
+<![CDATA[
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+
+var reportsDir;
+
+function findInsertionPoint(reports, date) {
+  if (reports.length == 0)
+    return 0;
+
+  var min = 0;
+  var max = reports.length - 1;
+  while (min < max) {
+    var mid = parseInt((min + max) / 2);
+    if (reports[mid].date < date)
+      max = mid - 1;
+    else if (reports[mid].date > date)
+      min = mid + 1;
+    else
+      return mid;
+  }
+  if (reports[min].date <= date)
+    return min;
+  return min+1;
+}
+
+function populateReportList() {
+  var prefService = Cc["@mozilla.org/preferences-service;1"].
+                    getService(Ci.nsIPrefBranch);
+  var reportURL = prefService.getCharPref("breakpad.reportURL");
+  var directoryService = Cc["@mozilla.org/file/directory_service;1"].
+                         getService(Ci.nsIProperties);
+
+#ifdef FORCE_DIR
+  var app = Cc["@mozilla.org/xre/app-info;1"].
+            getService(Ci.nsIXULAppInfo);
+
+  // Doesn't appear to be a key for the app support directory
+  reportsDir = directoryService.get("ULibDir", Ci.nsIFile);
+  reportsDir.append("Application Support");
+  reportsDir.append(app.name);
+#else
+  reportsDir = directoryService.get("UAppData", Ci.nsIFile);
+#endif
+  reportsDir.append("Crash Reports");
+  reportsDir.append("submitted");
+
+  var reports = [];
+  if (reportsDir.exists() && reportsDir.isDirectory()) {
+    var entries = reportsDir.directoryEntries;
+    while (entries.hasMoreElements()) {
+      var file = entries.getNext().QueryInterface(Ci.nsIFile);
+      var leaf = file.leafName;
+      if (leaf.substring(0, 3) == "bp-" &&
+          leaf.substring(leaf.length - 4) == ".txt") {
+        var entry = {
+          id: leaf.substring(3, leaf.length - 4),
+          date: file.lastModifiedTime
+        };
+        var pos = findInsertionPoint(reports, entry.date);
+        reports.splice(pos, 0, entry);
+      }
+    }
+  }
+
+  if (reports.length == 0) {
+    document.getElementById("reportList").style.display = "none";
+    document.getElementById("noReports").style.display = "block";
+    return;
+  }
+
+  var formatter = Cc["@mozilla.org/intl/scriptabledateformat;1"].
+                  createInstance(Ci.nsIScriptableDateFormat);
+  var body = document.getElementById("tbody");
+  for (var i = 0; i < reports.length; i++) {
+    var row = document.createElement("tr");
+    var cell = document.createElement("td");
+    row.appendChild(cell);
+    var link = document.createElement("a");
+    link.setAttribute("href", reportURL + reports[i].id);
+    link.appendChild(document.createTextNode(reports[i].id));
+    cell.appendChild(link);
+
+    var date = new Date(reports[i].date);
+    cell = document.createElement("td");
+    var datestr = formatter.FormatDate("",
+                                       Ci.nsIScriptableDateFormat.dateFormatShort,
+                                       date.getFullYear(),
+                                       date.getMonth() + 1,
+                                       date.getDate());
+    cell.appendChild(document.createTextNode(datestr));
+    row.appendChild(cell);
+    cell = document.createElement("td");
+    var timestr = formatter.FormatTime("",
+                                       Ci.nsIScriptableDateFormat.timeFormatNoSeconds,
+                                       date.getHours(),
+                                       date.getMinutes(),
+                                       date.getSeconds());
+    cell.appendChild(document.createTextNode(timestr));
+    row.appendChild(cell);
+    body.appendChild(row);
+  }
+}
+
+function clearReports() {
+  var bundles = Cc["@mozilla.org/intl/stringbundle;1"].
+                getService(Ci.nsIStringBundleService);
+  var bundle = bundles.createBundle("chrome://global/locale/crashes.properties");
+  var prompts = Cc["@mozilla.org/embedcomp/prompt-service;1"].
+                getService(Ci.nsIPromptService);
+  if (!prompts.confirm(window,
+                       bundle.GetStringFromName("deleteconfirm.title"),
+                       bundle.GetStringFromName("deleteconfirm.description")))
+    return;
+
+  var entries = reportsDir.directoryEntries;
+  while (entries.hasMoreElements()) {
+    var file = entries.getNext().QueryInterface(Ci.nsIFile);
+    var leaf = file.leafName;
+    if (leaf.substring(0, 3) == "bp-" &&
+        leaf.substring(leaf.length - 4) == ".txt") {
+      file.remove(false);
+    }
+  }
+  document.getElementById("reportList").style.display = "none";
+  document.getElementById("noReports").style.display = "block";
+}
+]]>
+</script>
+<title>&crashes.title;</title>
+</head><body onload="populateReportList()" dir="&locale.dir;">
+<button chromedir="&locale.dir;" class="clear-reports"
+        onclick="clearReports()">&clearReports.label;</button>
+<h1>&crashes.title;</h1>
+<div id="reportList">
+  <table>
+    <thead>
+      <tr>
+        <th chromedir="&locale.dir;">&id.heading;</th>
+        <th chromedir="&locale.dir;" colspan="2">&date.heading;</th>
+      </tr>
+    </thead>
+    <tbody id="tbody">
+    </tbody>
+  </table>
+</div>
+<p id="noReports" style="display: none">&noReports.label;</p>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/toolkit/crashreporter/jar.mn
@@ -0,0 +1,2 @@
+toolkit.jar:
+*+ content/global/crashes.xhtml              (content/crashes.xhtml) 
new file mode 100644
--- /dev/null
+++ b/toolkit/locales/en-US/crashreporter/crashes.dtd
@@ -0,0 +1,5 @@
+<!ENTITY crashes.title              "Submitted Crash Reports">
+<!ENTITY id.heading                 "Report ID">
+<!ENTITY date.heading               "Date Submitted">
+<!ENTITY noReports.label            "No crash reports have been submitted.">
+<!ENTITY clearReports.label         "Remove Reports">
new file mode 100644
--- /dev/null
+++ b/toolkit/locales/en-US/crashreporter/crashes.properties
@@ -0,0 +1,2 @@
+deleteconfirm.title=Are you sure?
+deleteconfirm.description=This will delete all reports and cannot be undone
--- a/toolkit/locales/jar.mn
+++ b/toolkit/locales/jar.mn
@@ -51,16 +51,18 @@
 + locale/@AB_CD@/global/wizard.dtd                      (%chrome/global/wizard.dtd)
 + locale/@AB_CD@/global/wizard.properties               (%chrome/global/wizard.properties)
   locale/@AB_CD@/global/nsHelperAppDlg.dtd              (%chrome/global/nsHelperAppDlg.dtd)
   locale/@AB_CD@/global/nsHelperAppDlg.properties       (%chrome/global/nsHelperAppDlg.properties)
   locale/@AB_CD@/global/nsProgressDialog.dtd            (%chrome/global/nsProgressDialog.dtd)
   locale/@AB_CD@/global/nsProgressDialog.properties     (%chrome/global/nsProgressDialog.properties)
   locale/@AB_CD@/global/history/history.properties      (%chrome/global/history/history.properties)
   locale/@AB_CD@/global/xpinstall/xpinstall.properties  (%chrome/global/xpinstall/xpinstall.properties)
+  locale/@AB_CD@/global/crashes.dtd                     (%crashreporter/crashes.dtd)
+  locale/@AB_CD@/global/crashes.properties              (%crashreporter/crashes.properties)
 % locale global-region @AB_CD@ %locale/@AB_CD@/global-region/
 + locale/@AB_CD@/global-region/region.dtd               (%chrome/global-region/region.dtd)
 + locale/@AB_CD@/global-region/region.properties        (%chrome/global-region/region.properties)
 % locale global-platform @AB_CD@ %locale/@AB_CD@/global-platform/
   locale/@AB_CD@/global-platform/mac/platformKeys.properties  (%chrome/global-platform/mac/platformKeys.properties)
   locale/@AB_CD@/global-platform/unix/platformKeys.properties (%chrome/global-platform/unix/platformKeys.properties)
   locale/@AB_CD@/global-platform/win/platformKeys.properties  (%chrome/global-platform/win/platformKeys.properties)
   locale/@AB_CD@/global-platform/mac/intl.properties          (%chrome/global-platform/mac/intl.properties)