Bug 1199434 - Send printer error messages to the parent process to report to the user. r=Mossop
authorMike Conley <mconley@mozilla.com>
Wed, 16 Sep 2015 16:12:54 -0400
changeset 295757 6578d90d03a42fbba7a56724d5e6c7e10f62ee99
parent 295756 e0f32c7b9250c15ea48ff2789934fcc3897bb12a
child 295758 9c3fc7bb6b7b3ef1e26214e366507e3487eedcc3
push id5245
push userraliiev@mozilla.com
push dateThu, 29 Oct 2015 11:30:51 +0000
treeherdermozilla-beta@dac831dc1bd0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersMossop
bugs1199434
milestone43.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1199434 - Send printer error messages to the parent process to report to the user. r=Mossop The printing back-end used to be in charge of opening up an error dialog when things go wrong with printing. Now we fire an event and let PrintUtils do the work of showing the error message. This has the added bonus of making the error messages work with e10s.
toolkit/components/printing/content/printUtils.js
toolkit/content/browser-content.js
--- a/toolkit/components/printing/content/printUtils.js
+++ b/toolkit/components/printing/content/printUtils.js
@@ -60,16 +60,27 @@
  *
  */
 
 var gPrintSettingsAreGlobal = false;
 var gSavePrintSettings = false;
 var gFocusedElement = null;
 
 var PrintUtils = {
+  init() {
+    window.messageManager.addMessageListener("Printing:Error", this);
+  },
+
+  get bundle() {
+    let stringService = Components.classes["@mozilla.org/intl/stringbundle;1"]
+                                  .getService(Components.interfaces.nsIStringBundleService);
+    delete this.bundle;
+    return this.bundle = stringService.createBundle("chrome://global/locale/printing.properties");
+  },
+
   /**
    * Shows the page setup dialog, and saves any settings changed in
    * that dialog if print.save_print_settings is set to true.
    *
    * @return true on success, false on failure
    */
   showPageSetup: function () {
     try {
@@ -295,17 +306,87 @@ var PrintUtils = {
       window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
             .getInterface(Components.interfaces.nsIWebNavigation)
             .QueryInterface(Components.interfaces.nsILoadContext)
             .useRemoteTabs;
     delete this.usingRemoteTabs;
     return this.usingRemoteTabs = usingRemoteTabs;
   },
 
+  displayPrintingError(nsresult, isPrinting) {
+    // The nsresults from a printing error are mapped to strings that have
+    // similar names to the errors themselves. For example, for error
+    // NS_ERROR_GFX_PRINTER_NO_PRINTER_AVAILABLE, the name of the string
+    // for the error message is: PERR_GFX_PRINTER_NO_PRINTER_AVAILABLE. What's
+    // more, if we're in the process of doing a print preview, it's possible
+    // that there are strings specific for print preview for these errors -
+    // if so, the names of those strings have _PP as a suffix. It's possible
+    // that no print preview specific strings exist, in which case it is fine
+    // to fall back to the original string name.
+    const MSG_CODES = [
+      "GFX_PRINTER_NO_PRINTER_AVAILABLE",
+      "GFX_PRINTER_NAME_NOT_FOUND",
+      "GFX_PRINTER_COULD_NOT_OPEN_FILE",
+      "GFX_PRINTER_STARTDOC",
+      "GFX_PRINTER_ENDDOC",
+      "GFX_PRINTER_STARTPAGE",
+      "GFX_PRINTER_DOC_IS_BUSY",
+      "ABORT",
+      "NOT_AVAILABLE",
+      "NOT_IMPLEMENTED",
+      "OUT_OF_MEMORY",
+      "UNEXPECTED",
+    ];
+
+    // PERR_FAILURE is the catch-all error message if we've gotten one that
+    // we don't recognize.
+    msgName = "PERR_FAILURE";
+
+    for (let code of MSG_CODES) {
+      let nsErrorResult = "NS_ERROR_" + code;
+      if (Components.results[nsErrorResult] == nsresult) {
+        msgName = "PERR_" + code;
+        break;
+      }
+    }
+
+    let msg, title;
+
+    if (!isPrinting) {
+      // Try first with _PP suffix.
+      let ppMsgName = msgName + "_PP";
+      try {
+        msg = this.bundle.GetStringFromName(ppMsgName);
+      } catch(e) {
+        // We allow localizers to not have the print preview error string,
+        // and just fall back to the printing error string.
+      }
+    }
+
+    if (!msg) {
+      msg = this.bundle.GetStringFromName(msgName);
+    }
+
+    title = this.bundle.GetStringFromName(isPrinting ? "print_error_dialog_title"
+                                                     : "printpreview_error_dialog_title");
+
+    let promptSvc = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
+                              .getService(Components.interfaces.nsIPromptService);
+    promptSvc.alert(window, title, msg);
+  },
+
   receiveMessage(aMessage) {
+    if (aMessage.name == "Printing:Error") {
+      this.displayPrintingError(aMessage.data.nsresult,
+                                aMessage.data.isPrinting);
+      return;
+    }
+
+    // If we got here, then the message we've received must involve
+    // updating the print progress UI.
     if (!this._webProgressPP.value) {
       // We somehow didn't get a nsIWebProgressListener to be updated...
       // I guess there's nothing to do.
       return;
     }
 
     let listener = this._webProgressPP.value;
     let mm = aMessage.target.messageManager;
@@ -532,8 +613,10 @@ var PrintUtils = {
     }
     // cancel shortkeys
     if (isModif) {
       aEvent.preventDefault();
       aEvent.stopPropagation();
     }
   }
 }
+
+PrintUtils.init();
--- a/toolkit/content/browser-content.js
+++ b/toolkit/content/browser-content.js
@@ -372,23 +372,37 @@ var Printing = {
     "Printing:Preview:Exit",
     "Printing:Preview:Navigate",
     "Printing:Preview:UpdatePageCount",
     "Printing:Print",
   ],
 
   init() {
     this.MESSAGES.forEach(msgName => addMessageListener(msgName, this));
+    addEventListener("PrintingError", this, true);
   },
 
   get shouldSavePrintSettings() {
     return Services.prefs.getBoolPref("print.use_global_printsettings", false) &&
            Services.prefs.getBoolPref("print.save_print_settings", false);
   },
 
+  handleEvent(event) {
+    if (event.type == "PrintingError") {
+      let win = event.target.defaultView;
+      let wbp = win.QueryInterface(Ci.nsIInterfaceRequestor)
+                   .getInterface(Ci.nsIWebBrowserPrint);
+      let nsresult = event.detail;
+      sendAsyncMessage("Printing:Error", {
+        isPrinting: wbp.doingPrint,
+        nsresult: nsresult,
+      });
+    }
+  },
+
   receiveMessage(message) {
     let objects = message.objects;
     let data = message.data;
     switch(message.name) {
       case "Printing:Preview:Enter": {
         this.enterPrintPreview(Services.wm.getOuterWindowWithId(data.windowID));
         break;
       }
@@ -484,16 +498,20 @@ var Printing = {
                                .getInterface(Ci.nsIWebBrowserPrint);
       print.print(printSettings, null);
     } catch(e) {
       // Pressing cancel is expressed as an NS_ERROR_ABORT return value,
       // causing an exception to be thrown which we catch here.
       if (e.result != Cr.NS_ERROR_ABORT) {
         Cu.reportError(`In Printing:Print:Done handler, got unexpected rv
                         ${e.result}.`);
+        sendAsyncMessage("Printing:Error", {
+          isPrinting: true,
+          nsresult: e.result,
+        });
       }
     }
 
     if (this.shouldSavePrintSettings) {
       let PSSVC = Cc["@mozilla.org/gfx/printsettings-service;1"]
                     .getService(Ci.nsIPrintSettingsService);
 
       PSSVC.savePrintSettingsToPrefs(printSettings, true,