RetroZilla/embedding/browser/powerplant/source/UDownload.cpp
2015-10-20 23:03:22 -04:00

322 lines
12 KiB
C++

/* -*- 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 <ccarlen@netscape.com>
*
* 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 "UDownload.h"
#include "nsIExternalHelperAppService.h"
#include "nsILocalFIleMac.h"
#include "nsDirectoryServiceDefs.h"
#include "nsDirectoryServiceUtils.h"
#include "nsIRequest.h"
#include "netCore.h"
#include "UDownloadDisplay.h"
#include "UMacUnicode.h"
#include "UNavServicesDialogs.h"
//*****************************************************************************
// CDownload
//*****************************************************************************
#pragma mark [CDownload]
ADownloadProgressView *CDownload::sProgressView;
CDownload::CDownload() :
mGotFirstStateChange(false), mIsNetworkTransfer(false),
mUserCanceled(false),
mStatus(NS_OK)
{
}
CDownload::~CDownload()
{
}
NS_IMPL_ISUPPORTS4(CDownload, nsIDownload, nsITransfer,
nsIWebProgressListener, nsIWebProgressListener2)
#pragma mark -
#pragma mark [CDownload::nsIDownload]
/* void init (in nsIURI aSource, in nsILocalFile aTarget, in wstring aDisplayName, in nsIMIMEInfo aMIMEInfo, in long long startTime, in nsILocalFile aTempFile, in nsICancelable aCancelable); */
NS_IMETHODIMP CDownload::Init(nsIURI *aSource, nsILocalFile *aTarget,
const PRUnichar *aDisplayName, nsIMIMEInfo *aMIMEInfo, PRInt64 startTime,
nsILocalFile* aTempFile, nsICancelable* aCancelable)
{
try {
mSource = aSource;
mDestination = aTarget;
mStartTime = startTime;
mPercentComplete = 0;
// We have to break this circular ref when the download is done
mCancelable = aCancelable;
EnsureProgressView();
sProgressView->AddDownloadItem(this);
}
catch (...) {
return NS_ERROR_FAILURE;
}
return NS_OK;
}
/* readonly attribute nsIURI source; */
NS_IMETHODIMP CDownload::GetSource(nsIURI * *aSource)
{
NS_ENSURE_ARG_POINTER(aSource);
NS_IF_ADDREF(*aSource = mSource);
return NS_OK;
}
/* readonly attribute nsILocalFile target; */
NS_IMETHODIMP CDownload::GetTarget(nsILocalFile * *aTarget)
{
NS_ENSURE_ARG_POINTER(aTarget);
NS_IF_ADDREF(*aTarget = mDestination);
return NS_OK;
}
/* readonly attribute nsICancelable cancelable; */
NS_IMETHODIMP CDownload::GetCancelable(nsIWebBrowserCancelable * *aCancelable)
{
NS_ENSURE_ARG_POINTER(aCancelable);
NS_IF_ADDREF(*aCancelable = mCancelable);
return NS_OK;
}
/* readonly attribute PRInt32 percentComplete; */
NS_IMETHODIMP CDownload::GetPercentComplete(PRInt32 *aPercentComplete)
{
NS_ENSURE_ARG_POINTER(aPercentComplete);
*aPercentComplete = mPercentComplete;
return NS_OK;
}
/* attribute wstring displayName; */
NS_IMETHODIMP CDownload::GetDisplayName(PRUnichar * *aDisplayName)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
/* readonly attribute long long startTime; */
NS_IMETHODIMP CDownload::GetStartTime(PRInt64 *aStartTime)
{
NS_ENSURE_ARG_POINTER(aStartTime);
*aStartTime = mStartTime;
return NS_OK;
}
/* readonly attribute nsIMIMEInfo MIMEInfo; */
NS_IMETHODIMP CDownload::GetMIMEInfo(nsIMIMEInfo * *aMIMEInfo)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
#pragma mark -
#pragma mark [CDownload::nsIWebProgressListener]
/* void onStateChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in unsigned long aStateFlags, in nsresult aStatus); */
NS_IMETHODIMP CDownload::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))) {
mCancelable = 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 CDownload::OnProgressChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, PRInt32 aCurSelfProgress, PRInt32 aMaxSelfProgress, PRInt32 aCurTotalProgress, PRInt32 aMaxTotalProgress)
{
if (mUserCanceled) {
mCancelable->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);
BroadcastMessage(msg_OnDLProgressChange, &info);
return NS_OK;
}
/* void onProgressChange64 (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in long long aCurSelfProgress, in long long aMaxSelfProgress, in long long aCurTotalProgress, in long long aMaxTotalProgress); */
NS_IMETHODIMP CDownload::OnProgressChange64(nsIWebProgress *aWebProgress, nsIRequest *aRequest, PRInt64 aCurSelfProgress, PRInt64 aMaxSelfProgress, PRInt64 aCurTotalProgress, PRInt64 aMaxTotalProgress)
{
// XXX truncates 64-bit to 32-bit
return OnProgressChange(aProgress, aRequest,
PRInt32(curSelfProgress), PRInt32(maxSelfProgress),
PRInt32(curTotalProgress), PRInt32(maxTotalProgress));
}
/* void onLocationChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in nsIURI location); */
NS_IMETHODIMP CDownload::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 CDownload::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 CDownload::OnSecurityChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, PRUint32 state)
{
return NS_OK;
}
#pragma mark -
#pragma mark [CDownload Internal Methods]
void CDownload::Cancel()
{
mUserCanceled = true;
// nsWebBrowserPersist does the right thing: After canceling, next time through
// OnStateChange(), aStatus != NS_OK. This isn't the case with nsExternalHelperAppService.
mStatus = NS_ERROR_ABORT;
}
void CDownload::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 unsigned long aReason); */
NS_IMETHODIMP CHelperAppLauncherDialog::Show(nsIHelperAppLauncher *aLauncher, nsISupports *aContext, PRUint32 aReason)
{
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<nsIFile> defaultDownloadDir;
NS_GetSpecialDirectory(NS_MAC_DEFAULT_DOWNLOAD_DIR, getter_AddRefs(defaultDownloadDir));
if (defaultDownloadDir) {
nsCOMPtr<nsILocalFileMac> 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<nsILocalFileMac> 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;
}