/* -*- Mode: C++; 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 * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Conrad Carlen * * 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 ***** */ #include "EphyDownload.h" #include "nsIExternalHelperAppService.h" //#include "nsILocalFIleMac.h" #include "nsDirectoryServiceDefs.h" #include "nsDirectoryServiceUtils.h" #include "nsIRequest.h" #include "netCore.h" #include "nsIObserver.h" //#include "UDownloadDisplay.h" //#include "UMacUnicode.h" //#include "UNavServicesDialogs.h" //***************************************************************************** // EphyDownload //***************************************************************************** #pragma mark [EphyDownload] //ADownloadProgressView *EphyDownload::sProgressView; EphyDownload::EphyDownload() : mGotFirstStateChange(false), mIsNetworkTransfer(false), mUserCanceled(false), mStatus(NS_OK) { } EphyDownload::~EphyDownload() { } NS_IMPL_ISUPPORTS2(EphyDownload, nsIDownload, nsIWebProgressListener) #pragma mark - #pragma mark [EphyDownload::nsIDownload] /* void init (in nsIURI aSource, in nsILocalFile aTarget, in wstring aDisplayName, in nsIMIMEInfo aMIMEInfo, in long long startTime, in nsIWebBrowserPersist aPersist); */ NS_IMETHODIMP EphyDownload::Init(nsIURI *aSource, nsILocalFile *aTarget, const PRUnichar *aDisplayName, nsIMIMEInfo *aMIMEInfo, PRInt64 startTime, nsIWebBrowserPersist *aPersist) { try { mSource = aSource; mDestination = aTarget; mStartTime = startTime; mPercentComplete = 0; mInterval = 400000; // ms mPriorKRate = 0; mRateChanges = 0; mRateChangeLimit = 2; mIsPaused = PR_FALSE; mStartTime = PR_Now(); mLastUpdate = mStartTime; if (aPersist) { mWebPersist = aPersist; // We have to break this circular ref when the download is done - // until nsIWebBrowserPersist supports weak refs - bug #163889. aPersist->SetProgressListener(this); } // UI Rumba mDownloaderView = EPHY_DOWNLOADER_VIEW (ephy_embed_shell_get_downloader_view (embed_shell)); downloader_view_add_download (mDownloaderView, "A", "B", "C", (gpointer)this); // EnsureProgressView(); // sProgressView->AddDownloadItem(this); } catch (...) { return NS_ERROR_FAILURE; } return NS_OK; } /* readonly attribute nsIURI source; */ NS_IMETHODIMP EphyDownload::GetSource(nsIURI * *aSource) { NS_ENSURE_ARG_POINTER(aSource); NS_IF_ADDREF(*aSource = mSource); return NS_OK; } /* readonly attribute nsILocalFile target; */ NS_IMETHODIMP EphyDownload::GetTarget(nsILocalFile * *aTarget) { NS_ENSURE_ARG_POINTER(aTarget); NS_IF_ADDREF(*aTarget = mDestination); return NS_OK; } /* readonly attribute nsIWebBrowserPersist persist; */ NS_IMETHODIMP EphyDownload::GetPersist(nsIWebBrowserPersist * *aPersist) { NS_ENSURE_ARG_POINTER(aPersist); NS_IF_ADDREF(*aPersist = mWebPersist); return NS_OK; } /* readonly attribute PRInt32 percentComplete; */ NS_IMETHODIMP EphyDownload::GetPercentComplete(PRInt32 *aPercentComplete) { NS_ENSURE_ARG_POINTER(aPercentComplete); *aPercentComplete = mPercentComplete; return NS_OK; } /* attribute wstring displayName; */ NS_IMETHODIMP EphyDownload::GetDisplayName(PRUnichar * *aDisplayName) { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP EphyDownload::SetDisplayName(const PRUnichar * aDisplayName) { return NS_ERROR_NOT_IMPLEMENTED; } /* readonly attribute long long startTime; */ NS_IMETHODIMP EphyDownload::GetStartTime(PRInt64 *aStartTime) { NS_ENSURE_ARG_POINTER(aStartTime); *aStartTime = mStartTime; return NS_OK; } /* readonly attribute nsIMIMEInfo MIMEInfo; */ NS_IMETHODIMP EphyDownload::GetMIMEInfo(nsIMIMEInfo * *aMIMEInfo) { return NS_ERROR_NOT_IMPLEMENTED; } /* attribute nsIWebProgressListener listener; */ NS_IMETHODIMP EphyDownload::GetListener(nsIWebProgressListener * *aListener) { NS_ENSURE_ARG_POINTER(aListener); NS_IF_ADDREF(*aListener = (nsIWebProgressListener *)this); return NS_OK; } NS_IMETHODIMP EphyDownload::SetListener(nsIWebProgressListener * aListener) { return NS_ERROR_NOT_IMPLEMENTED; } /* attribute nsIObserver observer; */ NS_IMETHODIMP EphyDownload::GetObserver(nsIObserver * *aObserver) { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP EphyDownload::SetObserver(nsIObserver * aObserver) { if (aObserver) aObserver->QueryInterface(NS_GET_IID(nsIHelperAppLauncher), getter_AddRefs(mHelperAppLauncher)); return NS_OK; } #pragma mark - #pragma mark [EphyDownload::nsIWebProgressListener] /* void onStateChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in unsigned long aStateFlags, in nsresult aStatus); */ NS_IMETHODIMP EphyDownload::OnStateChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, PRUint32 aStateFlags, nsresult aStatus) { // For a file download via the external helper app service, we will never get a start // notification. The helper app service has gotten that notification before it created us. if (!mGotFirstStateChange) { mIsNetworkTransfer = ((aStateFlags & STATE_IS_NETWORK) != 0); mGotFirstStateChange = PR_TRUE; //BroadcastMessage(msg_OnDLStart, this); } if (NS_FAILED(aStatus) && NS_SUCCEEDED(mStatus)) mStatus = aStatus; // We will get this even in the event of a cancel, if ((aStateFlags & STATE_STOP) && (!mIsNetworkTransfer || (aStateFlags & STATE_IS_NETWORK))) { if (mWebPersist) { mWebPersist->SetProgressListener(nsnull); mWebPersist = nsnull; } mHelperAppLauncher = nsnull; //BroadcastMessage(msg_OnDLComplete, this); } return NS_OK; } /* void onProgressChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in long aCurSelfProgress, in long aMaxSelfProgress, in long aCurTotalProgress, in long aMaxTotalProgress); */ NS_IMETHODIMP EphyDownload::OnProgressChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, PRInt32 aCurSelfProgress, PRInt32 aMaxSelfProgress, PRInt32 aCurTotalProgress, PRInt32 aMaxTotalProgress) { if (mUserCanceled) { if (mHelperAppLauncher) mHelperAppLauncher->Cancel(); else if (aRequest) aRequest->Cancel(NS_BINDING_ABORTED); mUserCanceled = false; } if (aMaxTotalProgress == -1) mPercentComplete = -1; else mPercentComplete = (PRInt32)(((float)aCurTotalProgress / (float)aMaxTotalProgress) * 100.0 + 0.5); //MsgOnDLProgressChangeInfo info(this, aCurTotalProgress, aMaxTotalProgress); // From ProgressListener PRInt64 now = PR_Now(); mElapsed = now - mStartTime; if ((now - mLastUpdate < mInterval) && (aMaxTotalProgress != -1) && (aCurTotalProgress < aMaxTotalProgress)) { return NS_OK; } mLastUpdate = now; gfloat progress = -1; if (aMaxTotalProgress > 0) { progress = (gfloat)aCurTotalProgress / (gfloat)aMaxTotalProgress; } /* compute download rate */ gfloat speed = -1; PRInt64 currentRate; if (mElapsed) { currentRate = ((PRInt64)(aCurTotalProgress)) * 1000000 / mElapsed; } else { currentRate = 0; } if (!mIsPaused && currentRate) { PRFloat64 currentKRate = ((PRFloat64)currentRate)/1024; if (currentKRate != mPriorKRate) { if (mRateChanges++ == mRateChangeLimit) { mPriorKRate = currentKRate; mRateChanges = 0; } else { currentKRate = mPriorKRate; } } else { mRateChanges = 0; } speed = currentKRate; } /* compute time remaining */ gint remaining = -1; if (currentRate && (aMaxTotalProgress > 0)) { remaining = (gint)((aMaxTotalProgress - aCurTotalProgress) /currentRate + 0.5); } //BroadcastMessage(msg_OnDLProgressChange, &info); // UI Rumba downloader_view_set_download_progress (mDownloaderView, mElapsed / 1000000, remaining, speed, aMaxTotalProgress / 1024.0 + 0.5, aCurTotalProgress / 1024.0 + 0.5, progress, (gpointer)this); return NS_OK; } /* void onLocationChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in nsIURI location); */ NS_IMETHODIMP EphyDownload::OnLocationChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, nsIURI *location) { return NS_OK; } /* void onStatusChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in nsresult aStatus, in wstring aMessage); */ NS_IMETHODIMP EphyDownload::OnStatusChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, nsresult aStatus, const PRUnichar *aMessage) { return NS_OK; } /* void onSecurityChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in unsigned long state); */ NS_IMETHODIMP EphyDownload::OnSecurityChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, PRUint32 state) { return NS_OK; } #pragma mark - #pragma mark [EphyDownload Internal Methods] void EphyDownload::Cancel() { mUserCanceled = true; // nsWebBrowserPersist does the right thing: After canceling, next time through // OnStateChange(), aStatus != NS_OK. This isn't the case with nsExternalHelperAppService. if (!mWebPersist) mStatus = NS_ERROR_ABORT; } void EphyDownload::Pause() { } void EphyDownload::Resume() { } /*void EphyDownload::CreateProgressView() { sProgressView = new CMultiDownloadProgress; ThrowIfNil_(sProgressView); }*/ //***************************************************************************** // CHelperAppLauncherDialog //***************************************************************************** /*#pragma mark - #pragma mark [CHelperAppLauncherDialog] CHelperAppLauncherDialog::CHelperAppLauncherDialog() { } CHelperAppLauncherDialog::~CHelperAppLauncherDialog() { } NS_IMPL_ISUPPORTS1(CHelperAppLauncherDialog, nsIHelperAppLauncherDialog)*/ /* void show (in nsIHelperAppLauncher aLauncher, in nsISupports aContext, in boolean aForced); */ /*NS_IMETHODIMP CHelperAppLauncherDialog::Show(nsIHelperAppLauncher *aLauncher, nsISupports *aContext, PRBool aForced) { return aLauncher->SaveToDisk(nsnull, PR_FALSE); }*/ /* nsILocalFile promptForSaveToFile (in nsIHelperAppLauncher aLauncher, in nsISupports aWindowContext, in wstring aDefaultFile, in wstring aSuggestedFileExtension); */ /*NS_IMETHODIMP CHelperAppLauncherDialog::PromptForSaveToFile(nsIHelperAppLauncher* aLauncher, nsISupports *aWindowContext, const PRUnichar *aDefaultFile, const PRUnichar *aSuggestedFileExtension, nsILocalFile **_retval) { NS_ENSURE_ARG_POINTER(_retval); *_retval = nsnull; static bool sFirstTime = true; UNavServicesDialogs::LFileDesignator designator; if (sFirstTime) { // Get the default download folder and point Nav Sevices to it. nsCOMPtr defaultDownloadDir; NS_GetSpecialDirectory(NS_MAC_DEFAULT_DOWNLOAD_DIR, getter_AddRefs(defaultDownloadDir)); if (defaultDownloadDir) { nsCOMPtr macDir(do_QueryInterface(defaultDownloadDir)); FSSpec defaultDownloadSpec; if (NS_SUCCEEDED(macDir->GetFSSpec(&defaultDownloadSpec))) designator.SetDefaultLocation(defaultDownloadSpec, true); } sFirstTime = false; } Str255 defaultName; CPlatformUCSConversion::GetInstance()->UCSToPlatform(nsDependentString(aDefaultFile), defaultName); bool result = designator.AskDesignateFile(defaultName); // After the dialog is dismissed, process all activation an update events right away. // The save dialog code calls UDesktop::Activate after dismissing the dialog. All that // does is activate the now frontmost LWindow which was behind the dialog. It does not // remove the activate event from the queue. If that event is not processed and removed // before we show the progress window, bad things happen. Specifically, the progress // dialog will show in front and then, shortly thereafter, the window which was behind this save // dialog will be moved to the front. if (LEventDispatcher::GetCurrentEventDispatcher()) { // Can this ever be NULL? EventRecord theEvent; while (::WaitNextEvent(updateMask | activMask, &theEvent, 0, nil)) LEventDispatcher::GetCurrentEventDispatcher()->DispatchEvent(theEvent); } if (result) { FSSpec destSpec; designator.GetFileSpec(destSpec); nsCOMPtr destFile; NS_NewLocalFileWithFSSpec(&destSpec, PR_TRUE, getter_AddRefs(destFile)); if (!destFile) return NS_ERROR_FAILURE; *_retval = destFile; NS_ADDREF(*_retval); return NS_OK; } else return NS_ERROR_ABORT; }*/