зеркало из https://github.com/mozilla/pjs.git
Adding new files for bug 162845 - PPEmbed needs native implementation of download UI. r=pink/sr=sfraser
This commit is contained in:
Родитель
af668a0285
Коммит
9f118d72bb
|
@ -0,0 +1,79 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** 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):
|
||||
* Brian Ryner <bryner@netscape.com>
|
||||
* 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 "AppComponents.h"
|
||||
#include "PromptService.h"
|
||||
#include "UDownload.h"
|
||||
|
||||
#define NS_PROMPTSERVICE_CID \
|
||||
{0xa2112d6a, 0x0e28, 0x421f, {0xb4, 0x6a, 0x25, 0xc0, 0xb3, 0x8, 0xcb, 0xd0}}
|
||||
#define NS_HELPERAPPLAUNCHERDIALOG_CID \
|
||||
{0xf68578eb, 0x6ec2, 0x4169, {0xae, 0x19, 0x8c, 0x62, 0x43, 0xf0, 0xab, 0xe1}}
|
||||
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(CPromptService);
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(CDownload);
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(CHelperAppLauncherDialog);
|
||||
|
||||
static const nsModuleComponentInfo components[] = {
|
||||
{
|
||||
"Prompt Service",
|
||||
NS_PROMPTSERVICE_CID,
|
||||
"@mozilla.org/embedcomp/prompt-service;1",
|
||||
CPromptServiceConstructor
|
||||
},
|
||||
{
|
||||
"Download",
|
||||
NS_DOWNLOAD_CID,
|
||||
NS_DOWNLOAD_CONTRACTID,
|
||||
CDownloadConstructor
|
||||
},
|
||||
{
|
||||
NS_IHELPERAPPLAUNCHERDLG_CLASSNAME,
|
||||
NS_HELPERAPPLAUNCHERDIALOG_CID,
|
||||
NS_IHELPERAPPLAUNCHERDLG_CONTRACTID,
|
||||
CHelperAppLauncherDialogConstructor
|
||||
}
|
||||
};
|
||||
|
||||
const nsModuleComponentInfo* GetAppModuleComponentInfo(int* outNumComponents)
|
||||
{
|
||||
*outNumComponents = sizeof(components) / sizeof(components[0]);
|
||||
return components;
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** 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):
|
||||
* Brian Ryner <bryner@netscape.com>
|
||||
* 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 ***** */
|
||||
|
||||
#ifndef AppComponents_h__
|
||||
#define AppComponents_h__
|
||||
|
||||
#ifndef nsIGenericFactory_h___
|
||||
#include "nsIGenericFactory.h"
|
||||
#endif
|
||||
|
||||
// This method should return a nsModuleComponentInfo array of
|
||||
// application-provided XPCOM components to register.
|
||||
extern const nsModuleComponentInfo* GetAppModuleComponentInfo(int* outNumComponents);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,452 @@
|
|||
/* ***** 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 Chimera 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):
|
||||
* David Hyatt <hyatt@netscape.com>
|
||||
* Simon Fraser <sfraser@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 "CHeaderSniffer.h"
|
||||
#include "UMacUnicode.h"
|
||||
|
||||
#include "UCustomNavServicesDialogs.h"
|
||||
|
||||
#include "netCore.h"
|
||||
|
||||
#include "nsIChannel.h"
|
||||
#include "nsIHttpChannel.h"
|
||||
#include "nsIURL.h"
|
||||
#include "nsIPrefService.h"
|
||||
#include "nsIMIMEService.h"
|
||||
#include "nsIMIMEInfo.h"
|
||||
#include "nsIDOMHTMLDocument.h"
|
||||
#include "nsIDownload.h"
|
||||
#include "nsILocalFileMac.h"
|
||||
|
||||
const char* const persistContractID = "@mozilla.org/embedding/browser/nsWebBrowserPersist;1";
|
||||
|
||||
CHeaderSniffer::CHeaderSniffer(nsIWebBrowserPersist* aPersist, nsIFile* aFile, nsIURI* aURL,
|
||||
nsIDOMDocument* aDocument, nsIInputStream* aPostData,
|
||||
const nsAString& aSuggestedFilename, PRBool aBypassCache, ESaveFormat aSaveFormat)
|
||||
: mPersist(aPersist)
|
||||
, mTmpFile(aFile)
|
||||
, mURL(aURL)
|
||||
, mDocument(aDocument)
|
||||
, mPostData(aPostData)
|
||||
, mDefaultFilename(aSuggestedFilename)
|
||||
, mBypassCache(aBypassCache)
|
||||
, mSaveFormat(aSaveFormat)
|
||||
{
|
||||
NS_INIT_ISUPPORTS();
|
||||
}
|
||||
|
||||
CHeaderSniffer::~CHeaderSniffer()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS1(CHeaderSniffer, nsIWebProgressListener)
|
||||
|
||||
#pragma mark -
|
||||
|
||||
// Implementation of nsIWebProgressListener
|
||||
/* void onStateChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in long aStateFlags, in unsigned long aStatus); */
|
||||
NS_IMETHODIMP
|
||||
CHeaderSniffer::OnStateChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, PRUint32 aStateFlags,
|
||||
PRUint32 aStatus)
|
||||
{
|
||||
if (aStateFlags & nsIWebProgressListener::STATE_START)
|
||||
{
|
||||
nsCOMPtr<nsIWebBrowserPersist> kungFuDeathGrip(mPersist); // be sure to keep it alive while we save
|
||||
// since it owns us as a listener
|
||||
nsCOMPtr<nsIWebProgressListener> kungFuSuicideGrip(this); // and keep ourselves alive
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest, &rv);
|
||||
if (!channel) return rv;
|
||||
channel->GetContentType(mContentType);
|
||||
|
||||
nsCOMPtr<nsIURI> origURI;
|
||||
channel->GetOriginalURI(getter_AddRefs(origURI));
|
||||
|
||||
// Get the content-disposition if we're an HTTP channel.
|
||||
nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
|
||||
if (httpChannel)
|
||||
httpChannel->GetResponseHeader(nsCAutoString("content-disposition"), mContentDisposition);
|
||||
|
||||
mPersist->CancelSave();
|
||||
PRBool exists;
|
||||
mTmpFile->Exists(&exists);
|
||||
if (exists)
|
||||
mTmpFile->Remove(PR_FALSE);
|
||||
|
||||
rv = PerformSave(origURI, mSaveFormat);
|
||||
if (NS_FAILED(rv))
|
||||
{
|
||||
// put up some UI
|
||||
|
||||
}
|
||||
}
|
||||
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
|
||||
CHeaderSniffer::OnProgressChange(nsIWebProgress *aWebProgress,
|
||||
nsIRequest *aRequest,
|
||||
PRInt32 aCurSelfProgress,
|
||||
PRInt32 aMaxSelfProgress,
|
||||
PRInt32 aCurTotalProgress,
|
||||
PRInt32 aMaxTotalProgress)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* void onLocationChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in nsIURI location); */
|
||||
NS_IMETHODIMP
|
||||
CHeaderSniffer::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
|
||||
CHeaderSniffer::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
|
||||
CHeaderSniffer::OnSecurityChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, PRUint32 state)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
static ESaveFormat SaveFormatFromPrefValue(PRInt32 inPrefValue)
|
||||
{
|
||||
switch (inPrefValue)
|
||||
{
|
||||
case 0: return eSaveFormatHTMLComplete;
|
||||
default: // fall through
|
||||
case 1: return eSaveFormatHTML;
|
||||
case 2: return eSaveFormatPlainText;
|
||||
}
|
||||
}
|
||||
|
||||
static PRInt32 PrefValueFromSaveFormat(ESaveFormat inSaveFormat)
|
||||
{
|
||||
switch (inSaveFormat)
|
||||
{
|
||||
case eSaveFormatPlainText: return 2;
|
||||
default: // fall through
|
||||
case eSaveFormatHTML: return 1;
|
||||
case eSaveFormatHTMLComplete: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
nsresult CHeaderSniffer::PerformSave(nsIURI* inOriginalURI, const ESaveFormat inSaveFormat)
|
||||
{
|
||||
nsresult rv;
|
||||
// Are we an HTML document? If so, we will want to append an accessory view to
|
||||
// the save dialog to provide the user with the option of doing a complete
|
||||
// save vs. a single file save.
|
||||
PRBool isHTML = (mDocument && mContentType.Equals("text/html") ||
|
||||
mContentType.Equals("text/xml") ||
|
||||
mContentType.Equals("application/xhtml+xml"));
|
||||
|
||||
// Next find out the directory that we should start in.
|
||||
nsCOMPtr<nsIPrefService> prefs(do_GetService("@mozilla.org/preferences-service;1", &rv));
|
||||
if (!prefs)
|
||||
return rv;
|
||||
nsCOMPtr<nsIPrefBranch> dirBranch;
|
||||
prefs->GetBranch("browser.download.", getter_AddRefs(dirBranch));
|
||||
PRInt32 filterIndex = 0;
|
||||
if (inSaveFormat != eSaveFormatUnspecified) {
|
||||
filterIndex = PrefValueFromSaveFormat(inSaveFormat);
|
||||
}
|
||||
else if (dirBranch) {
|
||||
nsresult rv = dirBranch->GetIntPref("save_converter_index", &filterIndex);
|
||||
if (NS_FAILED(rv))
|
||||
filterIndex = 0;
|
||||
}
|
||||
|
||||
// We need to figure out what file name to use.
|
||||
nsAutoString defaultFileName;
|
||||
if (!mContentDisposition.IsEmpty()) {
|
||||
// (1) Use the HTTP header suggestion.
|
||||
PRInt32 index = mContentDisposition.Find("filename=");
|
||||
if (index >= 0) {
|
||||
// Take the substring following the prefix.
|
||||
index += 9;
|
||||
nsCAutoString filename;
|
||||
mContentDisposition.Right(filename, mContentDisposition.Length() - index);
|
||||
defaultFileName = NS_ConvertUTF8toUCS2(filename);
|
||||
}
|
||||
}
|
||||
|
||||
if (defaultFileName.IsEmpty()) {
|
||||
nsCOMPtr<nsIURL> url(do_QueryInterface(mURL));
|
||||
if (url) {
|
||||
nsCAutoString fileNameCString;
|
||||
url->GetFileName(fileNameCString); // (2) For file URLs, use the file name.
|
||||
defaultFileName = NS_ConvertUTF8toUCS2(fileNameCString);
|
||||
}
|
||||
}
|
||||
|
||||
if (defaultFileName.IsEmpty() && mDocument && isHTML) {
|
||||
nsCOMPtr<nsIDOMHTMLDocument> htmlDoc(do_QueryInterface(mDocument));
|
||||
if (htmlDoc)
|
||||
htmlDoc->GetTitle(defaultFileName); // (3) Use the title of the document.
|
||||
}
|
||||
|
||||
if (defaultFileName.IsEmpty()) {
|
||||
// (4) Use the caller provided name.
|
||||
defaultFileName = mDefaultFilename;
|
||||
}
|
||||
|
||||
if (defaultFileName.IsEmpty() && mURL) {
|
||||
// (5) Use the host.
|
||||
nsCAutoString hostName;
|
||||
mURL->GetHost(hostName);
|
||||
defaultFileName = NS_ConvertUTF8toUCS2(hostName);
|
||||
}
|
||||
|
||||
// One last case to handle about:blank and other fruity untitled pages.
|
||||
if (defaultFileName.IsEmpty())
|
||||
defaultFileName.AssignWithConversion("untitled");
|
||||
|
||||
// Validate the file name to ensure legality.
|
||||
for (PRUint32 i = 0; i < defaultFileName.Length(); i++)
|
||||
if (defaultFileName[i] == ':' || defaultFileName[i] == '/')
|
||||
defaultFileName.SetCharAt(i, PRUnichar(' '));
|
||||
|
||||
// Make sure the appropriate extension is appended to the suggested file name.
|
||||
nsCOMPtr<nsIURI> fileURI(do_CreateInstance("@mozilla.org/network/standard-url;1"));
|
||||
nsCOMPtr<nsIURL> fileURL(do_QueryInterface(fileURI, &rv));
|
||||
if (!fileURL)
|
||||
return rv;
|
||||
|
||||
fileURL->SetFilePath(NS_ConvertUCS2toUTF8(defaultFileName));
|
||||
|
||||
nsCAutoString fileExtension;
|
||||
fileURL->GetFileExtension(fileExtension);
|
||||
|
||||
PRBool setExtension = PR_FALSE;
|
||||
if (mContentType.Equals("text/html")) {
|
||||
if (fileExtension.IsEmpty() || (!fileExtension.Equals("htm") && !fileExtension.Equals("html"))) {
|
||||
defaultFileName.AppendWithConversion(".html");
|
||||
setExtension = PR_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (!setExtension && fileExtension.IsEmpty()) {
|
||||
nsCOMPtr<nsIMIMEService> mimeService(do_GetService("@mozilla.org/mime;1", &rv));
|
||||
if (!mimeService)
|
||||
return rv;
|
||||
nsCOMPtr<nsIMIMEInfo> mimeInfo;
|
||||
rv = mimeService->GetFromMIMEType(mContentType.get(), getter_AddRefs(mimeInfo));
|
||||
if (!mimeInfo)
|
||||
return rv;
|
||||
|
||||
PRUint32 extCount = 0;
|
||||
char** extList = nsnull;
|
||||
mimeInfo->GetFileExtensions(&extCount, &extList);
|
||||
if (extCount > 0 && extList) {
|
||||
defaultFileName.AppendWithConversion(".");
|
||||
defaultFileName.AppendWithConversion(extList[0]);
|
||||
}
|
||||
}
|
||||
|
||||
// Now it's time to pose the save dialog.
|
||||
FSSpec destFileSpec;
|
||||
bool isReplacing = false;
|
||||
|
||||
{
|
||||
Str255 defaultName;
|
||||
char tempBuf1[256], tempBuf2[64];
|
||||
bool result;
|
||||
|
||||
CPlatformUCSConversion::GetInstance()->UCSToPlatform(defaultFileName, defaultName);
|
||||
::CopyPascalStringToC(defaultName, tempBuf1);
|
||||
::CopyCStringToPascal(NS_TruncNodeName(tempBuf1, tempBuf2), defaultName);
|
||||
|
||||
if (isHTML) {
|
||||
ESaveFormat saveFormat = SaveFormatFromPrefValue(filterIndex);
|
||||
UNavServicesDialogs::LCustomFileDesignator customDesignator;
|
||||
result = customDesignator.AskDesignateFile(defaultName, saveFormat);
|
||||
if (!result)
|
||||
return NS_OK; // user canceled
|
||||
filterIndex = PrefValueFromSaveFormat(saveFormat);
|
||||
customDesignator.GetFileSpec(destFileSpec);
|
||||
isReplacing = customDesignator.IsReplacing();
|
||||
}
|
||||
else {
|
||||
UNavServicesDialogs::LFileDesignator stdDesignator;
|
||||
result = stdDesignator.AskDesignateFile(defaultName);
|
||||
if (!result)
|
||||
return NS_OK; // user canceled
|
||||
stdDesignator.GetFileSpec(destFileSpec);
|
||||
isReplacing = stdDesignator.IsReplacing();
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
// only save the pref if the frontend didn't specify a format
|
||||
if (inSaveFormat == eSaveFormatUnspecified && isHTML)
|
||||
dirBranch->SetIntPref("save_converter_index", filterIndex);
|
||||
|
||||
nsCOMPtr<nsILocalFileMac> destFile;
|
||||
|
||||
rv = NS_NewLocalFileWithFSSpec(&destFileSpec, PR_TRUE, getter_AddRefs(destFile));
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
if (isReplacing) {
|
||||
PRBool exists;
|
||||
rv = destFile->Exists(&exists);
|
||||
if (NS_SUCCEEDED(rv) && exists)
|
||||
rv = destFile->Remove(PR_TRUE);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
}
|
||||
|
||||
// if the user chose plain text, set the content type
|
||||
if (isHTML && filterIndex == 2)
|
||||
mContentType = "text/plain";
|
||||
|
||||
nsCOMPtr<nsISupports> sourceData;
|
||||
if (isHTML && filterIndex != 1)
|
||||
sourceData = do_QueryInterface(mDocument); // HTML complete
|
||||
else
|
||||
sourceData = do_QueryInterface(mURL); // HTML or text only
|
||||
|
||||
return InitiateDownload(sourceData, destFile, inOriginalURI);
|
||||
}
|
||||
|
||||
// inOriginalURI is always a URI. inSourceData can be an nsIURI or an nsIDOMDocument, depending
|
||||
// on what we're saving. It's that way for nsIWebBrowserPersist.
|
||||
nsresult CHeaderSniffer::InitiateDownload(nsISupports* inSourceData, nsILocalFile* inDestFile, nsIURI* inOriginalURI)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
nsCOMPtr<nsIWebBrowserPersist> webPersist = do_CreateInstance(persistContractID, &rv);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
nsCOMPtr<nsIURI> sourceURI = do_QueryInterface(inSourceData);
|
||||
|
||||
PRInt64 timeNow = PR_Now();
|
||||
|
||||
nsAutoString fileDisplayName;
|
||||
inDestFile->GetLeafName(fileDisplayName);
|
||||
|
||||
nsCOMPtr<nsIDownload> downloader = do_CreateInstance(NS_DOWNLOAD_CONTRACTID);
|
||||
// dlListener attaches to its progress dialog here, which gains ownership
|
||||
rv = downloader->Init(inOriginalURI, inDestFile, fileDisplayName.get(), nsnull, timeNow, webPersist);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
PRInt32 flags = nsIWebBrowserPersist::PERSIST_FLAGS_NO_CONVERSION |
|
||||
nsIWebBrowserPersist::PERSIST_FLAGS_REPLACE_EXISTING_FILES;
|
||||
if (mBypassCache)
|
||||
flags |= nsIWebBrowserPersist::PERSIST_FLAGS_BYPASS_CACHE;
|
||||
else
|
||||
flags |= nsIWebBrowserPersist::PERSIST_FLAGS_FROM_CACHE;
|
||||
|
||||
webPersist->SetPersistFlags(flags);
|
||||
|
||||
if (sourceURI)
|
||||
{
|
||||
rv = webPersist->SaveURI(sourceURI, mPostData, inDestFile);
|
||||
}
|
||||
else
|
||||
{
|
||||
nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(inSourceData, &rv);
|
||||
if (!domDoc) return rv; // should never happen
|
||||
|
||||
PRInt32 encodingFlags = 0;
|
||||
nsCOMPtr<nsILocalFile> filesFolder;
|
||||
|
||||
if (!mContentType.Equals("text/plain")) {
|
||||
// Create a local directory in the same dir as our file. It
|
||||
// will hold our associated files.
|
||||
filesFolder = do_CreateInstance("@mozilla.org/file/local;1");
|
||||
nsAutoString unicodePath;
|
||||
inDestFile->GetPath(unicodePath);
|
||||
filesFolder->InitWithPath(unicodePath);
|
||||
|
||||
nsAutoString leafName;
|
||||
filesFolder->GetLeafName(leafName);
|
||||
nsAutoString nameMinusExt(leafName);
|
||||
PRInt32 index = nameMinusExt.RFind(".");
|
||||
if (index >= 0)
|
||||
nameMinusExt.Left(nameMinusExt, index);
|
||||
nameMinusExt += NS_LITERAL_STRING(" Files"); // XXXdwh needs to be localizable!
|
||||
filesFolder->SetLeafName(nameMinusExt);
|
||||
PRBool exists = PR_FALSE;
|
||||
filesFolder->Exists(&exists);
|
||||
if (!exists) {
|
||||
rv = filesFolder->Create(nsILocalFile::DIRECTORY_TYPE, 0755);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
encodingFlags |= nsIWebBrowserPersist::ENCODE_FLAGS_FORMATTED |
|
||||
nsIWebBrowserPersist::ENCODE_FLAGS_ABSOLUTE_LINKS |
|
||||
nsIWebBrowserPersist::ENCODE_FLAGS_NOFRAMES_CONTENT;
|
||||
}
|
||||
rv = webPersist->SaveDocument(domDoc, inDestFile, filesFolder, mContentType.get(), encodingFlags, 80);
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
|
@ -0,0 +1,355 @@
|
|||
/* -*- 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 "nsIObserver.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)
|
||||
{
|
||||
NS_INIT_ISUPPORTS();
|
||||
}
|
||||
|
||||
CDownload::~CDownload()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS2(CDownload, nsIDownload, nsIWebProgressListener)
|
||||
|
||||
#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 nsIWebBrowserPersist aPersist); */
|
||||
NS_IMETHODIMP CDownload::Init(nsIURI *aSource, nsILocalFile *aTarget, const PRUnichar *aDisplayName, nsIMIMEInfo *aMIMEInfo, PRInt64 startTime, nsIWebBrowserPersist *aPersist)
|
||||
{
|
||||
try {
|
||||
mSource = aSource;
|
||||
mDestination = aTarget;
|
||||
mStartTime = startTime;
|
||||
mPercentComplete = 0;
|
||||
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);
|
||||
}
|
||||
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 nsIWebBrowserPersist persist; */
|
||||
NS_IMETHODIMP CDownload::GetPersist(nsIWebBrowserPersist * *aPersist)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aPersist);
|
||||
NS_IF_ADDREF(*aPersist = mWebPersist);
|
||||
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;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP CDownload::SetDisplayName(const 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;
|
||||
}
|
||||
|
||||
/* attribute nsIWebProgressListener listener; */
|
||||
NS_IMETHODIMP CDownload::GetListener(nsIWebProgressListener * *aListener)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aListener);
|
||||
NS_IF_ADDREF(*aListener = (nsIWebProgressListener *)this);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP CDownload::SetListener(nsIWebProgressListener * aListener)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
/* attribute nsIObserver observer; */
|
||||
NS_IMETHODIMP CDownload::GetObserver(nsIObserver * *aObserver)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP CDownload::SetObserver(nsIObserver * aObserver)
|
||||
{
|
||||
if (aObserver)
|
||||
aObserver->QueryInterface(NS_GET_IID(nsIHelperAppLauncher), getter_AddRefs(mHelperAppLauncher));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
#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))) {
|
||||
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 CDownload::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 = ((float)aCurTotalProgress / (float)aMaxTotalProgress) * 100.0;
|
||||
|
||||
MsgOnDLProgressChangeInfo info(this, aCurTotalProgress, aMaxTotalProgress);
|
||||
BroadcastMessage(msg_OnDLProgressChange, &info);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* 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.
|
||||
if (!mWebPersist)
|
||||
mStatus = NS_ERROR_ABORT;
|
||||
}
|
||||
|
||||
void CDownload::CreateProgressView()
|
||||
{
|
||||
sProgressView = new CMultiDownloadProgress;
|
||||
ThrowIfNil_(sProgressView);
|
||||
}
|
||||
|
||||
|
||||
//*****************************************************************************
|
||||
// CHelperAppLauncherDialog
|
||||
//*****************************************************************************
|
||||
#pragma mark -
|
||||
#pragma mark [CHelperAppLauncherDialog]
|
||||
|
||||
CHelperAppLauncherDialog::CHelperAppLauncherDialog()
|
||||
{
|
||||
NS_INIT_ISUPPORTS();
|
||||
}
|
||||
|
||||
CHelperAppLauncherDialog::~CHelperAppLauncherDialog()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS1(CHelperAppLauncherDialog, nsIHelperAppLauncherDialog)
|
||||
|
||||
/* void show (in nsIHelperAppLauncher aLauncher, in nsISupports aContext); */
|
||||
NS_IMETHODIMP CHelperAppLauncherDialog::Show(nsIHelperAppLauncher *aLauncher, nsISupports *aContext)
|
||||
{
|
||||
return aLauncher->SaveToDisk(nsnull, PR_FALSE);
|
||||
}
|
||||
|
||||
/* nsILocalFile promptForSaveToFile (in nsISupports aWindowContext, in wstring aDefaultFile, in wstring aSuggestedFileExtension); */
|
||||
NS_IMETHODIMP CHelperAppLauncherDialog::PromptForSaveToFile(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;
|
||||
}
|
||||
|
||||
/* void showProgressDialog (in nsIHelperAppLauncher aLauncher, in nsISupports aContext); */
|
||||
NS_IMETHODIMP CHelperAppLauncherDialog::ShowProgressDialog(nsIHelperAppLauncher *aLauncher, nsISupports *aContext)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
|
@ -0,0 +1,171 @@
|
|||
/* -*- 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 ***** */
|
||||
|
||||
#ifndef UDownload_h__
|
||||
#define UDownload_h__
|
||||
#pragma once
|
||||
|
||||
#include "nsIDownload.h"
|
||||
#include "nsIWebProgressListener.h"
|
||||
#include "nsIHelperAppLauncherDialog.h"
|
||||
|
||||
#include "nsIURI.h"
|
||||
#include "nsILocalFile.h"
|
||||
#include "nsIWebBrowserPersist.h"
|
||||
|
||||
class ADownloadProgressView;
|
||||
|
||||
//*****************************************************************************
|
||||
// CDownload
|
||||
//
|
||||
// Holds information used to display a single download in the UI. This object is
|
||||
// created in one of two ways:
|
||||
// (1) By nsExternalHelperAppHandler when Gecko encounters a MIME type which
|
||||
// it doesn't itself handle. In this case, the notifications sent to
|
||||
// nsIDownload are controlled by nsExternalHelperAppHandler.
|
||||
// (2) By the embedding app's file saving code when saving a web page or a link
|
||||
// target. See CHeaderSniffer.cpp. In this case, the notifications sent to
|
||||
// nsIDownload are controlled by the implementation of nsIWebBrowserPersist.
|
||||
//*****************************************************************************
|
||||
|
||||
class CDownload : public nsIDownload,
|
||||
public nsIWebProgressListener,
|
||||
public LBroadcaster
|
||||
{
|
||||
public:
|
||||
|
||||
// Messages we broadcast to listeners.
|
||||
enum {
|
||||
msg_OnDLStart = 57723, // param is CDownload*
|
||||
msg_OnDLComplete, // param is CDownload*
|
||||
msg_OnDLProgressChange // param is MsgOnDLProgressChangeInfo*
|
||||
};
|
||||
|
||||
struct MsgOnDLProgressChangeInfo
|
||||
{
|
||||
MsgOnDLProgressChangeInfo(CDownload* broadcaster, PRInt32 curProgress, PRInt32 maxProgress) :
|
||||
mBroadcaster(broadcaster), mCurProgress(curProgress), mMaxProgress(maxProgress)
|
||||
{ }
|
||||
|
||||
CDownload *mBroadcaster;
|
||||
PRInt32 mCurProgress, mMaxProgress;
|
||||
};
|
||||
|
||||
CDownload();
|
||||
virtual ~CDownload();
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIDOWNLOAD
|
||||
NS_DECL_NSIWEBPROGRESSLISTENER
|
||||
|
||||
virtual void Cancel();
|
||||
virtual void GetStatus(nsresult& aStatus)
|
||||
{ aStatus = mStatus; }
|
||||
|
||||
protected:
|
||||
void EnsureProgressView()
|
||||
{
|
||||
if (!sProgressView)
|
||||
CreateProgressView();
|
||||
}
|
||||
virtual void CreateProgressView();
|
||||
// sProgressView is a singleton. This will only be called once.
|
||||
|
||||
protected:
|
||||
nsCOMPtr<nsIURI> mSource;
|
||||
nsCOMPtr<nsILocalFile> mDestination;
|
||||
PRInt64 mStartTime;
|
||||
PRInt32 mPercentComplete;
|
||||
|
||||
bool mGotFirstStateChange, mIsNetworkTransfer;
|
||||
bool mUserCanceled;
|
||||
nsresult mStatus;
|
||||
|
||||
// These two are mutually exclusive.
|
||||
nsCOMPtr<nsIWebBrowserPersist> mWebPersist;
|
||||
nsCOMPtr<nsIHelperAppLauncher> mHelperAppLauncher;
|
||||
|
||||
static ADownloadProgressView *sProgressView;
|
||||
};
|
||||
|
||||
//*****************************************************************************
|
||||
// CHelperAppLauncherDialog
|
||||
//
|
||||
// The implementation of nsIExternalHelperAppService in Gecko creates one of
|
||||
// these at the beginning of the download and calls its Show() method. Typically,
|
||||
// this will create a non-modal dialog in which the user can decide whether to
|
||||
// save the file to disk or open it with an application. This implementation
|
||||
// just saves the file to disk unconditionally. The user can decide what they
|
||||
// wish to do with the download from the progress dialog.
|
||||
//*****************************************************************************
|
||||
|
||||
class CHelperAppLauncherDialog : public nsIHelperAppLauncherDialog
|
||||
{
|
||||
public:
|
||||
CHelperAppLauncherDialog();
|
||||
virtual ~CHelperAppLauncherDialog();
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIHELPERAPPLAUNCHERDIALOG
|
||||
|
||||
protected:
|
||||
|
||||
};
|
||||
|
||||
|
||||
//*****************************************************************************
|
||||
// ADownloadProgressView
|
||||
//
|
||||
// An abstract class which handles the display and interaction with a download.
|
||||
// Typically, it presents a progress dialog.
|
||||
//*****************************************************************************
|
||||
|
||||
class ADownloadProgressView
|
||||
{
|
||||
friend class CDownload;
|
||||
|
||||
virtual void AddDownloadItem(CDownload *aDownloadItem) = 0;
|
||||
// A download is beginning. Initialize the UI for this download.
|
||||
// Throughout the download process, the CDownload will broadcast
|
||||
// status messages. The UI needs to call LBroadcaster::AddListener()
|
||||
// on the CDownload at this point in order to get the messages.
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif // UDownload_h__
|
|
@ -0,0 +1,615 @@
|
|||
/* -*- 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 "UDownloadDisplay.h"
|
||||
#include "ApplIDs.h"
|
||||
#include "CIconServicesIcon.h"
|
||||
|
||||
// Gecko
|
||||
#include "nsString.h"
|
||||
#include "nsILocalFileMac.h"
|
||||
|
||||
// Std
|
||||
#include <algorithm>
|
||||
using namespace std;
|
||||
|
||||
// PowerPlant
|
||||
#include <LStaticText.h>
|
||||
#include <LProgressBar.h>
|
||||
|
||||
//*****************************************************************************
|
||||
// CMultiDownloadProgress
|
||||
//*****************************************************************************
|
||||
#pragma mark [CMultiDownloadProgress]
|
||||
|
||||
bool CMultiDownloadProgress::sRegisteredViewClasses = false;
|
||||
|
||||
CMultiDownloadProgress::CMultiDownloadProgress() :
|
||||
mWindow(nil)
|
||||
{
|
||||
if (!sRegisteredViewClasses) {
|
||||
RegisterClass_(CMultiDownloadProgressWindow);
|
||||
RegisterClass_(CDownloadProgressView);
|
||||
RegisterClass_(CIconServicesIcon);
|
||||
sRegisteredViewClasses = true;
|
||||
}
|
||||
}
|
||||
|
||||
CMultiDownloadProgress::~CMultiDownloadProgress()
|
||||
{
|
||||
}
|
||||
|
||||
void CMultiDownloadProgress::AddDownloadItem(CDownload *aDownloadItem)
|
||||
{
|
||||
if (!mWindow) {
|
||||
mWindow = static_cast<CMultiDownloadProgressWindow*>
|
||||
(LWindow::CreateWindow(wind_DownloadProgress, this));
|
||||
ThrowIfNil_(mWindow);
|
||||
|
||||
// Add this as a listener to the window so we can know when it's destroyed.
|
||||
mWindow->AddListener(this);
|
||||
}
|
||||
|
||||
// Create the view...
|
||||
LView::SetDefaultView(mWindow);
|
||||
LCommander::SetDefaultCommander(mWindow);
|
||||
LAttachable::SetDefaultAttachable(nil);
|
||||
|
||||
CDownloadProgressView *itemView = static_cast<CDownloadProgressView*>
|
||||
(UReanimator::ReadObjects(ResType_PPob, view_DownloadProgressItem));
|
||||
ThrowIfNil_(itemView);
|
||||
|
||||
// and add it to the window.
|
||||
mWindow->AddDownloadView(itemView);
|
||||
itemView->SetDownload(aDownloadItem);
|
||||
}
|
||||
|
||||
// This happens in response to the window being closed. Check for active
|
||||
// downloads and confirm stopping them if there are any. Returning false
|
||||
// will prevent the window from being closed.
|
||||
Boolean CMultiDownloadProgress::AllowSubRemoval(LCommander* inSub)
|
||||
{
|
||||
return (!mWindow || (inSub == mWindow && mWindow->ConfirmClose()));
|
||||
}
|
||||
|
||||
// This happens in response to the app being quit. Check for active
|
||||
// downloads and confirm stopping them if there are any. Returning
|
||||
// false will prevent the app from quitting.
|
||||
Boolean CMultiDownloadProgress::AttemptQuitSelf(SInt32 inSaveOption)
|
||||
{
|
||||
return (!mWindow || mWindow->ConfirmClose());
|
||||
}
|
||||
|
||||
void CMultiDownloadProgress::ListenToMessage(MessageT inMessage,
|
||||
void* ioParam)
|
||||
{
|
||||
if (inMessage == msg_BroadcasterDied &&
|
||||
(CMultiDownloadProgressWindow*)((LBroadcaster*)ioParam) == mWindow)
|
||||
mWindow = nil;
|
||||
}
|
||||
|
||||
|
||||
//*****************************************************************************
|
||||
// CMultiDownloadProgressWindow
|
||||
//*****************************************************************************
|
||||
#pragma mark -
|
||||
#pragma mark [CMultiDownloadProgressWindow]
|
||||
|
||||
CMultiDownloadProgressWindow::CMultiDownloadProgressWindow() :
|
||||
mDownloadViewCount(0)
|
||||
{
|
||||
StartBroadcasting();
|
||||
}
|
||||
|
||||
CMultiDownloadProgressWindow::CMultiDownloadProgressWindow(LStream* inStream) :
|
||||
LWindow(inStream),
|
||||
mDownloadViewCount(0)
|
||||
{
|
||||
StartBroadcasting();
|
||||
}
|
||||
|
||||
CMultiDownloadProgressWindow::~CMultiDownloadProgressWindow()
|
||||
{
|
||||
}
|
||||
|
||||
void CMultiDownloadProgressWindow::AddDownloadView(CDownloadProgressView *aView)
|
||||
{
|
||||
const SInt16 kSeparatorHeight = 3;
|
||||
|
||||
SDimension16 currSize;
|
||||
GetFrameSize(currSize);
|
||||
|
||||
SDimension16 viewSize;
|
||||
aView->GetFrameSize(viewSize);
|
||||
ResizeWindowTo(currSize.width, (viewSize.height * (mDownloadViewCount + 1)) - kSeparatorHeight);
|
||||
|
||||
aView->PlaceInSuperFrameAt(0, viewSize.height * mDownloadViewCount++, false);
|
||||
aView->FinishCreate();
|
||||
}
|
||||
|
||||
void CMultiDownloadProgressWindow::RemoveDownloadView(CDownloadProgressView *aView)
|
||||
{
|
||||
// We can't remove the last view, leaving an empty window frame
|
||||
if (mDownloadViewCount <= 1)
|
||||
return;
|
||||
|
||||
SDimension16 removedPaneSize;
|
||||
aView->GetFrameSize(removedPaneSize);
|
||||
SPoint32 removedPaneLoc;
|
||||
aView->GetFrameLocation(removedPaneLoc);
|
||||
|
||||
delete aView;
|
||||
RemoveSubPane(aView);
|
||||
mDownloadViewCount--;
|
||||
|
||||
TArrayIterator<LPane*> iterator(GetSubPanes());
|
||||
LPane *subPane;
|
||||
while (iterator.Next(subPane)) {
|
||||
SPoint32 subPaneLoc;
|
||||
subPane->GetFrameLocation(subPaneLoc);
|
||||
if (subPaneLoc.v >= removedPaneLoc.v + removedPaneSize.height) {
|
||||
subPane->MoveBy(0, -removedPaneSize.height, true);
|
||||
}
|
||||
}
|
||||
ResizeWindowBy(0, -removedPaneSize.height);
|
||||
}
|
||||
|
||||
Boolean CMultiDownloadProgressWindow::ConfirmClose()
|
||||
{
|
||||
Boolean canClose = true;
|
||||
SInt32 numActiveDownloads = 0;
|
||||
|
||||
TArrayIterator<LPane*> iterator(GetSubPanes());
|
||||
LPane *subPane;
|
||||
while (iterator.Next(subPane)) {
|
||||
CDownloadProgressView *downloadView = dynamic_cast<CDownloadProgressView*>(subPane);
|
||||
if (downloadView && downloadView->IsActive())
|
||||
numActiveDownloads++;
|
||||
}
|
||||
|
||||
if (numActiveDownloads != 0) {
|
||||
short itemHit;
|
||||
AlertStdAlertParamRec pb;
|
||||
|
||||
pb.movable = false;
|
||||
pb.helpButton = false;
|
||||
pb.filterProc = nil;
|
||||
pb.defaultText = (StringPtr) kAlertDefaultOKText;
|
||||
pb.cancelText = (StringPtr) kAlertDefaultCancelText;
|
||||
pb.otherText = nil;
|
||||
pb.defaultButton = kStdOkItemIndex;
|
||||
pb.cancelButton = kStdCancelItemIndex;
|
||||
pb.position = kWindowAlertPositionParentWindowScreen;
|
||||
|
||||
LStr255 msgString(STRx_StdAlertStrings, str_ConfirmCloseDownloads);
|
||||
LStr255 explainString(STRx_StdAlertStrings, str_ConfirmCloseDownloadsExp);
|
||||
::StandardAlert(kAlertStopAlert, msgString, explainString, &pb, &itemHit);
|
||||
if (itemHit != kAlertStdAlertOKButton)
|
||||
canClose = false;
|
||||
}
|
||||
return canClose;
|
||||
}
|
||||
|
||||
|
||||
//*****************************************************************************
|
||||
// CDownloadProgressView
|
||||
//*****************************************************************************
|
||||
#pragma mark -
|
||||
#pragma mark [CDownloadProgressView]
|
||||
|
||||
enum {
|
||||
paneID_ProgressBar = 'Prog',
|
||||
paneID_CancelButton = 'Cncl',
|
||||
paneID_OpenButton = 'Open',
|
||||
paneID_RevealButton = 'Rvel',
|
||||
paneID_CloseButton = 'Clos',
|
||||
paneID_StatusText = 'Stat',
|
||||
paneID_StatusLabel = 'StLa',
|
||||
paneID_TimeRemText = 'Time',
|
||||
paneID_TimeRemLabel = 'TiLa',
|
||||
paneID_SrcURIText = 'SURI',
|
||||
paneID_SrcURILabel = 'SULa',
|
||||
paneID_DestFileText = 'Dest',
|
||||
paneID_DestFileLabel = 'DFLa'
|
||||
};
|
||||
|
||||
CDownloadProgressView::CDownloadProgressView() :
|
||||
mDownloadActive(false)
|
||||
{
|
||||
}
|
||||
|
||||
CDownloadProgressView::CDownloadProgressView(LStream* inStream) :
|
||||
LView(inStream),
|
||||
mDownloadActive(false)
|
||||
{
|
||||
}
|
||||
|
||||
CDownloadProgressView::~CDownloadProgressView()
|
||||
{
|
||||
if (mDownloadActive)
|
||||
CancelDownload();
|
||||
|
||||
mDownload = nsnull;
|
||||
}
|
||||
|
||||
void CDownloadProgressView::FinishCreateSelf()
|
||||
{
|
||||
mProgressBar = dynamic_cast<LProgressBar*>(FindPaneByID(paneID_ProgressBar));
|
||||
mCancelButton = dynamic_cast<LControl*>(FindPaneByID(paneID_CancelButton));
|
||||
mOpenButton = dynamic_cast<LControl*>(FindPaneByID(paneID_OpenButton));
|
||||
mRevealButton = dynamic_cast<LControl*>(FindPaneByID(paneID_RevealButton));
|
||||
mCloseButton = dynamic_cast<LControl*>(FindPaneByID(paneID_CloseButton));
|
||||
mStatusText = dynamic_cast<LStaticText*>(FindPaneByID(paneID_StatusText));
|
||||
mTimeRemainingText = dynamic_cast<LStaticText*>(FindPaneByID(paneID_TimeRemText));
|
||||
mSrcURIText = dynamic_cast<LStaticText*>(FindPaneByID(paneID_SrcURIText));
|
||||
mDestFileText = dynamic_cast<LStaticText*>(FindPaneByID(paneID_DestFileText));
|
||||
|
||||
// The control value is set in terms of percent
|
||||
if (mProgressBar)
|
||||
mProgressBar->SetMaxValue(100);
|
||||
|
||||
ControlFontStyleRec styleRec;
|
||||
|
||||
if (CreateStyleRecFromThemeFont(kThemeSmallSystemFont, styleRec) == noErr) {
|
||||
if (mStatusText)
|
||||
mStatusText->SetFontStyle(styleRec);
|
||||
if (mTimeRemainingText)
|
||||
mTimeRemainingText->SetFontStyle(styleRec);
|
||||
if (mSrcURIText)
|
||||
mSrcURIText->SetFontStyle(styleRec);
|
||||
if (mDestFileText)
|
||||
mDestFileText->SetFontStyle(styleRec);
|
||||
}
|
||||
if (CreateStyleRecFromThemeFont(kThemeSmallEmphasizedSystemFont, styleRec) == noErr) {
|
||||
|
||||
ResIDT labelIDs [] = { paneID_StatusLabel,
|
||||
paneID_TimeRemLabel,
|
||||
paneID_SrcURILabel,
|
||||
paneID_DestFileLabel };
|
||||
|
||||
for (int i = 0; i < sizeof(labelIDs) / sizeof(labelIDs[0]); i++) {
|
||||
LStaticText *staticText = dynamic_cast<LStaticText*>(FindPaneByID(labelIDs[i]));
|
||||
if (staticText)
|
||||
staticText->SetFontStyle(styleRec);
|
||||
}
|
||||
}
|
||||
|
||||
UReanimator::LinkListenerToControls(this, this, view_DownloadProgressItem);
|
||||
StartListening();
|
||||
}
|
||||
|
||||
|
||||
Boolean CDownloadProgressView::ObeyCommand(CommandT inCommand,
|
||||
void *ioParam)
|
||||
{
|
||||
#pragma unused(ioParam)
|
||||
|
||||
Boolean cmdHandled = false;
|
||||
nsCOMPtr<nsILocalFile> targetFile;
|
||||
|
||||
switch (inCommand)
|
||||
{
|
||||
case paneID_CancelButton:
|
||||
{
|
||||
CancelDownload();
|
||||
cmdHandled = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case paneID_OpenButton:
|
||||
{
|
||||
mDownload->GetTarget(getter_AddRefs(targetFile));
|
||||
if (targetFile)
|
||||
targetFile->Launch();
|
||||
}
|
||||
break;
|
||||
|
||||
case paneID_RevealButton:
|
||||
{
|
||||
mDownload->GetTarget(getter_AddRefs(targetFile));
|
||||
if (targetFile)
|
||||
targetFile->Reveal();
|
||||
}
|
||||
break;
|
||||
|
||||
case paneID_CloseButton:
|
||||
{
|
||||
LView *view = this, *superView;
|
||||
while ((superView = view->GetSuperView()) != nil)
|
||||
view = superView;
|
||||
CMultiDownloadProgressWindow *multiWindow = dynamic_cast<CMultiDownloadProgressWindow*>(view);
|
||||
if (multiWindow)
|
||||
multiWindow->RemoveDownloadView(this);
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
return cmdHandled;
|
||||
}
|
||||
|
||||
void CDownloadProgressView::ListenToMessage(MessageT inMessage,
|
||||
void* ioParam)
|
||||
{
|
||||
switch (inMessage) {
|
||||
|
||||
case CDownload::msg_OnDLStart:
|
||||
{
|
||||
mDownloadActive = true;
|
||||
if (mCancelButton)
|
||||
mCancelButton->Enable();
|
||||
}
|
||||
break;
|
||||
|
||||
case CDownload::msg_OnDLComplete:
|
||||
{
|
||||
mDownloadActive = false;
|
||||
if (mCancelButton)
|
||||
mCancelButton->Disable();
|
||||
if (mCloseButton)
|
||||
mCloseButton->Enable();
|
||||
|
||||
CDownload *download = reinterpret_cast<CDownload*>(ioParam);
|
||||
nsresult downloadStatus;
|
||||
download->GetStatus(downloadStatus);
|
||||
|
||||
// When saving documents as plain text, we might not get any
|
||||
// progress change notifications in which to set the progress bar.
|
||||
// Now that the download is done, put the bar in a reasonable state.
|
||||
if (mProgressBar) {
|
||||
mProgressBar->SetIndeterminateFlag(false, false);
|
||||
if (NS_SUCCEEDED(downloadStatus))
|
||||
mProgressBar->SetValue(mProgressBar->GetMaxValue());
|
||||
else
|
||||
mProgressBar->SetValue(0);
|
||||
}
|
||||
|
||||
if (NS_SUCCEEDED(downloadStatus)) {
|
||||
if (mOpenButton)
|
||||
mOpenButton->Enable();
|
||||
}
|
||||
if (mRevealButton)
|
||||
mRevealButton->Enable();
|
||||
if (mTimeRemainingText)
|
||||
mTimeRemainingText->SetText(LStr255("\p"));
|
||||
}
|
||||
break;
|
||||
|
||||
case CDownload::msg_OnDLProgressChange:
|
||||
{
|
||||
CDownload::MsgOnDLProgressChangeInfo *info =
|
||||
static_cast<CDownload::MsgOnDLProgressChangeInfo*>(ioParam);
|
||||
|
||||
if (mProgressBar) {
|
||||
PRInt32 percentComplete;
|
||||
info->mBroadcaster->GetPercentComplete(&percentComplete);
|
||||
if (percentComplete != -1 && mProgressBar->IsIndeterminate())
|
||||
mProgressBar->SetIndeterminateFlag(false, false);
|
||||
else if (percentComplete == -1 && !mProgressBar->IsIndeterminate())
|
||||
mProgressBar->SetIndeterminateFlag(true, true);
|
||||
|
||||
if (!mProgressBar->IsIndeterminate()) {
|
||||
PRInt32 controlVal = min(100, max(0, percentComplete));
|
||||
mProgressBar->SetValue(controlVal);
|
||||
}
|
||||
}
|
||||
|
||||
// Set the progress bar as often as we're called. Smooth movement is nice.
|
||||
// Limit the frequency at which the textual status is updated though.
|
||||
if (info->mCurProgress == info->mMaxProgress ||
|
||||
::TickCount() - mLastStatusUpdateTicks >= kStatusUpdateIntervalTicks) {
|
||||
UpdateStatus(info);
|
||||
mLastStatusUpdateTicks = ::TickCount();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
ProcessCommand(inMessage, ioParam);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void CDownloadProgressView::SetDownload(CDownload *aDownload)
|
||||
{
|
||||
mDownload = aDownload;
|
||||
if (!mDownload)
|
||||
return;
|
||||
|
||||
mDownloadActive = true;
|
||||
mLastStatusUpdateTicks = ::TickCount();
|
||||
aDownload->AddListener(this);
|
||||
|
||||
nsresult rv;
|
||||
nsCAutoString tempStr;
|
||||
|
||||
if (mSrcURIText) {
|
||||
nsCOMPtr<nsIURI> srcURI;
|
||||
aDownload->GetSource(getter_AddRefs(srcURI));
|
||||
if (srcURI) {
|
||||
rv = srcURI->GetSpec(tempStr);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
mSrcURIText->SetText(const_cast<Ptr>(PromiseFlatCString(tempStr).get()), tempStr.Length());
|
||||
}
|
||||
}
|
||||
|
||||
if (mDestFileText) {
|
||||
nsCOMPtr<nsILocalFile> destFile;
|
||||
aDownload->GetTarget(getter_AddRefs(destFile));
|
||||
if (destFile) {
|
||||
rv = destFile->GetNativePath(tempStr);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
mDestFileText->SetText(const_cast<Ptr>(PromiseFlatCString(tempStr).get()), tempStr.Length());
|
||||
}
|
||||
}
|
||||
|
||||
// At this point, make sure our window is showing.
|
||||
LWindow::FetchWindowObject(GetMacWindow())->Show();
|
||||
}
|
||||
|
||||
void CDownloadProgressView::CancelDownload()
|
||||
{
|
||||
CDownload *download = dynamic_cast<CDownload*>(mDownload.get());
|
||||
download->Cancel();
|
||||
}
|
||||
|
||||
Boolean CDownloadProgressView::IsActive()
|
||||
{
|
||||
return mDownloadActive;
|
||||
}
|
||||
|
||||
void CDownloadProgressView::UpdateStatus(CDownload::MsgOnDLProgressChangeInfo *info)
|
||||
{
|
||||
PRInt64 startTime;
|
||||
mDownload->GetStartTime(&startTime);
|
||||
PRInt32 elapsedSecs = (PR_Now() - startTime) / PR_USEC_PER_SEC;
|
||||
float bytesPerSec = info->mCurProgress / elapsedSecs;
|
||||
|
||||
UInt8 startPos;
|
||||
LStr255 valueStr;
|
||||
|
||||
if (mStatusText) {
|
||||
// "@1 of @2 (at @3/sec)"
|
||||
LStr255 formatStr(STRx_DownloadStatus, str_ProgressFormat);
|
||||
|
||||
// Insert each item into the string individually in order to
|
||||
// allow certain elements to be omitted from the format.
|
||||
if ((startPos = formatStr.Find("\p@1")) != 0)
|
||||
formatStr.Replace(startPos, 2, FormatBytes(info->mCurProgress, valueStr));
|
||||
if ((startPos = formatStr.Find("\p@2")) != 0)
|
||||
formatStr.Replace(startPos, 2, FormatBytes(info->mMaxProgress, valueStr));
|
||||
if ((startPos = formatStr.Find("\p@3")) != 0)
|
||||
formatStr.Replace(startPos, 2, FormatBytes(bytesPerSec, valueStr));
|
||||
|
||||
mStatusText->SetText(formatStr);
|
||||
}
|
||||
|
||||
if (mTimeRemainingText) {
|
||||
PRInt32 secsRemaining = rint(float(info->mMaxProgress - info->mCurProgress) / bytesPerSec);
|
||||
mTimeRemainingText->SetText(FormatFuzzyTime(secsRemaining, valueStr));
|
||||
}
|
||||
}
|
||||
|
||||
LStr255& CDownloadProgressView::FormatBytes(float inBytes, LStr255& ioString)
|
||||
{
|
||||
const float kOneThousand24 = 1024.0;
|
||||
char buf[256];
|
||||
|
||||
if (inBytes < 0) {
|
||||
return (ioString = "???");
|
||||
}
|
||||
if (inBytes < kOneThousand24) {
|
||||
sprintf(buf, "%.1f Bytes", inBytes);
|
||||
return (ioString = buf);
|
||||
}
|
||||
inBytes /= kOneThousand24;
|
||||
if (inBytes < 1024) {
|
||||
sprintf(buf, "%.1f KB", inBytes);
|
||||
return (ioString = buf);
|
||||
}
|
||||
inBytes /= kOneThousand24;
|
||||
if (inBytes < 1024) {
|
||||
sprintf(buf, "%.1f MB", inBytes);
|
||||
return (ioString = buf);
|
||||
}
|
||||
inBytes /= kOneThousand24;
|
||||
sprintf(buf, "%.2f GB", inBytes);
|
||||
return (ioString = buf);
|
||||
}
|
||||
|
||||
LStr255& CDownloadProgressView::FormatFuzzyTime(PRInt32 inSecs, LStr255& ioString)
|
||||
{
|
||||
char valueBuf[32];
|
||||
|
||||
if (inSecs < 90) {
|
||||
if (inSecs < 7)
|
||||
ioString.Assign(STRx_DownloadStatus, str_About5Seconds);
|
||||
else if (inSecs < 13)
|
||||
ioString.Assign(STRx_DownloadStatus, str_About10Seconds);
|
||||
else if (inSecs < 60)
|
||||
ioString.Assign(STRx_DownloadStatus, str_LessThan1Minute);
|
||||
else
|
||||
ioString.Assign(STRx_DownloadStatus, str_About1Minute);
|
||||
return ioString;
|
||||
}
|
||||
inSecs = (inSecs + 30) / 60; // Round up so we don't say "About 1 minutes"
|
||||
if (inSecs < 60) {
|
||||
sprintf(valueBuf, "%d", inSecs);
|
||||
ioString.Assign(STRx_DownloadStatus, str_AboutNMinutes);
|
||||
ioString.Replace(ioString.Find("\p@1"), 2, LStr255(valueBuf));
|
||||
return ioString;
|
||||
}
|
||||
inSecs /= 60;
|
||||
if (inSecs == 1)
|
||||
ioString.Assign(STRx_DownloadStatus, str_About1Hour);
|
||||
else {
|
||||
sprintf(valueBuf, "%d", inSecs);
|
||||
ioString.Assign(STRx_DownloadStatus, str_AboutNHours);
|
||||
ioString.Replace(ioString.Find("\p@1"), 2, LStr255(valueBuf));
|
||||
}
|
||||
return ioString;
|
||||
}
|
||||
|
||||
OSErr CDownloadProgressView::CreateStyleRecFromThemeFont(ThemeFontID inThemeID,
|
||||
ControlFontStyleRec& outStyle)
|
||||
{
|
||||
Str255 themeFontName;
|
||||
SInt16 themeFontSize;
|
||||
Style themeStyle;
|
||||
SInt16 themeFontNum;
|
||||
|
||||
OSErr err = ::GetThemeFont(kThemeSmallSystemFont,
|
||||
smSystemScript,
|
||||
themeFontName,
|
||||
&themeFontSize,
|
||||
&themeStyle);
|
||||
if (err != noErr)
|
||||
return err;
|
||||
|
||||
outStyle.flags = kControlUseFontMask +
|
||||
kControlUseFaceMask +
|
||||
kControlUseSizeMask;
|
||||
|
||||
::GetFNum(themeFontName, &themeFontNum);
|
||||
outStyle.font = themeFontNum;
|
||||
outStyle.size = themeFontSize;
|
||||
outStyle.style = themeStyle;
|
||||
|
||||
return noErr;
|
||||
}
|
||||
|
Загрузка…
Ссылка в новой задаче