Bug 544018 - print preview doesn't work in view source, r=dao
authorOlli Pettay <Olli.Pettay@helsinki.fi>
Mon, 08 Feb 2010 18:16:57 +0200
changeset 37983 a1ac5c4e8b263ce1b2412021b2d4bc0c42daff7b
parent 37982 d2ebee4e5e7d19cf8373b8fe40250a15e55ab05b
child 37984 4760079804e4280d227a36fea64a5e997935215b
push idunknown
push userunknown
push dateunknown
reviewersdao
bugs544018
milestone1.9.3a2pre
Bug 544018 - print preview doesn't work in view source, r=dao
browser/base/content/browser.js
content/base/src/nsDocument.cpp
toolkit/components/printing/content/printUtils.js
toolkit/components/viewsource/content/viewPartialSource.xul
toolkit/components/viewsource/content/viewSource.js
toolkit/components/viewsource/content/viewSource.xul
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -2531,21 +2531,44 @@ function BrowserReloadWithFlags(reloadFl
 
   try {
     webNav.reload(reloadFlags);
   } catch (e) {
   }
 }
 
 var PrintPreviewListener = {
+  _printPreviewTab: null,
+  _tabBeforePrintPreview: null,
+
+  getPrintPreviewBrowser: function () {
+    if (!this._printPreviewTab) {
+      this._tabBeforePrintPreview = gBrowser.selectedTab;
+      this._printPreviewTab = gBrowser.loadOneTab("about:blank",
+                                                  { inBackground: false });
+      gBrowser.selectedTab = this._printPreviewTab;
+    }
+    return gBrowser.getBrowserForTab(this._printPreviewTab);
+  },
+  getSourceBrowser: function () {
+    return this._tabBeforePrintPreview ?
+      this._tabBeforePrintPreview.linkedBrowser : gBrowser.selectedBrowser;
+  },
+  getNavToolbox: function () {
+    return gNavToolbox;
+  },
   onEnter: function () {
     gInPrintPreviewMode = true;
     this._toggleAffectedChrome();
   },
   onExit: function () {
+    gBrowser.selectedTab = this._tabBeforePrintPreview;
+    this._tabBeforePrintPreview = null;
+    gBrowser.removeTab(this._printPreviewTab);
+    this._printPreviewTab = null;
     gInPrintPreviewMode = false;
     this._toggleAffectedChrome();
   },
   _toggleAffectedChrome: function () {
     // chrome to toggle includes:
     //   (*) menubar
     //   (*) navigation bar
     //   (*) bookmarks toolbar
@@ -2567,51 +2590,44 @@ var PrintPreviewListener = {
   },
   _hideChrome: function () {
     this._chromeState = {};
 
     var sidebar = document.getElementById("sidebar-box");
     this._chromeState.sidebarOpen = !sidebar.hidden;
     this._sidebarCommand = sidebar.getAttribute("sidebarcommand");
 
-    this._chromeState.hadTabStrip = gBrowser.getStripVisibility();
-    gBrowser.setStripVisibilityTo(false);
+    gBrowser.mStrip.setAttribute("moz-collapsed", "true");
 
     var notificationBox = gBrowser.getNotificationBox();
     this._chromeState.notificationsOpen = !notificationBox.notificationsHidden;
     notificationBox.notificationsHidden = true;
 
     document.getElementById("sidebar").setAttribute("src", "about:blank");
     var statusbar = document.getElementById("status-bar");
     this._chromeState.statusbarOpen = !statusbar.hidden;
     statusbar.hidden = true;
 
     this._chromeState.findOpen = !gFindBar.hidden;
     gFindBar.close();
   },
   _showChrome: function () {
-    if (this._chromeState.hadTabStrip)
-      gBrowser.setStripVisibilityTo(true);
+    gBrowser.mStrip.removeAttribute("moz-collapsed");
 
     if (this._chromeState.notificationsOpen)
       gBrowser.getNotificationBox().notificationsHidden = false;
 
     if (this._chromeState.statusbarOpen)
       document.getElementById("status-bar").hidden = false;
 
     if (this._chromeState.findOpen)
       gFindBar.open();
   }
 }
 
-function getPPBrowser()
-{
-  return gBrowser;
-}
-
 function getMarkupDocumentViewer()
 {
   return gBrowser.markupDocumentViewer;
 }
 
 /**
  * Content area tooltip.
  * XXX - this must move into XBL binding/equiv! Do not want to pollute
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -1793,16 +1793,17 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mChannel)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mStyleAttrStyleSheet, nsIStyleSheet)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mScriptEventManager)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mXPathEvaluatorTearoff)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mLayoutHistoryState)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnloadBlocker)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mFirstBaseNodeWithHref)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mDOMImplementation)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOriginalDocument)
 
   // An element will only be in the linkmap as long as it's in the
   // document, so we'll traverse the table here instead of from the element.
   if (tmp->mLinkMap.IsInitialized()) {
     tmp->mLinkMap.EnumerateEntries(LinkMapTraverser, &cb);
   }
 
   // Traverse all our nsCOMArrays.
@@ -1846,16 +1847,17 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ns
     tmp->mChildren.ChildAt(indx)->UnbindFromTree();
     tmp->mChildren.RemoveChildAt(indx);
   }
 
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mCachedRootContent)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mDisplayDocument)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mFirstBaseNodeWithHref)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mDOMImplementation)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOriginalDocument)
 
   NS_IMPL_CYCLE_COLLECTION_UNLINK_USERDATA
 
   tmp->mParentDocument = nsnull;
 
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMARRAY(mPreloadingImages)
 
   // nsDocument has a pretty complex destructor, so we're going to
--- a/toolkit/components/printing/content/printUtils.js
+++ b/toolkit/components/printing/content/printUtils.js
@@ -82,42 +82,37 @@ var PrintUtils = {
     } catch (e) {
       // Pressing cancel is expressed as an NS_ERROR_ABORT return value,
       // causing an exception to be thrown which we catch here.
       // Unfortunately this will also consume helpful failures, so add a
       // dump("print: "+e+"\n"); // if you need to debug
     }
   },
 
-  // calling PrintUtils.printPreview() requires that you have three functions
-  // in the global scope: getPPBrowser(), which returns the browser element in
-  // the window print preview uses, getNavToolbox(), which returns the element
-  // (usually the main toolbox element) before which the print preview toolbar
-  // should be inserted, and getWebNavigation(), which returns the document's
-  // nsIWebNavigation object
-  printPreview: function (aListenerOrEnterCallback, aExitCallback)
+  // If aCallback is not null, it must be an object which has the following methods:
+  // getPrintPreviewBrowser(), getSourceBrowser(),
+  // getNavToolbox(), onEnter() and onExit().
+  // If aCallback is null, then printPreview must previously have been called with
+  // non-null aCallback and that object will be reused.
+  printPreview: function (aCallback)
   {
-    // if we're already in PP mode, don't set the callbacks; chances
-    // are they're null because someone is calling printPreview() to
+    // if we're already in PP mode, don't set the callback; chances
+    // are it is null because someone is calling printPreview() to
     // get us to refresh the display.
     if (!document.getElementById("print-preview-toolbar")) {
-      if (typeof aListenerOrEnterCallback == "object") {
-        this._onEnterPP = function () { aListenerOrEnterCallback.onEnter(); };
-        this._onExitPP  = function () { aListenerOrEnterCallback.onExit(); };
-      } else {
-        this._onEnterPP = aListenerOrEnterCallback;
-        this._onExitPP  = aExitCallback;
-      }
+      this._callback = aCallback;
+      this._sourceBrowser = aCallback.getSourceBrowser();
+      this._originalTitle = this._sourceBrowser.contentDocument.title;
+      this._originalURL = this._sourceBrowser.currentURI.spec;
     } else {
       // collapse the browser here -- it will be shown in
-      // onEnterPrintPreview; this forces a reflow which fixes display
+      // enterPrintPreview; this forces a reflow which fixes display
       // issues in bug 267422.
-      var browser = getPPBrowser();
-      if (browser)
-        browser.collapsed = true;
+      this._sourceBrowser = this._callback.getPrintPreviewBrowser();
+      this._sourceBrowser.collapsed = true;
     }
 
     this._webProgressPP = {};
     var ppParams        = {};
     var notifyOnOpen    = {};
     var webBrowserPrint = this.getWebBrowserPrint();
     var printSettings   = this.getPrintSettings();
     // Here we get the PrintingPromptService so we can display the PP Progress from script
@@ -128,19 +123,18 @@ var PrintUtils = {
     var PPROMPTSVC = Components.classes["@mozilla.org/embedcomp/printingprompt-service;1"]
                                .getService(Components.interfaces.nsIPrintingPromptService);
     // just in case we are already printing, 
     // an error code could be returned if the Prgress Dialog is already displayed
     try {
       PPROMPTSVC.showProgress(window, webBrowserPrint, printSettings, this._obsPP, false,
                               this._webProgressPP, ppParams, notifyOnOpen);
       if (ppParams.value) {
-        var webNav = getWebNavigation();
-        ppParams.value.docTitle = webNav.document.title;
-        ppParams.value.docURL   = webNav.currentURI.spec;
+        ppParams.value.docTitle = this._originalTitle;
+        ppParams.value.docURL   = this._originalURL;
       }
 
       // this tells us whether we should continue on with PP or 
       // wait for the callback via the observer
       if (!notifyOnOpen.value.valueOf() || this._webProgressPP.value == null)
         this.enterPrintPreview(aWindow);
     } catch (e) {
       this.enterPrintPreview(aWindow);
@@ -150,21 +144,17 @@ var PrintUtils = {
   getWebBrowserPrint: function (aWindow)
   {
     var contentWindow = aWindow || window.content;
     return contentWindow.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
                         .getInterface(Components.interfaces.nsIWebBrowserPrint);
   },
 
   getPrintPreview: function() {
-    if (this._printPreviewTab) {
-      var docShell = getPPBrowser().getBrowserForTab(this._printPreviewTab).docShell;
-      return docShell.printPreview;
-    }
-    return null;
+    return this._callback.getPrintPreviewBrowser().docShell.printPreview;
   },
 
   ////////////////////////////////////////
   // "private" methods. Don't use them. //
   ////////////////////////////////////////
 
   setPrinterDefaultsForSelectedPrinter: function (aPSSVC, aPrintSettings)
   {
@@ -200,18 +190,20 @@ var PrintUtils = {
       dump("getPrintSettings: "+e+"\n");
     }
     return printSettings;
   },
 
   _originalZoomValue: null,
   _closeHandlerPP: null,
   _webProgressPP: null,
-  _onEnterPP: null,
-  _onExitPP: null,
+  _callback: null,
+  _sourceBrowser: null,
+  _originalTitle: "",
+  _originalURL: "",
 
   // This observer is called once the progress dialog has been "opened"
   _obsPP: 
   {
     observe: function(aSubject, aTopic, aData)
     {
       // delay the print preview to show the content of the progress dialog
       setTimeout(function () { PrintUtils.enterPrintPreview(); }, 0);
@@ -222,144 +214,110 @@ var PrintUtils = {
       if (iid.equals(Components.interfaces.nsIObserver) ||
           iid.equals(Components.interfaces.nsISupportsWeakReference) ||
           iid.equals(Components.interfaces.nsISupports))
         return this;   
       throw Components.results.NS_NOINTERFACE;
     }
   },
 
-  _originalTab: null,
-  _printPreviewTab: null,
-
   enterPrintPreview: function ()
   {
     gFocusedElement = document.commandDispatcher.focusedElement;
 
     // Reset the zoom value and save it to be restored later.
     if (typeof ZoomManager == "object") {
       this._originalZoomValue = ZoomManager.zoom;
       ZoomManager.reset();
     }
 
     var webBrowserPrint;
     var printSettings  = this.getPrintSettings();
-    var tabbrowser = getPPBrowser();
-    var contentWindow = null;
-    if (tabbrowser) {
-      if (this._printPreviewTab) {
-        contentWindow =
-          tabbrowser.getBrowserForTab(this._printPreviewTab).contentWindow;
-      } else {
-        this._originalTab = tabbrowser.mCurrentTab;
-        contentWindow = window.content
-        this._printPreviewTab = tabbrowser.loadOneTab("about:blank", null, null,
-                                                      null, true, false);
-      }
-    }
+    var originalWindow = this._sourceBrowser.contentWindow;
 
     try {
       webBrowserPrint = this.getPrintPreview();
-      webBrowserPrint.printPreview(printSettings, contentWindow,
+      webBrowserPrint.printPreview(printSettings, originalWindow,
                                    this._webProgressPP.value);
     } catch (e) {
-      this._printPreviewTab = null;
-      this._originalTab = null;
       if (typeof ZoomManager == "object")
         ZoomManager.zoom = this._originalZoomValue;
       // Pressing cancel is expressed as an NS_ERROR_ABORT return value,
       // causing an exception to be thrown which we catch here.
       // Unfortunately this will also consume helpful failures, so add a
       // dump(e); // if you need to debug
       return;
     }
 
     var printPreviewTB = document.getElementById("print-preview-toolbar");
     if (printPreviewTB) {
       printPreviewTB.updateToolbar();
-      var browser = getPPBrowser();
-      if (browser)
-        browser.collapsed = false;
-
-      tabbrowser.getBrowserForTab(this._printPreviewTab).contentWindow.focus();
-      tabbrowser.selectedTab = this._printPreviewTab;
+      var browser = this._callback.getPrintPreviewBrowser();
+      browser.collapsed = false;
+      browser.contentWindow.focus();
       return;
     }
 
     // show the toolbar after we go into print preview mode so
     // that we can initialize the toolbar with total num pages
     var XUL_NS =
       "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
     printPreviewTB = document.createElementNS(XUL_NS, "toolbar");
     printPreviewTB.setAttribute("printpreview", true);
     printPreviewTB.id = "print-preview-toolbar";
     printPreviewTB.className = "toolbar-primary";
 
-    var navToolbox = getNavToolbox();
+    var navToolbox = this._callback.getNavToolbox();
     navToolbox.parentNode.insertBefore(printPreviewTB, navToolbox);
 
     // copy the window close handler
     if (document.documentElement.hasAttribute("onclose"))
       this._closeHandlerPP = document.documentElement.getAttribute("onclose");
     else
       this._closeHandlerPP = null;
     document.documentElement.setAttribute("onclose", "PrintUtils.exitPrintPreview(); return false;");
 
     // disable chrome shortcuts...
     window.addEventListener("keypress", this.onKeyPressPP, true);
 
-    tabbrowser.getBrowserForTab(this._printPreviewTab).contentWindow.focus();
-    tabbrowser.selectedTab = this._printPreviewTab;
+    var browser = this._callback.getPrintPreviewBrowser();
+    browser.collapsed = false;
+    browser.contentWindow.focus();
 
     // on Enter PP Call back
-    if (this._onEnterPP) {
-      this._onEnterPP();
-      this._onEnterPP = null;
-    }
+    this._callback.onEnter();
   },
 
   exitPrintPreview: function ()
   {
     window.removeEventListener("keypress", this.onKeyPressPP, true);
 
     // restore the old close handler
     document.documentElement.setAttribute("onclose", this._closeHandlerPP);
     this._closeHandlerPP = null;
 
-    var webBrowserPrint = this.getWebBrowserPrint();
+    var webBrowserPrint = this.getPrintPreview();
     webBrowserPrint.exitPrintPreview();
 
-    var tabbrowser = getPPBrowser();
-    if (tabbrowser) {
-      tabbrowser.removeTab(this._printPreviewTab);
-      tabbrowser.selectedTab = this._originalTab;
-      this._originalTab = null;
-      this._printPreviewTab = null;
-    }
-
     if (typeof ZoomManager == "object")
       ZoomManager.zoom = this._originalZoomValue;
 
     // remove the print preview toolbar
     var printPreviewTB = document.getElementById("print-preview-toolbar");
-    getNavToolbox().parentNode.removeChild(printPreviewTB);
+    this._callback.getNavToolbox().parentNode.removeChild(printPreviewTB);
 
     var fm = Components.classes["@mozilla.org/focus-manager;1"]
                        .getService(Components.interfaces.nsIFocusManager);
     if (gFocusedElement)
       fm.setFocus(gFocusedElement, fm.FLAG_NOSCROLL);
     else
       window.content.focus();
     gFocusedElement = null;
 
-    // on Exit PP Call back
-    if (this._onExitPP) {
-      this._onExitPP();
-      this._onExitPP = null;
-    }
+    this._callback.onExit();
   },
 
   onKeyPressPP: function (aEvent)
   {
     var closeKey;
     try {
       closeKey = document.getElementById("key_close")
                          .getAttribute("key");
--- a/toolkit/components/viewsource/content/viewPartialSource.xul
+++ b/toolkit/components/viewsource/content/viewPartialSource.xul
@@ -73,17 +73,17 @@
   <script type="application/javascript" src="chrome://global/content/viewPartialSource.js"/>
   <script type="application/javascript" src="chrome://global/content/viewZoomOverlay.js"/>
   <script type="application/javascript" src="chrome://global/content/contentAreaUtils.js"/>
 
   <stringbundle id="viewSourceBundle" src="chrome://global/locale/viewSource.properties"/>
 
   <command id="cmd_savePage" oncommand="ViewSourceSavePage();"/>
   <command id="cmd_print" oncommand="PrintUtils.print();"/>
-  <command id="cmd_printpreview" oncommand="PrintUtils.printPreview(onEnterPP, onExitPP);"/>
+  <command id="cmd_printpreview" oncommand="PrintUtils.printPreview(PrintPreviewListener);"/>
   <command id="cmd_pagesetup" oncommand="PrintUtils.showPageSetup();"/>
   <command id="cmd_close" oncommand="window.close();"/>
   <commandset id="editMenuCommands"/>
   <command id="cmd_find"
            oncommand="document.getElementById('FindToolbar').onFindCommand();"/>
   <command id="cmd_findAgain"
            oncommand="document.getElementById('FindToolbar').onFindAgainCommand(false);"/>
   <command id="cmd_findPrevious"
--- a/toolkit/components/viewsource/content/viewSource.js
+++ b/toolkit/components/viewsource/content/viewSource.js
@@ -378,36 +378,44 @@ function ViewSourceEditPage()
 }
 
 // Strips the |view-source:| for saveURL()
 function ViewSourceSavePage()
 {
   saveURL(window.content.location.href.substring(12), null, "SaveLinkTitle");
 }
 
-function onEnterPP()
-{
-  var toolbox = document.getElementById("viewSource-toolbox");
-  toolbox.hidden = true;
-}
-
-function onExitPP()
-{
-  var toolbox = document.getElementById("viewSource-toolbox");
-  toolbox.hidden = false;
-}
-
-function getPPBrowser() {
-  return gBrowser;
-}
-
-// printUtils.js uses this
-function getNavToolbox()
-{
-  return document.getElementById("appcontent");
+var PrintPreviewListener = {
+  getPrintPreviewBrowser: function () {
+    var browser = document.getElementById("ppBrowser");
+    if (!browser) {
+      browser = document.createElement("browser");
+      browser.setAttribute("id", "ppBrowser");
+      browser.setAttribute("flex", "1");
+      document.getElementById("appcontent").
+        insertBefore(browser, document.getElementById("FindToolbar"));
+    }
+    return browser;
+  },
+  getSourceBrowser: function () {
+    return gBrowser;
+  },
+  getNavToolbox: function () {
+    return document.getElementById("appcontent");
+  },
+  onEnter: function () {
+    var toolbox = document.getElementById("viewSource-toolbox");
+    toolbox.hidden = true;
+    gBrowser.collapsed = true;
+  },
+  onExit: function () {
+    document.getElementById("ppBrowser").collapsed = true;
+    gBrowser.collapsed = false;
+    document.getElementById("viewSource-toolbox").hidden = false;
+  }
 }
 
 function getWebNavigation()
 {
   try {
     return gBrowser.webNavigation;
   } catch (e) {
     return null;
--- a/toolkit/components/viewsource/content/viewSource.xul
+++ b/toolkit/components/viewsource/content/viewSource.xul
@@ -73,17 +73,17 @@
   <script type="application/javascript" src="chrome://global/content/viewSource.js"/>
   <script type="application/javascript" src="chrome://global/content/viewZoomOverlay.js"/>
   <script type="application/javascript" src="chrome://global/content/contentAreaUtils.js"/>
   
   <stringbundle id="viewSourceBundle" src="chrome://global/locale/viewSource.properties"/>
 
   <command id="cmd_savePage" oncommand="ViewSourceSavePage();"/>
   <command id="cmd_print" oncommand="PrintUtils.print();"/>
-  <command id="cmd_printpreview" oncommand="PrintUtils.printPreview(onEnterPP, onExitPP);"/>
+  <command id="cmd_printpreview" oncommand="PrintUtils.printPreview(PrintPreviewListener);"/>
   <command id="cmd_pagesetup" oncommand="PrintUtils.showPageSetup();"/>
   <command id="cmd_close" oncommand="window.close();"/>
   <commandset id="editMenuCommands"/>
   <command id="cmd_find"
            oncommand="document.getElementById('FindToolbar').onFindCommand();"/>
   <command id="cmd_findAgain"
            oncommand="document.getElementById('FindToolbar').onFindAgainCommand(false);"/>
   <command id="cmd_findPrevious"