# -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- # ***** BEGIN LICENSE BLOCK ***** # Version: MPL 1.1/GPL 2.0/LGPL 2.1 # # The contents of this file are subject to the Mozilla Public License Version # 1.1 (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # http://www.mozilla.org/MPL/ # # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License # for the specific language governing rights and limitations under the # License. # # The Original Code is Mozilla.org Code. # # The Initial Developer of the Original Code is # Doron Rosenberg. # Portions created by the Initial Developer are Copyright (C) 2001 # the Initial Developer. All Rights Reserved. # # Contributor(s): # Blake Ross (Original Author) # Ben Goodger (v2.0) # # Alternatively, the contents of this file may be used under the terms of # either the GNU General Public License Version 2 or later (the "GPL"), or # the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), # in which case the provisions of the GPL or the LGPL are applicable instead # of those above. If you wish to allow use of your version of this file only # under the terms of either the GPL or the LGPL, and not to allow others to # use your version of this file under the terms of the MPL, indicate your # decision by deleting the provisions above and replace them with the notice # and other provisions required by the GPL or the LGPL. If you do not delete # the provisions above, a recipient may use your version of this file under # the terms of any one of the MPL, the GPL or the LGPL. # # ***** END LICENSE BLOCK ***** var gStrings = []; const interval = 500; // Update every 500 milliseconds. function DownloadProgressListener (aDocument, aStringBundle) { this.doc = aDocument; this._statusFormat = aStringBundle.getString("statusFormat"); this._statusFormatKBMB = aStringBundle.getString("statusFormatKBMB"); this._statusFormatKBKB = aStringBundle.getString("statusFormatKBKB"); this._statusFormatMBMB = aStringBundle.getString("statusFormatMBMB"); this._statusFormatUnknownMB = aStringBundle.getString("statusFormatUnknownMB"); this._statusFormatUnknownKB = aStringBundle.getString("statusFormatUnknownKB"); this._remain = aStringBundle.getString("remain"); this._unknownFilesize = aStringBundle.getString("unknownFilesize"); this._longTimeFormat = aStringBundle.getString("longTimeFormat"); this._shortTimeFormat = aStringBundle.getString("shortTimeFormat"); } DownloadProgressListener.prototype = { rateChanges: 0, rateChangeLimit: 0, priorRate: 0, lastUpdate: -500, doc: null, onStateChange: function(aWebProgress, aRequest, aStateFlags, aStatus, aDownload) { if (aStateFlags & Components.interfaces.nsIWebProgressListener.STATE_STOP) { var aDownloadID = aDownload.targetFile.path; var download = this.doc.getElementById(aDownloadID); if (download) download.setAttribute("status", ""); } }, onProgressChange: function(aWebProgress, aRequest, aCurSelfProgress, aMaxSelfProgress, aCurTotalProgress, aMaxTotalProgress, aDownload) { var overallProgress = aCurTotalProgress; // Get current time. var now = (new Date()).getTime(); // If interval hasn't elapsed, ignore it. if (now - this.lastUpdate < interval && aMaxTotalProgress != "-1" && parseInt(aCurTotalProgress) < parseInt(aMaxTotalProgress)) { return; } // Update this time. this.lastUpdate = now; var aDownloadID = aDownload.targetFile.path; var download = this.doc.getElementById(aDownloadID); // Calculate percentage. var percent; if (aMaxTotalProgress > 0) { percent = Math.floor((overallProgress*100.0)/aMaxTotalProgress); if (percent > 100) percent = 100; // Advance progress meter. if (download) { download.setAttribute("progress", percent); download.setAttribute("progressmode", "normal"); onUpdateProgress(); } } else { percent = -1; // Progress meter should be barber-pole in this case. download.setAttribute("progressmode", "undetermined"); } // Now that we've set the progress and the time, update the UI with // all the the pertinent information (bytes transferred, bytes total, // download rate, time remaining). var status = this._statusFormat; // Insert the progress so far using the formatting routine. var KBProgress = parseInt(overallProgress/1024 + .5); var KBTotal = parseInt(aMaxTotalProgress/1024 + .5); var kbProgress = this._formatKBytes(KBProgress, KBTotal); status = this._replaceInsert(status, 1, kbProgress); if (download) download.setAttribute("status-internal", kbProgress); var rate = aDownload.QueryInterface(Components.interfaces.nsIDownload_MOZILLA_1_8_BRANCH).speed; if (rate) { // rate is bytes/sec var kRate = rate / 1024; // K bytes/sec; kRate = parseInt( kRate * 10 + .5 ); // xxx (3 digits) // Don't update too often! if (kRate != this.priorRate) { if (this.rateChanges++ == this.rateChangeLimit) { // Time to update download rate. this.priorRate = kRate; this.rateChanges = 0; } else { // Stick with old rate for a bit longer. kRate = this.priorRate; } } else this.rateChanges = 0; var fraction = kRate % 10; kRate = parseInt((kRate - fraction) / 10); // Insert 3 is the download rate (in kilobytes/sec). if (kRate < 100) kRate += "." + fraction; status = this._replaceInsert(status, 2, kRate); } else status = this._replaceInsert(status, 2, "??.?"); // Update time remaining. if (rate && (aMaxTotalProgress > 0)) { var rem = (aMaxTotalProgress - aCurTotalProgress) / rate; rem = parseInt(rem + .5); status = this._replaceInsert(status, 3, this._formatSeconds(rem, this.doc) + " " + this._remain); } else status = this._replaceInsert(status, 3, this._unknownFilesize); if (download) download.setAttribute("status", status); }, onLocationChange: function(aWebProgress, aRequest, aLocation, aDownload) { }, onStatusChange: function(aWebProgress, aRequest, aStatus, aMessage, aDownload) { }, onSecurityChange: function(aWebProgress, aRequest, state, aDownload) { }, QueryInterface : function(iid) { if (iid.equals(Components.interfaces.nsIDownloadProgressListener) || iid.equals(Components.interfaces.nsISupports)) return this; throw Components.results.NS_NOINTERFACE; }, _replaceInsert: function ( text, index, value ) { var result = text; var regExp = new RegExp( "#"+index ); result = result.replace( regExp, value ); return result; }, // aBytes aTotalKBytes returns: // x, < 1MB y < 1MB x of y KB // x, < 1MB y >= 1MB x KB of y MB // x, >= 1MB y >= 1MB x of y MB _formatKBytes: function (aKBytes, aTotalKBytes) { var progressHasMB = parseInt(aKBytes/1024) > 0; var totalHasMB = parseInt(aTotalKBytes/1024) > 0; var format = ""; if (!progressHasMB && !totalHasMB) { if (!aTotalKBytes) { format = this._statusFormatUnknownKB; format = this._replaceInsert(format, 1, aKBytes); } else { format = this._statusFormatKBKB; format = this._replaceInsert(format, 1, aKBytes); format = this._replaceInsert(format, 2, aTotalKBytes); } } else if (progressHasMB && totalHasMB) { format = this._statusFormatMBMB; format = this._replaceInsert(format, 1, (aKBytes / 1024).toFixed(1)); format = this._replaceInsert(format, 2, (aTotalKBytes / 1024).toFixed(1)); } else if (totalHasMB && !progressHasMB) { format = this._statusFormatKBMB; format = this._replaceInsert(format, 1, aKBytes); format = this._replaceInsert(format, 2, (aTotalKBytes / 1024).toFixed(1)); } else if (progressHasMB && !totalHasMB) { format = this._statusFormatUnknownMB; format = this._replaceInsert(format, 1, (aKBytes / 1024).toFixed(1)); } else { // This is an undefined state! dump("*** huh?!\n"); } return format; }, _formatSeconds: function (secs, doc) { // Round the number of seconds to remove fractions. secs = parseInt(secs + .5); var hours = parseInt(secs/3600); secs -= hours * 3600; var mins = parseInt(secs/60); secs -= mins * 60; var result = hours ? this._longTimeFormat : this._shortTimeFormat; if (hours < 10) hours = "0" + hours; if (mins < 10) mins = "0" + mins; if (secs < 10) secs = "0" + secs; // Insert hours, minutes, and seconds into result string. result = this._replaceInsert(result, 1, hours); result = this._replaceInsert(result, 2, mins); result = this._replaceInsert(result, 3, secs); return result; } };