home *** CD-ROM | disk | FTP | other *** search
/ PC World 2003 May / PCWorld_2003-05_cd.bin / Komunik / phoenix / chrome / toolkit.jar / content / global / nsProgressDlg.js < prev    next >
Text File  |  2002-10-06  |  19KB  |  594 lines

  1. /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /*
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "License"); you may not use this file except in
  5.  * compliance with the License.  You may obtain a copy of the License at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the License is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  10.  * for the specific language governing rights and limitations under the
  11.  * License.
  12.  *
  13.  * The Original Code is Mozilla Communicator client code,
  14.  * released March 31, 1998.
  15.  *
  16.  * The Initial Developer of the Original Code is Netscape Communications
  17.  * Corporation.  Portions created by Netscape are
  18.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  19.  * Reserved.
  20.  *
  21.  * Contributors:
  22.  *     William A. ("PowerGUI") Law <law@netscape.com>
  23.  *     Scott MacGregor <mscott@netscape.com>
  24.  */
  25.  
  26. var prefContractID            = "@mozilla.org/preferences-service;1";
  27. var externalProtocolServiceID = "@mozilla.org/uriloader/external-protocol-service;1";
  28.  
  29. // dialog is just an array we'll use to store various properties from the dialog document...
  30. var dialog;
  31.  
  32. // the helperAppLoader is a nsIHelperAppLauncher object
  33. var helperAppLoader;
  34. var webBrowserPersist;                                                          
  35. var persistArgs;    
  36. const nsIWBP = Components.interfaces.nsIWebBrowserPersist;
  37.  
  38. // random global variables...
  39. var completed = false;
  40. var startTime = 0;
  41. var elapsed = 0;
  42. var interval = 500; // Update every 500 milliseconds.
  43. var lastUpdate = -interval; // Update initially.
  44. var keepProgressWindowUpBox;
  45. var targetFile;
  46. var gRestartChecked = false;
  47.  
  48. // These are to throttle down the updating of the download rate figure.
  49. var priorRate = 0;
  50. var rateChanges = 0;
  51. var rateChangeLimit = 2;
  52.  
  53. // all progress notifications are done through our nsIWebProgressListener implementation...
  54. var progressListener = {
  55.     onStateChange: function(aWebProgress, aRequest, aStateFlags, aStatus)
  56.     {
  57.       if (aStateFlags & Components.interfaces.nsIWebProgressListener.STATE_STOP)
  58.       {
  59.         // we are done downloading...
  60.         completed = true;
  61.         // Indicate completion in status area.
  62.         var msg = getString( "completeMsg" );
  63.         msg = replaceInsert( msg, 1, formatSeconds( elapsed/1000 ) );
  64.         dialog.status.setAttribute("value", msg);
  65.  
  66.         // Put progress meter at 100%.
  67.         dialog.progress.setAttribute( "value", 100 );
  68.         dialog.progress.setAttribute( "mode", "normal" );
  69.         var percentMsg = getString( "percentMsg" );
  70.         percentMsg = replaceInsert( percentMsg, 1, 100 );
  71.         dialog.progressText.setAttribute("label", percentMsg);
  72.  
  73.         const nsIWebBrowserPersist = Components.interfaces.nsIWebBrowserPersist;
  74.         if (helperAppLoader || webBrowserPersist &&
  75.             webBrowserPersist.currentState == nsIWebBrowserPersist.PERSIST_STATE_FINISHED)
  76.           setTimeout("processEndOfDownload()", 0);
  77.       }
  78.     },
  79.  
  80.     onProgressChange: function(aWebProgress, aRequest, aCurSelfProgress, aMaxSelfProgress, aCurTotalProgress, aMaxTotalProgress)
  81.     {
  82.  
  83.       if (!gRestartChecked)
  84.       {
  85.         gRestartChecked = true;
  86.         try 
  87.         {
  88.           // right now, all that supports restarting downloads is ftp (rfc959)    
  89.           ftpChannel = aRequest.QueryInterface(Components.interfaces.nsIFTPChannel);
  90.           if (ftpChannel) {
  91.             dialog.pauseResumeDeck.setAttribute("selectedIndex", "1");
  92.           }
  93.         }
  94.         catch (ex) {}
  95.       }
  96.  
  97.       // this is so that we don't clobber the status text if 
  98.       // a onProgressChange event happens after we press the pause btn.
  99.       if (dialog.downloadPaused) 
  100.       {
  101.         dialog.status.setAttribute("value", getString("pausedMsg"));
  102.       }
  103.  
  104.       dialog.request = aRequest;  
  105.  
  106.       var overallProgress = aCurTotalProgress;
  107.  
  108.       // Get current time.
  109.       var now = ( new Date() ).getTime();
  110.       // If interval hasn't elapsed, ignore it.
  111.       if ( now - lastUpdate < interval && aMaxTotalProgress != "-1" &&  parseInt(aCurTotalProgress) < parseInt(aMaxTotalProgress) )
  112.         return;
  113.  
  114.       // Update this time.
  115.       lastUpdate = now;
  116.  
  117.       // Update download rate.
  118.       elapsed = now - startTime;
  119.       var rate; // aCurTotalProgress/sec
  120.       if ( elapsed )
  121.         rate = ( aCurTotalProgress * 1000 ) / elapsed;
  122.       else
  123.         rate = 0;
  124.  
  125.       // Update elapsed time display.
  126.       dialog.timeElapsed.setAttribute("value", formatSeconds( elapsed / 1000 ));
  127.  
  128.       // Calculate percentage.
  129.       var percent;
  130.       if ( aMaxTotalProgress > 0)
  131.       {
  132.         percent = Math.floor((overallProgress*100.0)/aMaxTotalProgress);
  133.         if ( percent > 100 )
  134.           percent = 100;
  135.  
  136.         // Advance progress meter.
  137.         dialog.progress.setAttribute( "value", percent );
  138.       }
  139.       else
  140.       {
  141.         percent = -1;
  142.  
  143.         // Progress meter should be barber-pole in this case.
  144.         dialog.progress.setAttribute( "mode", "undetermined" );
  145.       }
  146.  
  147.       // now that we've set the progress and the time, update # bytes downloaded...
  148.       // Update status (nnK of mmK bytes at xx.xK aCurTotalProgress/sec)
  149.       var status = getString( "progressMsg" );
  150.  
  151.       // Insert 1 is the number of kilobytes downloaded so far.
  152.       status = replaceInsert( status, 1, parseInt( overallProgress/1024 + .5 ) );
  153.  
  154.       // Insert 2 is the total number of kilobytes to be downloaded (if known).
  155.       if ( aMaxTotalProgress != "-1" )
  156.          status = replaceInsert( status, 2, parseInt( aMaxTotalProgress/1024 + .5 ) );
  157.       else
  158.          status = replaceInsert( status, 2, "??" );
  159.  
  160.       if ( rate )
  161.       {
  162.         // rate is bytes/sec
  163.         var kRate = rate / 1024; // K bytes/sec;
  164.         kRate = parseInt( kRate * 10 + .5 ); // xxx (3 digits)
  165.         // Don't update too often!
  166.         if ( kRate != priorRate )
  167.         {
  168.           if ( rateChanges++ == rateChangeLimit )
  169.           {
  170.              // Time to update download rate.
  171.              priorRate = kRate;
  172.              rateChanges = 0;
  173.           }
  174.           else
  175.           {
  176.             // Stick with old rate for a bit longer.
  177.             kRate = priorRate;
  178.           }
  179.         }
  180.         else
  181.           rateChanges = 0;
  182.  
  183.          var fraction = kRate % 10;
  184.          kRate = parseInt( ( kRate - fraction ) / 10 );
  185.  
  186.          // Insert 3 is the download rate (in kilobytes/sec).
  187.          status = replaceInsert( status, 3, kRate + "." + fraction );
  188.       }
  189.       else
  190.        status = replaceInsert( status, 3, "??.?" );
  191.  
  192.       // Update status msg.
  193.       dialog.status.setAttribute("value", status);
  194.  
  195.       // Update percentage label on progress meter.      
  196.       if (percent < 0)
  197.         dialog.progressText.setAttribute("value", "");
  198.       else
  199.       {
  200.         var percentMsg = getString( "percentMsg" );      
  201.         percentMsg = replaceInsert( percentMsg, 1, percent );
  202.         dialog.progressText.setAttribute("value", percentMsg);
  203.       }
  204.  
  205.       // Update time remaining.
  206.       if ( rate && (aMaxTotalProgress > 0) )
  207.       {
  208.         var rem = ( aMaxTotalProgress - aCurTotalProgress ) / rate;
  209.         rem = parseInt( rem + .5 );
  210.         dialog.timeLeft.setAttribute("value", formatSeconds( rem ));
  211.       }
  212.       else
  213.         dialog.timeLeft.setAttribute("value", getString( "unknownTime" ));
  214.     },
  215.     onLocationChange: function(aWebProgress, aRequest, aLocation)
  216.     {
  217.       // we can ignore this notification
  218.     },
  219.     onStatusChange: function(aWebProgress, aRequest, aStatus, aMessage)
  220.     {
  221.     },
  222.     onSecurityChange: function(aWebProgress, aRequest, state)
  223.     {
  224.     },
  225.     QueryInterface : function(iid)
  226.     {
  227.      if (iid.equals(Components.interfaces.nsIWebProgressListener) ||
  228.          iid.equals(Components.interfaces.nsISupportsWeakReference) ||
  229.          iid.equals(Components.interfaces.nsISupports))
  230.       return this;
  231.  
  232.      throw Components.results.NS_NOINTERFACE;
  233.     }
  234. };
  235.  
  236. function getString( stringId ) {
  237.    // Check if we've fetched this string already.
  238.    if ( !dialog.strings[ stringId ] ) {
  239.       // Try to get it.
  240.       var elem = document.getElementById( "dialog.strings."+stringId );
  241.       try {
  242.         if ( elem
  243.            &&
  244.            elem.childNodes
  245.            &&
  246.            elem.childNodes[0]
  247.            &&
  248.            elem.childNodes[0].nodeValue ) {
  249.          dialog.strings[ stringId ] = elem.childNodes[0].nodeValue;
  250.         } else {
  251.           // If unable to fetch string, use an empty string.
  252.           dialog.strings[ stringId ] = "";
  253.         }
  254.       } catch (e) { dialog.strings[ stringId ] = ""; }
  255.    }
  256.    return dialog.strings[ stringId ];
  257. }
  258.  
  259. function formatSeconds( secs )
  260. {
  261.   // Round the number of seconds to remove fractions.
  262.   secs = parseInt( secs + .5 );
  263.   var hours = parseInt( secs/3600 );
  264.   secs -= hours*3600;
  265.   var mins = parseInt( secs/60 );
  266.   secs -= mins*60;
  267.   var result;
  268.   if ( hours )
  269.     result = getString( "longTimeFormat" );
  270.   else
  271.     result = getString( "shortTimeFormat" );
  272.  
  273.   if ( hours < 10 )
  274.      hours = "0" + hours;
  275.   if ( mins < 10 )
  276.      mins = "0" + mins;
  277.   if ( secs < 10 )
  278.      secs = "0" + secs;
  279.  
  280.   // Insert hours, minutes, and seconds into result string.
  281.   result = replaceInsert( result, 1, hours );
  282.   result = replaceInsert( result, 2, mins );
  283.   result = replaceInsert( result, 3, secs );
  284.  
  285.   return result;
  286. }
  287.  
  288. function loadDialog()
  289. {
  290.   var sourceUrlValue = {};
  291.   var initialDownloadTimeValue = {};
  292.   var sourceUrl = null;
  293.   
  294.    // targetFile is global because we are going to want re-use later one...
  295.   if (helperAppLoader) {
  296.     targetFile =  helperAppLoader.getDownloadInfo(sourceUrlValue, initialDownloadTimeValue);
  297.  
  298.     sourceUrl = sourceUrlValue.value;
  299.     startTime = initialDownloadTimeValue.value / 1000;
  300.   }
  301.   else if (webBrowserPersist) {
  302.     // When saving web pages, the file we're saving into is passed to us as a parameter.
  303.     try {
  304.       persistArgs.source.QueryInterface(Components.interfaces.nsIURI);
  305.       sourceUrl = persistArgs.source;
  306.     }
  307.     catch (e) {
  308.       sourceUrl = { spec: persistArgs.source.URL };
  309.     }
  310.   
  311.     // When saving web pages, we don't need to do anything special to receive the time
  312.     // at which the transfer started, so just assume it started 'now'.
  313.     startTime = ( new Date() ).getTime();  
  314.   }  
  315.   
  316.   // set the elapsed time on the first pass...
  317.   var now = ( new Date() ).getTime();
  318.   // intialize the elapsed time global variable slot
  319.   elapsed = now - startTime;
  320.   // Update elapsed time display.
  321.   dialog.timeElapsed.setAttribute("value", formatSeconds( elapsed / 1000 ));
  322.   dialog.timeLeft.setAttribute("value", formatSeconds( 0 ));
  323.  
  324.   dialog.location.setAttribute("value", sourceUrl.spec );
  325.   dialog.fileName.setAttribute( "value", targetFile.path );
  326.  
  327.   var prefs = Components.classes[prefContractID].getService(Components.interfaces.nsIPrefBranch);
  328.   if (prefs)
  329.     keepProgressWindowUpBox.checked = prefs.getBoolPref("browser.download.progressDnldDialog.keepAlive");
  330. }
  331.  
  332. function replaceInsert( text, index, value ) {
  333.    var result = text;
  334.    var regExp = new RegExp( "#"+index );
  335.    result = result.replace( regExp, value );
  336.    return result;
  337. }
  338.  
  339. function onLoad() {
  340.     // Set global variables.
  341.     try {
  342.       helperAppLoader = window.arguments[0].QueryInterface( Components.interfaces.nsIHelperAppLauncher );
  343.     }
  344.     catch (e) {
  345.       webBrowserPersist = window.arguments[0].QueryInterface( Components.interfaces.nsIWebBrowserPersist );
  346.       setTimeout("checkPersistComplete()", 100);
  347.     }
  348.  
  349.     if ( !helperAppLoader && !webBrowserPersist ) {
  350.         dump( "Invalid argument to helperAppDldProgress.xul\n" );
  351.         window.close()
  352.         return;
  353.     }
  354.  
  355.     dialog = new Object;
  356.     dialog.strings = new Array;
  357.     dialog.location    = document.getElementById("dialog.location");
  358.     dialog.contentType = document.getElementById("dialog.contentType");
  359.     dialog.fileName    = document.getElementById("dialog.fileName");
  360.     dialog.status      = document.getElementById("dialog.status");
  361.     dialog.progress    = document.getElementById("dialog.progress");
  362.     dialog.progressText = document.getElementById("dialog.progressText");
  363.     dialog.timeLeft    = document.getElementById("dialog.timeLeft");
  364.     dialog.timeElapsed = document.getElementById("dialog.timeElapsed");
  365.     dialog.cancel      = document.getElementById("cancel");
  366.     dialog.pause       = document.getElementById("pause");
  367.     dialog.resume      = document.getElementById("resume");
  368.     dialog.pauseResumeDeck = document.getElementById("pauseResumeDeck");
  369.     dialog.request     = 0;
  370.     dialog.downloadPaused = false;
  371.     keepProgressWindowUpBox = document.getElementById('keepProgressDialogUp');
  372.  
  373.     // Set up dialog button callbacks.
  374.     var object = this;
  375.     doSetOKCancel("", function () { return object.onCancel();});
  376.  
  377.     // set our web progress listener on the helper app launcher
  378.     if (helperAppLoader) 
  379.       helperAppLoader.setWebProgressListener(progressListener);
  380.     else if (webBrowserPersist) {
  381.       webBrowserPersist.progressListener = progressListener;
  382.       
  383.       persistArgs = window.arguments[1];
  384.       
  385.       targetFile = persistArgs.target;
  386.         
  387.       // If the code reaches this point, the user has agreed to replace existing files in the
  388.       // file picker. 
  389.       const flags = nsIWBP.PERSIST_FLAGS_NO_CONVERSION | nsIWBP.PERSIST_FLAGS_REPLACE_EXISTING_FILES;
  390.       if (persistArgs.bypassCache)
  391.         webBrowserPersist.persistFlags |= nsIWBP.PERSIST_FLAGS_BYPASS_CACHE;
  392.       else 
  393.         webBrowserPersist.persistFlags |= nsIWBP.PERSIST_FLAGS_FROM_CACHE;
  394.       
  395.       try {
  396.         var uri = persistArgs.source.QueryInterface(Components.interfaces.nsIURI);
  397.         webBrowserPersist.saveURI(uri, persistArgs.postData, targetFile);
  398.       }
  399.       catch (e) {
  400.         // Saving a Document, not a URI:
  401.         
  402.         var filesFolder = null;
  403.         if (persistArgs.contentType != "text/plain") {
  404.           // Create the local directory into which to save associated files. 
  405.           const lfContractID = "@mozilla.org/file/local;1";
  406.           const lfIID = Components.interfaces.nsILocalFile;
  407.           filesFolder = Components .classes[lfContractID].createInstance(lfIID);
  408.           filesFolder.initWithPath(persistArgs.target.path);
  409.           
  410.           var nameWithoutExtension = filesFolder.leafName;
  411.           nameWithoutExtension = nameWithoutExtension.substring(0, nameWithoutExtension.lastIndexOf("."));
  412.           var filesFolderLeafName = getString("filesFolder");
  413.           filesFolderLeafName = filesFolderLeafName.replace(/\^BASE\^/, nameWithoutExtension);
  414.  
  415.           filesFolder.leafName = filesFolderLeafName;
  416.           
  417.           if (!filesFolder.exists())
  418.             filesFolder.create(lfIID.DIRECTORY_TYPE, 0755);
  419.         }
  420.           
  421.         var encodingFlags = 0;
  422.         if (persistArgs.contentType == "text/plain") {
  423.           encodingFlags |= nsIWBP.ENCODE_FLAGS_FORMATTED;
  424.           encodingFlags |= nsIWBP.ENCODE_FLAGS_ABSOLUTE_LINKS;
  425.           encodingFlags |= nsIWBP.ENCODE_FLAGS_NOFRAMES_CONTENT;        
  426.         }
  427.         
  428.         const kWrapColumn = 80;
  429.  
  430.         webBrowserPersist.saveDocument(persistArgs.source, targetFile, filesFolder, 
  431.                                        persistArgs.contentType, encodingFlags, kWrapColumn);
  432.       }
  433.     }
  434.     
  435.     // Fill dialog.
  436.     loadDialog();
  437.  
  438.     if ( window.opener ) {
  439.         moveToAlertPosition();
  440.     } else {
  441.         centerWindowOnScreen();
  442.     }
  443.     
  444.     // Set initial focus
  445.     if ( !completed )
  446.     {
  447.         keepProgressWindowUpBox.focus();
  448.     }
  449. }
  450.  
  451. function onUnload()
  452. {
  453.  
  454.   // remember the user's decision for the checkbox.
  455.  
  456.   var prefs = Components.classes[prefContractID].getService(Components.interfaces.nsIPrefBranch);
  457.   if (prefs)
  458.     prefs.setBoolPref("browser.download.progressDnldDialog.keepAlive", keepProgressWindowUpBox.checked);
  459.  
  460.    // Cancel app launcher.
  461.    if (helperAppLoader)
  462.    {
  463.      try
  464.      {
  465.        helperAppLoader.closeProgressWindow();
  466.        helperAppLoader = null;
  467.      }
  468.  
  469.      catch( exception ) {}
  470.    }
  471. }
  472.  
  473. // If the user presses cancel, tell the app launcher and close the dialog...
  474. function onCancel ()
  475. {
  476.    // Cancel app launcher.
  477.    if (helperAppLoader && !completed)
  478.    {
  479.      try
  480.      {
  481.        helperAppLoader.Cancel();
  482.      }
  483.  
  484.      catch( exception ) {}
  485.    }
  486.    else if (webBrowserPersist)
  487.    {
  488.      webBrowserPersist.cancelSave();
  489.    }
  490.  
  491.   // Close up dialog by returning true.
  492.   return true;
  493. }
  494.  
  495. // closeWindow should only be called from processEndOfDownload
  496. function closeWindow()
  497. {
  498.   // while the time out was fired the user may have checked the
  499.   // keep this dialog open box...so we should abort and not actually
  500.   // close the window.
  501.  
  502.   if (!keepProgressWindowUpBox.checked)
  503.     window.close();
  504.   else
  505.     setupPostProgressUI();
  506. }
  507.  
  508. function setupPostProgressUI()
  509. {
  510.   //dialog.cancel.childNodes[0].nodeValue = "Close";
  511.   // turn the cancel button into a close button
  512.   var cancelButton = document.getElementById('cancel');
  513.   if (cancelButton)
  514.   {
  515.     cancelButton.label = getString("close");
  516.     cancelButton.focus();
  517.   }
  518.  
  519.   // enable the open and open folder buttons
  520.   var openFolderButton = document.getElementById('openFolder');
  521.   var openButton = document.getElementById('open');
  522.  
  523.   openFolderButton.removeAttribute("disabled");
  524.   if ( !targetFile.isExecutable() )
  525.   {
  526.     openButton.removeAttribute("disabled");
  527.   }
  528.  
  529.   dialog.pause.disabled = true; // setAttribute("disabled", true);
  530.   dialog.resume.disabled = true;
  531.   
  532. }
  533.  
  534. // when we receive a stop notification we are done reporting progress on the download
  535. // now we have to decide if the window is supposed to go away or if we are supposed to remain open
  536. // and enable the open and open folder buttons on the dialog.
  537. function processEndOfDownload()
  538. {
  539.   if (!keepProgressWindowUpBox.checked) {
  540.     closeWindow(); // shut down, we are all done.
  541.     return;
  542.   }
  543.  
  544.   // o.t the user has asked the window to stay open so leave it open and enable the open and open new folder buttons
  545.   setupPostProgressUI();
  546. }
  547.  
  548. function doOpen()
  549. {
  550.   try {
  551.     var localFile = targetFile.QueryInterface(Components.interfaces.nsILocalFile);
  552.     if (localFile)
  553.       localFile.launch();
  554.     window.close();
  555.   } catch (ex) {}
  556. }
  557.  
  558. function doOpenFolder()
  559. {
  560.   try {
  561.     var localFile = targetFile.QueryInterface(Components.interfaces.nsILocalFile);
  562.     if (localFile)
  563.       localFile.reveal();
  564.     window.close();
  565.   } catch (ex) {}
  566. }
  567.  
  568. function doPauseButton() {
  569.     if (dialog.downloadPaused)
  570.     {
  571.         // resume
  572.         dialog.downloadPaused = false;
  573.         dialog.pauseResumeDeck.setAttribute("selectedIndex", "1");
  574.         dialog.request.resume()
  575.     }
  576.     else
  577.     {
  578.         // suspend
  579.         dialog.downloadPaused = true;
  580.         dialog.pauseResumeDeck.setAttribute("selectedIndex", "2");
  581.         dialog.request.suspend()
  582.     }
  583. }
  584.  
  585. function checkPersistComplete()
  586. {
  587.   const nsIWebBrowserPersist = Components.interfaces.nsIWebBrowserPersist;
  588.   if (webBrowserPersist.currentState == nsIWebBrowserPersist.PERSIST_STATE_FINISHED) {
  589.     dump("*** all done\n");
  590.     processEndOfDownload();
  591.   }
  592. }
  593.  
  594.