home *** CD-ROM | disk | FTP | other *** search
/ InterCD 2001 November / november_2001.iso / Browsers / Netscape 6.1 / browser.xpi / bin / chrome / toolkit.jar / content / global / helperAppDldProgress.js < prev    next >
Encoding:
JavaScript  |  2001-07-05  |  15.0 KB  |  480 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;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.  
  35. // random global variables...
  36. var completed = false;
  37. var startTime = 0;
  38. var elapsed = 0;
  39. var interval = 500; // Update every 500 milliseconds.
  40. var lastUpdate = -interval; // Update initially.
  41. var keepProgressWindowUpBox;
  42. var targetFile;
  43. var gRestartChecked = false;
  44.  
  45. // These are to throttle down the updating of the download rate figure.
  46. var priorRate = 0;
  47. var rateChanges = 0;
  48. var rateChangeLimit = 2;
  49.  
  50. // all progress notifications are done through our nsIWebProgressListener implementation...
  51. var progressListener = {
  52.     onStateChange: function(aWebProgress, aRequest, aStateFlags, aStatus)
  53.     {
  54.       if (aStateFlags & Components.interfaces.nsIWebProgressListener.STATE_STOP)
  55.       {
  56.         // we are done downloading...
  57.         completed = true;
  58.         // Indicate completion in status area.
  59.         var msg = getString( "completeMsg" );
  60.         msg = replaceInsert( msg, 1, formatSeconds( elapsed/1000 ) );
  61.         dialog.status.setAttribute("value", msg);
  62.  
  63.         // Put progress meter at 100%.
  64.         dialog.progress.setAttribute( "value", 100 );
  65.         dialog.progress.setAttribute( "mode", "normal" );
  66.         var percentMsg = getString( "percentMsg" );
  67.         percentMsg = replaceInsert( percentMsg, 1, 100 );
  68.         dialog.progressText.setAttribute("label", percentMsg);
  69.  
  70.         processEndOfDownload();
  71.       }
  72.     },
  73.  
  74.     onProgressChange: function(aWebProgress, aRequest, aCurSelfProgress, aMaxSelfProgress, aCurTotalProgress, aMaxTotalProgress)
  75.     {
  76.  
  77.       if (!gRestartChecked) 
  78.       {
  79.         gRestartChecked = true;
  80.         try 
  81.         {
  82.         // right now, all that supports restarting downloads is ftp (rfc959)    
  83.         ftpChannel = aRequest.QueryInterface(Components.interfaces.nsIFTPChannel);
  84.         if (ftpChannel) {
  85.             dialog.pause.setAttribute("hidden", false);
  86.             dialog.pause.setAttribute("label", getString("pause"));
  87.         }
  88.       }
  89.         catch (ex) {}
  90.       }
  91.  
  92.       // this is so that we don't clobber the status text if 
  93.       // a onProgressChange event happens after we press the pause btn.
  94.       if (dialog.downloadPaused) 
  95.       {
  96.         dialog.status.setAttribute("value", getString("pausedMsg"));
  97.       }
  98.  
  99.       dialog.request = aRequest;  
  100.  
  101.       var overallProgress = aCurTotalProgress;
  102.  
  103.       // Get current time.
  104.       var now = ( new Date() ).getTime();
  105.       // If interval hasn't elapsed, ignore it.
  106.       if ( now - lastUpdate < interval && aMaxTotalProgress != "-1" &&  eval(aCurTotalProgress) < eval(aMaxTotalProgress) )
  107.         return;
  108.  
  109.       // Update this time.
  110.       lastUpdate = now;
  111.  
  112.       // Update download rate.
  113.       elapsed = now - startTime;
  114.       var rate; // aCurTotalProgress/sec
  115.       if ( elapsed )
  116.         rate = ( aCurTotalProgress * 1000 ) / elapsed;
  117.       else
  118.         rate = 0;
  119.  
  120.       // Update elapsed time display.
  121.       dialog.timeElapsed.setAttribute("value", formatSeconds( elapsed / 1000 ));
  122.  
  123.       // Calculate percentage.
  124.       var percent;
  125.       if ( aMaxTotalProgress > 0)
  126.       {
  127.         percent = parseInt( (overallProgress*100)/aMaxTotalProgress + .5 );
  128.         if ( percent > 100 )
  129.           percent = 100;
  130.  
  131.         // Advance progress meter.
  132.         dialog.progress.setAttribute( "value", percent );
  133.       }
  134.       else
  135.       {
  136.         percent = -1;
  137.  
  138.         // Progress meter should be barber-pole in this case.
  139.         dialog.progress.setAttribute( "mode", "undetermined" );
  140.       }
  141.  
  142.       // now that we've set the progress and the time, update # bytes downloaded...
  143.       // Update status (nnK of mmK bytes at xx.xK aCurTotalProgress/sec)
  144.       var status = getString( "progressMsg" );
  145.  
  146.       // Insert 1 is the number of kilobytes downloaded so far.
  147.       status = replaceInsert( status, 1, parseInt( overallProgress/1024 + .5 ) );
  148.  
  149.       // Insert 2 is the total number of kilobytes to be downloaded (if known).
  150.       if ( aMaxTotalProgress != "-1" )
  151.          status = replaceInsert( status, 2, parseInt( aMaxTotalProgress/1024 + .5 ) );
  152.       else
  153.          status = replaceInsert( status, 2, "??" );
  154.  
  155.       if ( rate )
  156.       {
  157.         // rate is bytes/sec
  158.         var kRate = rate / 1024; // K bytes/sec;
  159.         kRate = parseInt( kRate * 10 + .5 ); // xxx (3 digits)
  160.         // Don't update too often!
  161.         if ( kRate != priorRate )
  162.         {
  163.           if ( rateChanges++ == rateChangeLimit )
  164.           {
  165.              // Time to update download rate.
  166.              priorRate = kRate;
  167.              rateChanges = 0;
  168.           }
  169.           else
  170.           {
  171.             // Stick with old rate for a bit longer.
  172.             kRate = priorRate;
  173.           }
  174.         }
  175.         else
  176.           rateChanges = 0;
  177.  
  178.          var fraction = kRate % 10;
  179.          kRate = parseInt( ( kRate - fraction ) / 10 );
  180.  
  181.          // Insert 3 is the download rate (in kilobytes/sec).
  182.          status = replaceInsert( status, 3, kRate + "." + fraction );
  183.       }
  184.       else
  185.        status = replaceInsert( status, 3, "??.?" );
  186.  
  187.       // Update status msg.
  188.       dialog.status.setAttribute("value", status);
  189.  
  190.       // Update percentage label on progress meter.
  191.       if (percent < 0)
  192.         dialog.progressText.setAttribute("value", "");
  193.       else
  194.       {
  195.       var percentMsg = getString( "percentMsg" );
  196.       percentMsg = replaceInsert( percentMsg, 1, percent );
  197.       dialog.progressText.setAttribute("value", percentMsg);
  198.       }
  199.  
  200.       // Update time remaining.
  201.       if ( rate && (aMaxTotalProgress > 0) )
  202.       {
  203.         var rem = ( aMaxTotalProgress - aCurTotalProgress ) / rate;
  204.             rem = parseInt( rem + .5 );
  205.             dialog.timeLeft.setAttribute("value", formatSeconds( rem ));
  206.       }
  207.       else
  208.             dialog.timeLeft.setAttribute("value", getString( "unknownTime" ));
  209.     },
  210.     onLocationChange: function(aWebProgress, aRequest, aLocation)
  211.     {
  212.       // we can ignore this notification
  213.     },
  214.     onStatusChange: function(aWebProgress, aRequest, aStatus, aMessage)
  215.     {
  216.     },
  217.     onSecurityChange: function(aWebProgress, aRequest, state)
  218.     {
  219.     },
  220.     QueryInterface : function(iid)
  221.     {
  222.      if (iid.equals(Components.interfaces.nsIWebProgressListener) || iid.equals(Components.interfaces.nsISupportsWeakReference))
  223.       return this;
  224.  
  225.      throw Components.results.NS_NOINTERFACE;
  226.     }
  227. };
  228.  
  229. function getString( stringId ) {
  230.    // Check if we've fetched this string already.
  231.    if ( !dialog.strings[ stringId ] ) {
  232.       // Try to get it.
  233.       var elem = document.getElementById( "dialog.strings."+stringId );
  234.       try {
  235.         if ( elem
  236.            &&
  237.            elem.childNodes
  238.            &&
  239.            elem.childNodes[0]
  240.            &&
  241.            elem.childNodes[0].nodeValue ) {
  242.          dialog.strings[ stringId ] = elem.childNodes[0].nodeValue;
  243.         } else {
  244.           // If unable to fetch string, use an empty string.
  245.           dialog.strings[ stringId ] = "";
  246.         }
  247.       } catch (e) { dialog.strings[ stringId ] = ""; }
  248.    }
  249.    return dialog.strings[ stringId ];
  250. }
  251.  
  252. function formatSeconds( secs )
  253. {
  254.   // Round the number of seconds to remove fractions.
  255.   secs = parseInt( secs + .5 );
  256.   var hours = parseInt( secs/3600 );
  257.   secs -= hours*3600;
  258.   var mins = parseInt( secs/60 );
  259.   secs -= mins*60;
  260.   var result;
  261.   if ( hours )
  262.     result = getString( "longTimeFormat" );
  263.   else
  264.     result = getString( "shortTimeFormat" );
  265.  
  266.   if ( hours < 10 )
  267.      hours = "0" + hours;
  268.   if ( mins < 10 )
  269.      mins = "0" + mins;
  270.   if ( secs < 10 )
  271.      secs = "0" + secs;
  272.  
  273.   // Insert hours, minutes, and seconds into result string.
  274.   result = replaceInsert( result, 1, hours );
  275.   result = replaceInsert( result, 2, mins );
  276.   result = replaceInsert( result, 3, secs );
  277.  
  278.   return result;
  279. }
  280.  
  281. function loadDialog()
  282. {
  283.   var sourceUrlValue = {};
  284.   var initialDownloadTimeValue = {};
  285.   // targetFile is global because we are going to want re-use later one...
  286.   targetFile =  helperAppLoader.getDownloadInfo(sourceUrlValue, initialDownloadTimeValue);
  287.  
  288.   var sourceUrl = sourceUrlValue.value;
  289.   startTime = initialDownloadTimeValue.value / 1000;
  290.  
  291.   // set the elapsed time on the first pass...
  292.   var now = ( new Date() ).getTime();
  293.   // intialize the elapsed time global variable slot
  294.   elapsed = now - startTime;
  295.   // Update elapsed time display.
  296.   dialog.timeElapsed.setAttribute("value", formatSeconds( elapsed / 1000 ));
  297.   dialog.timeLeft.setAttribute("value", formatSeconds( 0 ));
  298.  
  299.   dialog.location.setAttribute("value", sourceUrl.spec );
  300.   dialog.fileName.setAttribute( "value", targetFile.unicodePath );
  301.  
  302.   var prefs = Components.classes[prefContractID].getService(Components.interfaces.nsIPref);
  303.   if (prefs)
  304.     keepProgressWindowUpBox.checked = prefs.GetBoolPref("browser.download.progressDnldDialog.keepAlive");
  305. }
  306.  
  307. function replaceInsert( text, index, value ) {
  308.    var result = text;
  309.    var regExp = eval( "/#"+index+"/" );
  310.    result = result.replace( regExp, value );
  311.    return result;
  312. }
  313.  
  314. function onLoad() {
  315.     // Set global variables.
  316.     helperAppLoader = window.arguments[0].QueryInterface( Components.interfaces.nsIHelperAppLauncher );
  317.  
  318.     if ( !helperAppLoader ) {
  319.         dump( "Invalid argument to downloadProgress.xul\n" );
  320.         window.close()
  321.         return;
  322.     }
  323.  
  324.     dialog = new Object;
  325.     dialog.strings = new Array;
  326.     dialog.location    = document.getElementById("dialog.location");
  327.     dialog.contentType = document.getElementById("dialog.contentType");
  328.     dialog.fileName    = document.getElementById("dialog.fileName");
  329.     dialog.status      = document.getElementById("dialog.status");
  330.     dialog.progress    = document.getElementById("dialog.progress");
  331.     dialog.progressText = document.getElementById("dialog.progressText");
  332.     dialog.timeLeft    = document.getElementById("dialog.timeLeft");
  333.     dialog.timeElapsed = document.getElementById("dialog.timeElapsed");
  334.     dialog.cancel      = document.getElementById("cancel");
  335.     dialog.pause       = document.getElementById("pause")
  336.     dialog.request     = 0;
  337.     dialog.downloadPaused = false;
  338.     keepProgressWindowUpBox = document.getElementById('keepProgressDialogUp');
  339.  
  340.     // Set up dialog button callbacks.
  341.     var object = this;
  342.     doSetOKCancel("", function () { return object.onCancel();});
  343.  
  344.     // Fill dialog.
  345.     loadDialog();
  346.  
  347.     // set our web progress listener on the helper app launcher
  348.     helperAppLoader.setWebProgressListener(progressListener);
  349.  
  350.     if ( window.opener ) {
  351.         moveToAlertPosition();
  352.     } else {
  353.         centerWindowOnScreen();
  354.     }
  355. }
  356.  
  357. function onUnload()
  358. {
  359.  
  360.   // remember the user's decision for the checkbox.
  361.  
  362.   var prefs = Components.classes[prefContractID].getService(Components.interfaces.nsIPref);
  363.   if (prefs)
  364.     prefs.SetBoolPref("browser.download.progressDnldDialog.keepAlive", keepProgressWindowUpBox.checked);
  365.  
  366.    // Cancel app launcher.
  367.    if (helperAppLoader)
  368.    {
  369.      try
  370.      {
  371.        helperAppLoader.closeProgressWindow();
  372.        helperAppLoader = null;
  373.      }
  374.  
  375.      catch( exception ) {}
  376.    }
  377. }
  378.  
  379. // If the user presses cancel, tell the app launcher and close the dialog...
  380. function onCancel ()
  381. {
  382.    // Cancel app launcher.
  383.    if (helperAppLoader)
  384.    {
  385.      try
  386.      {
  387.        helperAppLoader.Cancel();
  388.      }
  389.  
  390.      catch( exception ) {}
  391.    }
  392.  
  393.   // Close up dialog by returning true.
  394.   return true;
  395. }
  396.  
  397. // closeWindow should only be called from processEndOfDownload
  398. function closeWindow()
  399. {
  400.   // while the time out was fired the user may have checked the
  401.   // keep this dialog open box...so we should abort and not actually
  402.   // close the window.
  403.  
  404.   if (!keepProgressWindowUpBox.checked)
  405.     window.close();
  406.   else
  407.     setupPostProgressUI();
  408. }
  409.  
  410. function setupPostProgressUI()
  411. {
  412.   //dialog.cancel.childNodes[0].nodeValue = "Close";
  413.   // turn the cancel button into a close button
  414.   var cancelButton = document.getElementById('cancel');
  415.   if (cancelButton)
  416.   {
  417.     cancelButton.label = "Close"; // mscott -> replace with a string bundle
  418.     cancelButton.setAttribute("onclick", "window.close()");
  419.   }
  420.  
  421.   // enable the open and open folder buttons
  422.   var openFolderButton = document.getElementById('openFolder');
  423.   var openButton = document.getElementById('open');
  424.  
  425.   openFolderButton.removeAttribute("disabled");
  426.   if ( !targetFile.isExecutable() )
  427.   {
  428.     openButton.removeAttribute("disabled");
  429.   }
  430.  
  431.   dialog.pause.setAttribute("disabled", true);
  432. }
  433.  
  434. // when we receive a stop notification we are done reporting progress on the download
  435. // now we have to decide if the window is supposed to go away or if we are supposed to remain open
  436. // and enable the open and open folder buttons on the dialog.
  437. function processEndOfDownload()
  438. {
  439.   if (!keepProgressWindowUpBox.checked)
  440.     return window.setTimeout( "closeWindow();", 2000 ); // shut down, we are all done.
  441.  
  442.   // o.t the user has asked the window to stay open so leave it open and enable the open and open new folder buttons
  443.   setupPostProgressUI();
  444. }
  445.  
  446. function doOpen()
  447. {
  448.   try {
  449.     var localFile = targetFile.QueryInterface(Components.interfaces.nsILocalFile);
  450.     if (localFile)
  451.       localFile.launch();
  452.   } catch (ex) {}
  453. }
  454.  
  455. function doOpenFolder()
  456. {
  457.   try {
  458.     var localFile = targetFile.QueryInterface(Components.interfaces.nsILocalFile);
  459.     if (localFile)
  460.       localFile.reveal();
  461.   } catch (ex) {}
  462. }
  463.  
  464. function doPauseButton() {
  465.     if (dialog.downloadPaused)
  466.     {
  467.         // resume
  468.         dialog.downloadPaused = false;
  469.         dialog.pause.setAttribute("label", getString("pause"));
  470.         dialog.request.resume()
  471.     }
  472.     else
  473.     {
  474.         // suspend
  475.         dialog.downloadPaused = true;
  476.         dialog.pause.setAttribute("label", getString("resume"));
  477.         dialog.request.suspend()
  478.     }
  479. }
  480.