Back to index

lightning-sunbird  0.9+nobinonly
UDownload.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 2002
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *  Conrad Carlen <ccarlen@netscape.com>
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either the GNU General Public License Version 2 or later (the "GPL"), or
00027  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 #include "UDownload.h"
00040 
00041 #include "nsIExternalHelperAppService.h"
00042 #include "nsILocalFIleMac.h"
00043 #include "nsDirectoryServiceDefs.h"
00044 #include "nsDirectoryServiceUtils.h"
00045 #include "nsIRequest.h"
00046 #include "netCore.h"
00047 
00048 #include "UDownloadDisplay.h"
00049 #include "UMacUnicode.h"
00050 
00051 #include "UNavServicesDialogs.h"
00052 
00053 
00054 //*****************************************************************************
00055 // CDownload
00056 //*****************************************************************************
00057 #pragma mark [CDownload]
00058 
00059 ADownloadProgressView *CDownload::sProgressView;
00060 
00061 CDownload::CDownload() :
00062     mGotFirstStateChange(false), mIsNetworkTransfer(false),
00063     mUserCanceled(false),
00064     mStatus(NS_OK)
00065 {
00066 }
00067 
00068 CDownload::~CDownload()
00069 {
00070 }
00071 
00072 NS_IMPL_ISUPPORTS4(CDownload, nsIDownload, nsITransfer,
00073                    nsIWebProgressListener, nsIWebProgressListener2)
00074 
00075 #pragma mark -
00076 #pragma mark [CDownload::nsIDownload]
00077 
00078 /* void init (in nsIURI aSource, in nsILocalFile aTarget, in wstring aDisplayName, in nsIMIMEInfo aMIMEInfo, in long long startTime, in nsILocalFile aTempFile, in nsICancelable aCancelable); */
00079 NS_IMETHODIMP CDownload::Init(nsIURI *aSource, nsILocalFile *aTarget,
00080     const PRUnichar *aDisplayName, nsIMIMEInfo *aMIMEInfo, PRInt64 startTime,
00081     nsILocalFile* aTempFile, nsICancelable* aCancelable)
00082 {
00083     try {
00084         mSource = aSource;
00085         mDestination = aTarget;
00086         mStartTime = startTime;
00087         mPercentComplete = 0;
00088         // We have to break this circular ref when the download is done
00089         mCancelable = aCancelable;
00090         EnsureProgressView();
00091         sProgressView->AddDownloadItem(this);
00092     }
00093     catch (...) {
00094         return NS_ERROR_FAILURE;
00095     }
00096     return NS_OK;
00097 }
00098 
00099 /* readonly attribute nsIURI source; */
00100 NS_IMETHODIMP CDownload::GetSource(nsIURI * *aSource)
00101 {
00102     NS_ENSURE_ARG_POINTER(aSource);
00103     NS_IF_ADDREF(*aSource = mSource);
00104     return NS_OK;
00105 }
00106 
00107 /* readonly attribute nsILocalFile target; */
00108 NS_IMETHODIMP CDownload::GetTarget(nsILocalFile * *aTarget)
00109 {
00110     NS_ENSURE_ARG_POINTER(aTarget);
00111     NS_IF_ADDREF(*aTarget = mDestination);
00112     return NS_OK;
00113 }
00114 
00115 /* readonly attribute nsICancelable cancelable; */
00116 NS_IMETHODIMP CDownload::GetCancelable(nsIWebBrowserCancelable * *aCancelable)
00117 {
00118     NS_ENSURE_ARG_POINTER(aCancelable);
00119     NS_IF_ADDREF(*aCancelable = mCancelable);
00120     return NS_OK;
00121 }
00122 
00123 /* readonly attribute PRInt32 percentComplete; */
00124 NS_IMETHODIMP CDownload::GetPercentComplete(PRInt32 *aPercentComplete)
00125 {
00126     NS_ENSURE_ARG_POINTER(aPercentComplete);
00127     *aPercentComplete = mPercentComplete;
00128     return NS_OK;
00129 }
00130 
00131 /* attribute wstring displayName; */
00132 NS_IMETHODIMP CDownload::GetDisplayName(PRUnichar * *aDisplayName)
00133 {
00134     return NS_ERROR_NOT_IMPLEMENTED;
00135 }
00136 
00137 /* readonly attribute long long startTime; */
00138 NS_IMETHODIMP CDownload::GetStartTime(PRInt64 *aStartTime)
00139 {
00140     NS_ENSURE_ARG_POINTER(aStartTime);
00141     *aStartTime = mStartTime;
00142     return NS_OK;
00143 }
00144 
00145 /* readonly attribute nsIMIMEInfo MIMEInfo; */
00146 NS_IMETHODIMP CDownload::GetMIMEInfo(nsIMIMEInfo * *aMIMEInfo)
00147 {
00148     return NS_ERROR_NOT_IMPLEMENTED;
00149 }
00150 
00151 #pragma mark -
00152 #pragma mark [CDownload::nsIWebProgressListener]
00153 
00154 /* void onStateChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in unsigned long aStateFlags, in nsresult aStatus); */
00155 NS_IMETHODIMP CDownload::OnStateChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, PRUint32 aStateFlags, nsresult aStatus)
00156 {
00157     // For a file download via the external helper app service, we will never get a start
00158     // notification. The helper app service has gotten that notification before it created us.
00159     if (!mGotFirstStateChange) {
00160         mIsNetworkTransfer = ((aStateFlags & STATE_IS_NETWORK) != 0);
00161         mGotFirstStateChange = PR_TRUE;
00162         BroadcastMessage(msg_OnDLStart, this);
00163     }
00164 
00165     if (NS_FAILED(aStatus) && NS_SUCCEEDED(mStatus))
00166         mStatus = aStatus;
00167   
00168     // We will get this even in the event of a cancel,
00169     if ((aStateFlags & STATE_STOP) && (!mIsNetworkTransfer || (aStateFlags & STATE_IS_NETWORK))) {
00170         mCancelable = nsnull;
00171         BroadcastMessage(msg_OnDLComplete, this);
00172     }
00173         
00174     return NS_OK; 
00175 }
00176 
00177 /* void onProgressChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in long aCurSelfProgress, in long aMaxSelfProgress, in long aCurTotalProgress, in long aMaxTotalProgress); */
00178 NS_IMETHODIMP CDownload::OnProgressChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, PRInt32 aCurSelfProgress, PRInt32 aMaxSelfProgress, PRInt32 aCurTotalProgress, PRInt32 aMaxTotalProgress)
00179 {
00180     if (mUserCanceled) {
00181         mCancelable->Cancel(NS_BINDING_ABORTED);
00182         mUserCanceled = false;
00183     }
00184     if (aMaxTotalProgress == -1)
00185         mPercentComplete = -1;
00186     else
00187         mPercentComplete = (PRInt32)(((float)aCurTotalProgress / (float)aMaxTotalProgress) * 100.0 + 0.5);
00188     
00189     MsgOnDLProgressChangeInfo info(this, aCurTotalProgress, aMaxTotalProgress);
00190     BroadcastMessage(msg_OnDLProgressChange, &info);
00191 
00192     return NS_OK;
00193 }
00194 
00195 /* void onProgressChange64 (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in long long aCurSelfProgress, in long long aMaxSelfProgress, in long long aCurTotalProgress, in long long aMaxTotalProgress); */
00196 NS_IMETHODIMP CDownload::OnProgressChange64(nsIWebProgress *aWebProgress, nsIRequest *aRequest, PRInt64 aCurSelfProgress, PRInt64 aMaxSelfProgress, PRInt64 aCurTotalProgress, PRInt64 aMaxTotalProgress)
00197 {
00198   // XXX truncates 64-bit to 32-bit
00199   return OnProgressChange(aProgress, aRequest,
00200                           PRInt32(curSelfProgress), PRInt32(maxSelfProgress),
00201                           PRInt32(curTotalProgress), PRInt32(maxTotalProgress));
00202 }
00203 
00204 
00205 /* void onLocationChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in nsIURI location); */
00206 NS_IMETHODIMP CDownload::OnLocationChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, nsIURI *location)
00207 {
00208     return NS_OK;
00209 }
00210 
00211 /* void onStatusChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in nsresult aStatus, in wstring aMessage); */
00212 NS_IMETHODIMP CDownload::OnStatusChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, nsresult aStatus, const PRUnichar *aMessage)
00213 {
00214     return NS_OK;
00215 }
00216 
00217 /* void onSecurityChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in unsigned long state); */
00218 NS_IMETHODIMP CDownload::OnSecurityChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, PRUint32 state)
00219 {
00220     return NS_OK;
00221 }
00222 
00223 #pragma mark -
00224 #pragma mark [CDownload Internal Methods]
00225 
00226 void CDownload::Cancel()
00227 {
00228     mUserCanceled = true;
00229     // nsWebBrowserPersist does the right thing: After canceling, next time through
00230     // OnStateChange(), aStatus != NS_OK. This isn't the case with nsExternalHelperAppService.
00231     mStatus = NS_ERROR_ABORT;
00232 }
00233 
00234 void CDownload::CreateProgressView()
00235 {
00236     sProgressView = new CMultiDownloadProgress;
00237     ThrowIfNil_(sProgressView);
00238 }
00239 
00240 
00241 //*****************************************************************************
00242 // CHelperAppLauncherDialog
00243 //*****************************************************************************   
00244 #pragma mark -
00245 #pragma mark [CHelperAppLauncherDialog]
00246 
00247 CHelperAppLauncherDialog::CHelperAppLauncherDialog()
00248 {
00249 }
00250 
00251 CHelperAppLauncherDialog::~CHelperAppLauncherDialog()
00252 {
00253 }
00254 
00255 NS_IMPL_ISUPPORTS1(CHelperAppLauncherDialog, nsIHelperAppLauncherDialog)
00256 
00257 /* void show (in nsIHelperAppLauncher aLauncher, in nsISupports aContext, in unsigned long aReason); */
00258 NS_IMETHODIMP CHelperAppLauncherDialog::Show(nsIHelperAppLauncher *aLauncher, nsISupports *aContext, PRUint32 aReason)
00259 {
00260     return aLauncher->SaveToDisk(nsnull, PR_FALSE);
00261 }
00262 
00263 /* nsILocalFile promptForSaveToFile (in nsIHelperAppLauncher aLauncher, in nsISupports aWindowContext, in wstring aDefaultFile, in wstring aSuggestedFileExtension); */
00264 NS_IMETHODIMP CHelperAppLauncherDialog::PromptForSaveToFile(nsIHelperAppLauncher* aLauncher, 
00265                                                             nsISupports *aWindowContext, 
00266                                                             const PRUnichar *aDefaultFile, 
00267                                                             const PRUnichar *aSuggestedFileExtension, 
00268                                                             nsILocalFile **_retval)
00269 {
00270     NS_ENSURE_ARG_POINTER(_retval);
00271     *_retval = nsnull;
00272  
00273     static bool sFirstTime = true;   
00274        UNavServicesDialogs::LFileDesignator      designator;
00275 
00276     if (sFirstTime) {
00277         // Get the default download folder and point Nav Sevices to it.
00278         nsCOMPtr<nsIFile> defaultDownloadDir;
00279         NS_GetSpecialDirectory(NS_MAC_DEFAULT_DOWNLOAD_DIR, getter_AddRefs(defaultDownloadDir));
00280         if (defaultDownloadDir) {
00281             nsCOMPtr<nsILocalFileMac> macDir(do_QueryInterface(defaultDownloadDir));
00282             FSSpec defaultDownloadSpec;
00283             if (NS_SUCCEEDED(macDir->GetFSSpec(&defaultDownloadSpec)))
00284                 designator.SetDefaultLocation(defaultDownloadSpec, true);
00285         }
00286         sFirstTime = false;
00287     }
00288        
00289        Str255  defaultName;
00290        CPlatformUCSConversion::GetInstance()->UCSToPlatform(nsDependentString(aDefaultFile), defaultName);
00291     bool result = designator.AskDesignateFile(defaultName);
00292     
00293     // After the dialog is dismissed, process all activation an update events right away.
00294     // The save dialog code calls UDesktop::Activate after dismissing the dialog. All that
00295     // does is activate the now frontmost LWindow which was behind the dialog. It does not
00296     // remove the activate event from the queue. If that event is not processed and removed
00297     // before we show the progress window, bad things happen. Specifically, the progress
00298     // dialog will show in front and then, shortly thereafter, the window which was behind this save
00299     // dialog will be moved to the front.
00300     
00301     if (LEventDispatcher::GetCurrentEventDispatcher()) { // Can this ever be NULL?
00302         EventRecord theEvent;
00303         while (::WaitNextEvent(updateMask | activMask, &theEvent, 0, nil))
00304             LEventDispatcher::GetCurrentEventDispatcher()->DispatchEvent(theEvent);
00305     }
00306         
00307     if (result) {
00308         FSSpec destSpec;
00309         designator.GetFileSpec(destSpec);
00310         nsCOMPtr<nsILocalFileMac> destFile;
00311         NS_NewLocalFileWithFSSpec(&destSpec, PR_TRUE, getter_AddRefs(destFile));
00312         if (!destFile)
00313             return NS_ERROR_FAILURE;
00314         *_retval = destFile;
00315         NS_ADDREF(*_retval);
00316         return NS_OK;
00317     }
00318     else
00319         return NS_ERROR_ABORT;
00320 }
00321