home *** CD-ROM | disk | FTP | other *** search
/ GameStar 2005 October / Gamestar_77_2005-10_dvd.iso / Programy / nsb-install-8-0.exe / chrome / toolkit.jar / content / mozapps / downloads / downloads.js < prev    next >
Text File  |  2005-07-29  |  30KB  |  822 lines

  1.  
  2. ///////////////////////////////////////////////////////////////////////////////
  3. // Globals
  4.  
  5. const kObserverServiceProgID = "@mozilla.org/observer-service;1";
  6. const NC_NS = "http://home.netscape.com/NC-rdf#";
  7. const PREF_BDM_CLOSEWHENDONE = "browser.download.manager.closeWhenDone";
  8. const PREF_BDM_ALERTONEXEOPEN = "browser.download.manager.alertOnEXEOpen";
  9.  
  10. var gDownloadManager  = null;
  11. var gDownloadListener = null;
  12. var gDownloadsView    = null;
  13. var gUserInterfered   = false;
  14. var gActiveDownloads  = [];
  15.  
  16. // This variable exists because for XPInstalls, we don't want to close the 
  17. // download manager until the XPInstallManager sends the DIALOG_CLOSE status
  18. // message. Setting this variable to false when the downloads window is 
  19. // opened by the xpinstall manager prevents the window from being closed after
  20. // each download completes (because xpinstall downloads are done sequentially, 
  21. // not concurrently) 
  22. var gCanAutoClose     = true;
  23.  
  24. ///////////////////////////////////////////////////////////////////////////////
  25. // Utility Functions 
  26. function setRDFProperty(aID, aProperty, aValue)
  27. {
  28.   var rdf = Components.classes["@mozilla.org/rdf/rdf-service;1"].getService(Components.interfaces.nsIRDFService);
  29.  
  30.   var db = gDownloadManager.datasource;
  31.   var propertyArc = rdf.GetResource(NC_NS + aProperty);
  32.   
  33.   var res = rdf.GetResource(aID);
  34.   var node = db.GetTarget(res, propertyArc, true);
  35.   if (node)
  36.     db.Change(res, propertyArc, node, rdf.GetLiteral(aValue));
  37.   else
  38.     db.Assert(res, propertyArc, rdf.GetLiteral(aValue), true);
  39. }
  40.  
  41. function getRDFProperty(aID, aProperty)
  42. {
  43.   var rdf = Components.classes["@mozilla.org/rdf/rdf-service;1"].getService(Components.interfaces.nsIRDFService);
  44.  
  45.   var db = gDownloadManager.datasource;
  46.   var propertyArc = rdf.GetResource(NC_NS + aProperty);
  47.   
  48.   var res = rdf.GetResource(aID);
  49.   var node = db.GetTarget(res, propertyArc, true);
  50.   if (!node) return "";
  51.   try {
  52.     node = node.QueryInterface(Components.interfaces.nsIRDFLiteral);
  53.     return node.Value;
  54.   }
  55.   catch (e) {
  56.     try {
  57.       node = node.QueryInterface(Components.interfaces.nsIRDFInt);
  58.       return node.Value;
  59.     }
  60.     catch (e) {
  61.       node = node.QueryInterface(Components.interfaces.nsIRDFResource);
  62.       return node.Value;
  63.     }
  64.   }
  65.   return "";
  66. }
  67.  
  68. function fireEventForElement(aElement, aEventType)
  69. {
  70.   var e = document.createEvent("Events");
  71.   e.initEvent("download-" + aEventType, false, true);
  72.   
  73.   aElement.dispatchEvent(e);
  74. }
  75.  
  76. ///////////////////////////////////////////////////////////////////////////////
  77. // Start/Stop Observers
  78. function downloadCompleted(aDownload) 
  79. {
  80.   // Wrap this in try...catch since this can be called while shutting down... 
  81.   // it doesn't really matter if it fails then since well.. we're shutting down
  82.   // and there's no UI to update!
  83.   try {
  84.     var rdf = Components.classes["@mozilla.org/rdf/rdf-service;1"].getService(Components.interfaces.nsIRDFService);
  85.     var rdfc = Components.classes["@mozilla.org/rdf/container;1"].createInstance(Components.interfaces.nsIRDFContainer);
  86.  
  87.     var db = gDownloadManager.datasource;
  88.     
  89.     rdfc.Init(db, rdf.GetResource("NC:DownloadsRoot"));
  90.  
  91.     var id = aDownload.targetFile.path;
  92.     
  93.     // Refresh the icon, so that executable icons are shown.
  94.     var mimeService = Components.classes["@mozilla.org/uriloader/external-helper-app-service;1"].getService(Components.interfaces.nsIMIMEService);
  95.     var contentType = mimeService.getTypeFromFile(aDownload.targetFile);
  96.     
  97.     var listItem = document.getElementById(id);
  98.     var oldImage = listItem.getAttribute("image");
  99.     // I tack on the content-type here as a hack to bypass the cache which seems
  100.     // to be interfering despite the fact the image has 'validate="always"' set
  101.     // on it. 
  102.     listItem.setAttribute("image", oldImage + "&contentType=" + contentType);
  103.     
  104.     var dlRes = rdf.GetUnicodeResource(id);
  105.   
  106.     var insertIndex = gDownloadManager.activeDownloadCount + 1;
  107.     // Don't bother inserting the item into the same place!
  108.     if (insertIndex != rdfc.IndexOf(dlRes)) {
  109.       rdfc.RemoveElement(dlRes, true);
  110.       if (insertIndex == rdfc.GetCount() || insertIndex < 1) 
  111.         rdfc.AppendElement(dlRes);
  112.       else
  113.         rdfc.InsertElementAt(dlRes, insertIndex, true);      
  114.     }
  115.         
  116.     // Remove the download from our book-keeping list and if the count
  117.     // falls to zero, update the title here, since we won't be getting
  118.     // any more progress notifications in which to do it. 
  119.     for (var i = 0; i < gActiveDownloads.length; ++i) {
  120.       if (gActiveDownloads[i] == aDownload) {
  121.         gActiveDownloads.splice(i, 1);
  122.         break;
  123.       }
  124.     }
  125.  
  126.     gDownloadViewController.onCommandUpdate();
  127.  
  128.     if (gActiveDownloads.length == 0)
  129.       window.title = document.documentElement.getAttribute("statictitle");    
  130.   }
  131.   catch (e) {
  132.   }
  133. }
  134.  
  135. function autoClose(aDownload)
  136. {
  137.   if (gDownloadManager.activeDownloadCount == 0) {
  138.     // For the moment, just use the simple heuristic that if this window was
  139.     // opened by the download process, rather than by the user, it should auto-close
  140.     // if the pref is set that way. If the user opened it themselves, it should
  141.     // not close until they explicitly close it. 
  142.     // We may like to revisit this in a bit more detail later, perhaps we want
  143.     // to keep it up if the user messes with it in a significant way.
  144.     var pref = Components.classes["@mozilla.org/preferences-service;1"]
  145.                         .getService(Components.interfaces.nsIPrefBranch);
  146.     var autoClose = pref.getBoolPref(PREF_BDM_CLOSEWHENDONE)
  147.     if (autoClose && (!window.opener || window.opener.location.href == window.location.href) &&
  148.         gCanAutoClose)
  149.       gCloseDownloadManager();
  150.   }
  151. }
  152.  
  153. // This function can be overwritten by extensions that wish to place the Download Window in
  154. // another part of the UI, such as in a tab or a sidebar panel. 
  155. function gCloseDownloadManager()
  156. {
  157.   window.close();
  158. }
  159.  
  160. var gDownloadObserver = {
  161.   observe: function (aSubject, aTopic, aState) 
  162.   {
  163.     switch (aTopic) {
  164.     case "dl-done":
  165.       var dl = aSubject.QueryInterface(Components.interfaces.nsIDownload);
  166.       downloadCompleted(dl);
  167.       
  168.       autoClose(dl);      
  169.       break;
  170.     case "dl-failed":
  171.     case "dl-cancel":
  172.       var dl = aSubject.QueryInterface(Components.interfaces.nsIDownload);
  173.       downloadCompleted(dl);
  174.       break;
  175.     case "dl-start":
  176.       // Add this download to the percentage average tally
  177.       var dl = aSubject.QueryInterface(Components.interfaces.nsIDownload);
  178.       gActiveDownloads.push(dl);
  179.       break;
  180.     case "xpinstall-download-started":
  181.       var windowArgs = aSubject.QueryInterface(Components.interfaces.nsISupportsArray);
  182.       var params = windowArgs.QueryElementAt(0, Components.interfaces.nsISupportsInterfacePointer);
  183.       params = params.data.QueryInterface(Components.interfaces.nsIDialogParamBlock);
  184.       var installObserver = windowArgs.QueryElementAt(1, Components.interfaces.nsISupportsInterfacePointer);
  185.       installObserver = installObserver.data.QueryInterface(Components.interfaces.nsIObserver);
  186.       XPInstallDownloadManager.addDownloads(params, installObserver);
  187.       break;  
  188.     case "xpinstall-dialog-close":
  189.       if ("gDownloadManager" in window) {
  190.         var mgr = gDownloadManager.QueryInterface(Components.interfaces.nsIXPInstallManagerUI);
  191.         gCanAutoClose = mgr.hasActiveXPIOperations;
  192.         autoClose();
  193.       }
  194.       break;          
  195.     }
  196.   }
  197. };
  198.  
  199. ///////////////////////////////////////////////////////////////////////////////
  200. // Download Event Handlers
  201.  
  202. function onDownloadCancel(aEvent)
  203. {
  204.   gDownloadManager.cancelDownload(aEvent.target.id);
  205.  
  206.   setRDFProperty(aEvent.target.id, "DownloadAnimated", "false");
  207.  
  208.   // XXXben - 
  209.   // If we got here because we resumed the download, we weren't using a temp file
  210.   // because we used saveURL instead. (this is because the proper download mechanism
  211.   // employed by the helper app service isn't fully accessible yet... should be fixed...
  212.   // talk to bz...)
  213.   // the upshot is we have to delete the file if it exists. 
  214.   var f = getLocalFileFromNativePathOrUrl(aEvent.target.id);
  215.  
  216.   if (f.exists()) 
  217.     f.remove(false);
  218.  
  219.   gDownloadViewController.onCommandUpdate();
  220. }
  221.  
  222. function onDownloadPause(aEvent)
  223. {
  224.   var uri = aEvent.target.id;
  225.   gDownloadManager.pauseDownload(uri);
  226.   setRDFProperty(uri, "DownloadStatus", aEvent.target.getAttribute("status-internal"));
  227.   setRDFProperty(uri, "ProgressPercent", aEvent.target.getAttribute("progress"));
  228. }
  229.  
  230. function onDownloadResume(aEvent)
  231. {
  232.   gDownloadManager.resumeDownload(aEvent.target.id);
  233. }
  234.  
  235. function onDownloadRemove(aEvent)
  236. {
  237.   if (aEvent.target.removable) {
  238.     gDownloadManager.removeDownload(aEvent.target.id);
  239.     
  240.     gDownloadViewController.onCommandUpdate();
  241.   }
  242. }
  243.  
  244. function onDownloadShow(aEvent)
  245. {
  246.   var f = getLocalFileFromNativePathOrUrl(aEvent.target.id);
  247.  
  248.   if (f.exists()) {
  249.     try {
  250.       f.reveal();
  251.     } catch (ex) {
  252.       // if reveal failed for some reason (eg on unix it's not currently
  253.       // implemented), send the file: URL  window rooted at the parent to 
  254.       // the OS handler for that protocol
  255.       var parent = f.parent;
  256.       if (parent) {
  257.         openExternal(parent.path);
  258.       }
  259.     }
  260.   }
  261.   else {
  262.     var brandStrings = document.getElementById("brandStrings");
  263.     var appName = brandStrings.getString("brandShortName");
  264.   
  265.     var strings = document.getElementById("downloadStrings");
  266.     var name = aEvent.target.getAttribute("target");
  267.     var message = strings.getFormattedString("fileDoesNotExistError", [name, appName]);
  268.     var title = strings.getFormattedString("fileDoesNotExistShowTitle", [name]);
  269.  
  270.     var promptSvc = Components.classes["@mozilla.org/embedcomp/prompt-service;1"].getService(Components.interfaces.nsIPromptService);
  271.     promptSvc.alert(window, title, message);
  272.   }
  273. }
  274.  
  275. function onDownloadOpen(aEvent)
  276. {
  277.   if (aEvent.type == "dblclick" && aEvent.button != 0)
  278.     return;
  279.   var download = aEvent.target;
  280.   if (download.localName == "download") {
  281.     if (download.openable) {
  282.       var f = getLocalFileFromNativePathOrUrl(aEvent.target.id);
  283.       if (f.exists()) {
  284.         if (f.isExecutable()) {
  285.           var dontAsk = false;
  286.           var pref = Components.classes["@mozilla.org/preferences-service;1"]
  287.                               .getService(Components.interfaces.nsIPrefBranch);
  288.           try {
  289.             dontAsk = !pref.getBoolPref(PREF_BDM_ALERTONEXEOPEN);
  290.           }
  291.           catch (e) { }
  292.           
  293.           if (!dontAsk) {
  294.             var strings = document.getElementById("downloadStrings");
  295.             var name = aEvent.target.getAttribute("target");
  296.             var message = strings.getFormattedString("fileExecutableSecurityWarning", [name, name]);
  297.  
  298.             var title = strings.getString("fileExecutableSecurityWarningTitle");
  299.             var dontAsk = strings.getString("fileExecutableSecurityWarningDontAsk");
  300.  
  301.             var promptSvc = Components.classes["@mozilla.org/embedcomp/prompt-service;1"].getService(Components.interfaces.nsIPromptService);
  302.             var checkbox = { value: false };
  303.             var open = promptSvc.confirmCheck(window, title, message, dontAsk, checkbox);
  304.             
  305.             if (!open) 
  306.               return;
  307.             else
  308.               pref.setBoolPref(PREF_BDM_ALERTONEXEOPEN, !checkbox.value);              
  309.           }        
  310.         }
  311.         try {
  312.           f.launch();
  313.         } catch (ex) {
  314.           // if launch fails, try sending it through the system's external
  315.           // file: URL handler
  316.           openExternal(f.path);
  317.         }
  318.       }
  319.       else {
  320.         var brandStrings = document.getElementById("brandStrings");
  321.         var appName = brandStrings.getString("brandShortName");
  322.       
  323.         var strings = document.getElementById("downloadStrings");
  324.         var name = aEvent.target.getAttribute("target");
  325.         var message = strings.getFormattedString("fileDoesNotExistError", [name, appName]);
  326.  
  327.         var title = strings.getFormattedString("fileDoesNotExistOpenTitle", [name]);
  328.  
  329.         var promptSvc = Components.classes["@mozilla.org/embedcomp/prompt-service;1"].getService(Components.interfaces.nsIPromptService);
  330.         promptSvc.alert(window, title, message);
  331.       }
  332.     }
  333.     else if(download.canceledOrFailed) {
  334.       // If the user canceled this download, double clicking tries again. 
  335.       fireEventForElement(download, "retry")
  336.     }
  337.   }
  338. }
  339.  
  340. function onDownloadOpenWith(aEvent)
  341. {
  342. }
  343.  
  344. function onDownloadProperties(aEvent)
  345. {
  346.   window.openDialog("chrome://mozapps/content/downloads/downloadProperties.xul",
  347.                     "_blank", "modal,centerscreen,chrome,resizable=no", aEvent.target.id);
  348. }
  349.  
  350. function onDownloadAnimated(aEvent)
  351. {
  352.   gDownloadViewController.onCommandUpdate();    
  353.  
  354.   setRDFProperty(aEvent.target.id, "DownloadAnimated", "true");
  355. }
  356.  
  357. function onDownloadRetry(aEvent)
  358. {
  359.   var download = aEvent.target;
  360.   if (download.localName == "download") {
  361.     var src = getRDFProperty(download.id, "URL");
  362.     var f = getLocalFileFromNativePathOrUrl(aEvent.target.id);
  363.     saveURL(src, f, null, true, true);
  364.   }
  365.   
  366.   gDownloadViewController.onCommandUpdate();
  367. }
  368.  
  369. // This is called by the progress listener. We don't actually use the event
  370. // system here to minimize time wastage. 
  371. var gLastComputedMean = 0;
  372. function onUpdateProgress()
  373. {
  374.   var numActiveDownloads = gActiveDownloads.length;
  375.   if (numActiveDownloads == 0) {
  376.     window.title = document.documentElement.getAttribute("statictitle");
  377.     gLastComputedMean = 0;
  378.     return;
  379.   }
  380.     
  381.   var mean = 0;
  382.   for (var i = 0; i < numActiveDownloads; ++i) {
  383.     var dl = gActiveDownloads[i];
  384.     var progress = dl.percentComplete;
  385.     if (progress < 100)
  386.       mean += progress;
  387.   }
  388.  
  389.   mean = Math.round(mean / numActiveDownloads);
  390.   
  391.   // At the end of a download, progress is set from 100% to 0% for 
  392.   // some reason. We can identify this case because at this point the
  393.   // mean progress will be zero but the last computed mean will be
  394.   // greater than zero. 
  395.   if (mean == 0 && gLastComputedMean > 0) {
  396.     window.title = document.documentElement.getAttribute("statictitle");
  397.     return;
  398.   }
  399.   if (mean != gLastComputedMean) {
  400.     gLastComputedMean = mean;
  401.     var strings = document.getElementById("downloadStrings");
  402.     
  403.     var title;
  404.     if (numActiveDownloads > 1)
  405.       title = strings.getFormattedString("downloadsTitleMultiple", [mean, numActiveDownloads]);
  406.     else
  407.       title = strings.getFormattedString("downloadsTitle", [mean]);
  408.  
  409.     window.title = title;
  410.   }
  411. }
  412.  
  413. ///////////////////////////////////////////////////////////////////////////////
  414. // Startup, Shutdown
  415. function Startup() 
  416. {
  417.   gDownloadsView = document.getElementById("downloadView");
  418.  
  419.   const dlmgrContractID = "@mozilla.org/download-manager;1";
  420.   const dlmgrIID = Components.interfaces.nsIDownloadManager;
  421.   gDownloadManager = Components.classes[dlmgrContractID].getService(dlmgrIID);
  422.   
  423.   // The DownloadProgressListener (DownloadProgressListener.js) handles progress
  424.   // notifications. 
  425.   var downloadStrings = document.getElementById("downloadStrings");
  426.   gDownloadListener = new DownloadProgressListener(document, downloadStrings);
  427.   gDownloadManager.listener = gDownloadListener;
  428.  
  429.   // The active downloads list is created by the front end only when the download starts,  
  430.   // so we need to pre-populate it with any downloads that were already going. 
  431.   var activeDownloads = gDownloadManager.activeDownloads;
  432.   var count = activeDownloads.Count();
  433.   for (var i = 0; i < count; ++i)
  434.     gActiveDownloads.push(activeDownloads.QueryElementAt(i, Components.interfaces.nsIDownload));
  435.  
  436.   // Handlers for events generated by the UI (downloads, list view)
  437.   gDownloadsView.addEventListener("download-cancel",      onDownloadCancel,     false);
  438.   gDownloadsView.addEventListener("download-pause",       onDownloadPause,      false);
  439.   gDownloadsView.addEventListener("download-resume",      onDownloadResume,     false);
  440.   gDownloadsView.addEventListener("download-remove",      onDownloadRemove,     false);
  441.   gDownloadsView.addEventListener("download-show",        onDownloadShow,       false);
  442.   gDownloadsView.addEventListener("download-open",        onDownloadOpen,       false);
  443.   gDownloadsView.addEventListener("download-retry",       onDownloadRetry,      false);
  444.   gDownloadsView.addEventListener("download-animated",    onDownloadAnimated,   false);
  445.   gDownloadsView.addEventListener("download-properties",  onDownloadProperties, false);
  446.   gDownloadsView.addEventListener("dblclick",             onDownloadOpen,       false);
  447.   
  448.   // Set up AutoDownload display area
  449.   initAutoDownloadDisplay();
  450.   var pbi = Components.classes["@mozilla.org/preferences-service;1"]
  451.                       .getService(Components.interfaces.nsIPrefBranchInternal);
  452.   pbi.addObserver("browser.download.", gDownloadPrefObserver, false);
  453.   
  454.   // Handlers for events generated by the Download Manager (download events)
  455.   var observerService = Components.classes[kObserverServiceProgID]
  456.                                   .getService(Components.interfaces.nsIObserverService);
  457.   observerService.addObserver(gDownloadObserver, "dl-done",   false);
  458.   observerService.addObserver(gDownloadObserver, "dl-cancel", false);
  459.   observerService.addObserver(gDownloadObserver, "dl-failed", false);  
  460.   observerService.addObserver(gDownloadObserver, "dl-start",  false);  
  461.   observerService.addObserver(gDownloadObserver, "xpinstall-download-started", false);  
  462.   observerService.addObserver(gDownloadObserver, "xpinstall-dialog-close",     false);
  463.   
  464.   // Now look and see if we're being opened by XPInstall
  465.   if ("arguments" in window) {
  466.     try {
  467.       var params = window.arguments[0].QueryInterface(Components.interfaces.nsIDialogParamBlock);
  468.       var installObserver = window.arguments[1].QueryInterface(Components.interfaces.nsIObserver);
  469.       XPInstallDownloadManager.addDownloads(params, installObserver);
  470.       var mgr = gDownloadManager.QueryInterface(Components.interfaces.nsIXPInstallManagerUI);
  471.       gCanAutoClose = mgr.hasActiveXPIOperations;
  472.     }
  473.     catch (e) { }
  474.   }
  475.  
  476.   // This is for the "Clean Up" button, which requires there to be
  477.   // non-active downloads before it can be enabled. 
  478.   gDownloadsView.controllers.appendController(gDownloadViewController);
  479.  
  480.   // Finally, update the UI. 
  481.   gDownloadsView.database.AddDataSource(gDownloadManager.datasource);
  482.   gDownloadsView.builder.rebuild();
  483.   
  484.   gDownloadsView.focus();
  485. }
  486.  
  487. function Shutdown() 
  488. {
  489.   gDownloadManager.listener = null;
  490.  
  491.   // Assert the current progress for all the downloads in case the window is reopened
  492.   gDownloadManager.saveState();
  493.  
  494.   var pbi = Components.classes["@mozilla.org/preferences-service;1"]
  495.                       .getService(Components.interfaces.nsIPrefBranchInternal);
  496.   pbi.removeObserver("browser.download.", gDownloadPrefObserver);
  497.  
  498.   var observerService = Components.classes[kObserverServiceProgID]
  499.                                   .getService(Components.interfaces.nsIObserverService);
  500.   observerService.removeObserver(gDownloadObserver, "dl-done");
  501.   observerService.removeObserver(gDownloadObserver, "dl-cancel");
  502.   observerService.removeObserver(gDownloadObserver, "dl-failed");  
  503.   observerService.removeObserver(gDownloadObserver, "dl-start");  
  504.   observerService.removeObserver(gDownloadObserver, "xpinstall-download-started");  
  505. }
  506.  
  507. ///////////////////////////////////////////////////////////////////////////////
  508. // XPInstall
  509.  
  510. var XPInstallDownloadManager = {
  511.   addDownloads: function (aParams, aObserver)
  512.   {
  513.     var numXPInstallItems = aParams.GetInt(1);
  514.     
  515.     var fileLocator = Components.classes["@mozilla.org/file/directory_service;1"].getService(Components.interfaces.nsIProperties);
  516.     var tempDir = fileLocator.get("TmpD", Components.interfaces.nsIFile);
  517.  
  518.     var mimeService = Components.classes["@mozilla.org/uriloader/external-helper-app-service;1"].getService(Components.interfaces.nsIMIMEService);
  519.     
  520.     var xpinstallManager = gDownloadManager.QueryInterface(Components.interfaces.nsIXPInstallManagerUI);
  521.  
  522.     var xpiString = "";
  523.     for (var i = 0; i < numXPInstallItems;) {
  524.       // Pretty Name
  525.       var displayName = aParams.GetString(i++);
  526.       
  527.       // URI
  528.       var uri = Components.classes["@mozilla.org/network/standard-url;1"].createInstance(Components.interfaces.nsIURI);
  529.       uri.spec = aParams.GetString(i++);
  530.       
  531.       var iconURL = aParams.GetString(i++);
  532.       
  533.       // Local File Target
  534.       var url = uri.QueryInterface(Components.interfaces.nsIURL);
  535.       var localTarget = tempDir.clone();
  536.       localTarget.append(url.fileName);
  537.       
  538.       xpiString += localTarget.path + ",";
  539.       
  540.       // MIME Info
  541.       var mimeInfo = null;
  542.       try {
  543.         mimeInfo = mimeService.getFromTypeAndExtension(null, url.fileExtension);
  544.       }
  545.       catch (e) { }
  546.       
  547.       if (!iconURL) 
  548.         iconURL = "chrome://mozapps/skin/xpinstall/xpinstallItemGeneric.png";
  549.       
  550.       var targetUrl = makeFileURL(localTarget);
  551.       var download = gDownloadManager.addDownload(Components.interfaces.nsIXPInstallManagerUI.DOWNLOAD_TYPE_INSTALL, 
  552.                                                   uri, targetUrl, displayName, iconURL, mimeInfo, 0, null);
  553.       
  554.       // Advance the enumerator
  555.       var certName = aParams.GetString(i++);
  556.     }
  557.  
  558.     var observerService = Components.classes[kObserverServiceProgID]
  559.                                     .getService(Components.interfaces.nsIObserverService);
  560.     observerService.notifyObservers(xpinstallManager.xpiProgress, "xpinstall-progress", "open");  
  561.   }
  562. }
  563.  
  564. ///////////////////////////////////////////////////////////////////////////////
  565. // View Context Menus
  566. var gContextMenus = [ 
  567.   ["menuitem_pause", "menuitem_cancel", "menuseparator_properties", "menuitem_properties"],
  568.   ["menuitem_open", "menuitem_show", "menuitem_remove", "menuseparator_properties", "menuitem_properties"],
  569.   ["menuitem_retry", "menuitem_remove", "menuseparator_properties", "menuitem_properties"],
  570.   ["menuitem_retry", "menuitem_remove", "menuseparator_properties", "menuitem_properties"],
  571.   ["menuitem_resume", "menuitem_cancel", "menuseparator_properties", "menuitem_properties"]
  572. ];
  573.  
  574. function buildContextMenu(aEvent)
  575. {
  576.   if (aEvent.target.id != "downloadContextMenu")
  577.     return;
  578.     
  579.   var popup = document.getElementById("downloadContextMenu");
  580.   while (popup.hasChildNodes())
  581.     popup.removeChild(popup.firstChild);
  582.   
  583.   if (gDownloadsView.selected) {
  584.     var idx = parseInt(gDownloadsView.selected.getAttribute("state"));
  585.     if (idx < 0)
  586.       idx = 0;
  587.     
  588.     var menus = gContextMenus[idx];
  589.     for (var i = 0; i < menus.length; ++i)
  590.       popup.appendChild(document.getElementById(menus[i]).cloneNode(true));
  591.     
  592.     return true;
  593.   }
  594.   
  595.   return false;
  596. }
  597.  
  598. ///////////////////////////////////////////////////////////////////////////////
  599. // Drag and Drop
  600.  
  601. var gDownloadDNDObserver =
  602. {
  603.   onDragOver: function (aEvent, aFlavour, aDragSession)
  604.   {
  605.     aDragSession.canDrop = true;
  606.   },
  607.   
  608.   onDrop: function(aEvent, aXferData, aDragSession)
  609.   {
  610.     var split = aXferData.data.split("\n");
  611.     var url = split[0];
  612.     if (url != aXferData.data) {  //do nothing, not a valid URL
  613.       var name = split[1];
  614.       saveURL(url, name, null, true, true);
  615.     }
  616.   },
  617.   _flavourSet: null,  
  618.   getSupportedFlavours: function ()
  619.   {
  620.     if (!this._flavourSet) {
  621.       this._flavourSet = new FlavourSet();
  622.       this._flavourSet.appendFlavour("text/x-moz-url");
  623.       this._flavourSet.appendFlavour("text/unicode");
  624.     }
  625.     return this._flavourSet;
  626.   }
  627. }
  628.  
  629. ///////////////////////////////////////////////////////////////////////////////
  630. // Command Updating and Command Handlers
  631.  
  632. var gDownloadViewController = {
  633.   supportsCommand: function (aCommand)
  634.   {
  635.     return aCommand == "cmd_cleanUp";
  636.   },
  637.   
  638.   isCommandEnabled: function (aCommand)
  639.   {
  640.     if (aCommand == "cmd_cleanUp") 
  641.       return gDownloadManager.canCleanUp;
  642.     return false;
  643.   },
  644.   
  645.   doCommand: function (aCommand)
  646.   {
  647.     if (aCommand == "cmd_cleanUp" && this.isCommandEnabled(aCommand)) {
  648.       gDownloadManager.cleanUp();
  649.       this.onCommandUpdate();
  650.     }
  651.   },  
  652.   
  653.   onCommandUpdate: function ()
  654.   {
  655.     var command = "cmd_cleanUp";
  656.     var enabled = this.isCommandEnabled(command);
  657.     goSetCommandEnabled(command, enabled);
  658.   }
  659. };
  660.  
  661. function onDownloadShowOptions()
  662. {
  663.   var windowManager = Components.classes['@mozilla.org/appshell/window-mediator;1'].getService();
  664.   var windowManagerInterface = windowManager.QueryInterface(Components.interfaces.nsIWindowMediator);
  665.   var topWindow = windowManagerInterface.getMostRecentWindow("Browser:Options");
  666.   if (topWindow) {
  667.     topWindow.focus();
  668.     topWindow.switchPage("catDownloadsButton");
  669.   }
  670.   else
  671.     openDialog("chrome://browser/content/pref/pref.xul", "PrefWindow",
  672.               "chrome,titlebar,resizable,modal", "catDownloadsButton");
  673. }
  674.  
  675. function onDownloadShowInfo()
  676. {
  677.   if (gDownloadsView.selected)
  678.     fireEventForElement(gDownloadsView.selected, "properties");
  679. }
  680.  
  681. function initAutoDownloadDisplay()
  682. {
  683.   var pref = Components.classes["@mozilla.org/preferences-service;1"]
  684.                        .getService(Components.interfaces.nsIPrefBranch);
  685.  
  686.   var autodownload = pref.getBoolPref("browser.download.useDownloadDir");  
  687.   if (autodownload) {
  688.     var autodownloadInfo = document.getElementById("autodownloadInfo");
  689.     autodownloadInfo.hidden = false;
  690.     var autodownloadSpring = document.getElementById("autodownloadSpring");
  691.     autodownloadSpring.hidden = true; 
  692.  
  693.     function getSpecialFolderKey(aFolderType) 
  694.     {
  695.       return aFolderType == "Desktop" ? "DeskV" : "Pers";
  696.       return "Home";
  697.     }
  698.     
  699.     function getDownloadsFolder(aFolder)
  700.     {
  701.       var fileLocator = Components.classes["@mozilla.org/file/directory_service;1"]
  702.                                   .getService(Components.interfaces.nsIProperties);
  703.       var dir = fileLocator.get(getSpecialFolderKey(aFolder), Components.interfaces.nsILocalFile);
  704.       
  705.       var bundle = Components.classes["@mozilla.org/intl/stringbundle;1"]
  706.                               .getService(Components.interfaces.nsIStringBundleService);
  707.       bundle = bundle.createBundle("chrome://mozapps/locale/downloads/unknownContentType.properties");
  708.  
  709.       var description = bundle.GetStringFromName("myDownloads");
  710.       if (aFolder != "Desktop")
  711.         dir.append(description);
  712.         
  713.       return dir;
  714.     }
  715.  
  716.     var displayName = null;
  717.     switch (pref.getIntPref("browser.download.folderList")) {
  718.     case 0:
  719.       folder = getDownloadsFolder("Desktop");
  720.       var strings = document.getElementById("downloadStrings");
  721.       displayName = strings.getString("displayNameDesktop");
  722.       break;
  723.     case 1:
  724.       folder = getDownloadsFolder("Downloads");
  725.       break;
  726.     case 2: 
  727.       folder = pref.getComplexValue("browser.download.dir", Components.interfaces.nsILocalFile);
  728.       break;
  729.     }
  730.  
  731.     if (folder) {    
  732.       var ioServ = Components.classes["@mozilla.org/network/io-service;1"]
  733.                               .getService(Components.interfaces.nsIIOService);
  734.       var fph = ioServ.getProtocolHandler("file").QueryInterface(Components.interfaces.nsIFileProtocolHandler);
  735.       var mozIconURI = "moz-icon://" +  fph.getURLSpecFromFile(folder) + "?size=16";
  736.       var folderIcon = document.getElementById("saveToFolder")
  737.       folderIcon.image = mozIconURI;
  738.       
  739.       var folderName = document.getElementById("saveToFolder");
  740.       folderName.label = displayName || folder.leafName;
  741.       folderName.setAttribute("path", folder.path);
  742.     }
  743.   }
  744.   else {
  745.     var autodownloadInfo = document.getElementById("autodownloadInfo");
  746.     autodownloadInfo.hidden = true;
  747.     var autodownloadSpring = document.getElementById("autodownloadSpring");
  748.     autodownloadSpring.hidden = false; 
  749.   }
  750. }
  751.  
  752. var gDownloadPrefObserver = {
  753.   observe: function (aSubject, aTopic, aData)
  754.   {
  755.     if (aTopic == "nsPref:changed") {
  756.       switch(aData) {
  757.       case "browser.download.folderList":
  758.       case "browser.download.useDownloadDir":
  759.       case "browser.download.dir":
  760.         initAutoDownloadDisplay();
  761.       }
  762.     }
  763.   }
  764. };
  765.  
  766. function onDownloadShowFolder()
  767. {
  768.   var folderName = document.getElementById("saveToFolder");
  769.   var dir = getLocalFileFromNativePathOrUrl(folderName.getAttribute("path"));
  770.   if (!dir.exists())
  771.    dir.create(Components.interfaces.nsIFile.DIRECTORY_TYPE, 0755);
  772.  
  773.   try {
  774.     dir.reveal();
  775.   } catch (ex) {
  776.     // if nsILocalFile::Reveal failed (eg it currently just returns an
  777.     // error on unix), just open the folder in a browser window
  778.     openExternal(dir.path);
  779.   }
  780. }
  781.  
  782. function openExternal(aPath)
  783. {
  784.   var uri = Components.classes["@mozilla.org/network/standard-url;1"]
  785.     .createInstance(Components.interfaces.nsIURI);
  786.   uri.spec = "file:///" + aPath;
  787.  
  788.   var protocolSvc = Components.classes
  789.     ["@mozilla.org/uriloader/external-protocol-service;1"]
  790.     .getService(Components.interfaces.nsIExternalProtocolService);
  791.   protocolSvc.loadUrl(uri);
  792.  
  793.   return;
  794. }
  795.  
  796. // we should be using real URLs all the time, but until 
  797. // bug 239948 is fully fixed, this will do...
  798. function getLocalFileFromNativePathOrUrl(aPathOrUrl)
  799. {
  800.   if (aPathOrUrl.substring(0,7) == "file://") {
  801.  
  802.     // if this is a URL, get the file from that
  803.     ioSvc = Components.classes["@mozilla.org/network/io-service;1"]
  804.       .getService(Components.interfaces.nsIIOService);
  805.  
  806.     // XXX it's possible that using a null char-set here is bad
  807.     const fileUrl = ioSvc.newURI(aPathOrUrl, null, null).
  808.       QueryInterface(Components.interfaces.nsIFileURL);
  809.     return fileUrl.file.clone().
  810.       QueryInterface(Components.interfaces.nsILocalFile);
  811.  
  812.   } else {
  813.  
  814.     // if it's a pathname, create the nsILocalFile directly
  815.     f = Components.classes["@mozilla.org/file/local;1"].
  816.       createInstance(Components.interfaces.nsILocalFile);
  817.     f.initWithPath(aPathOrUrl);
  818.  
  819.     return f;
  820.   }
  821. }
  822.