Fix bug 145800 -- implement downlod progress UI in chimera. These changes allow us to reuse the nsDownloadListener and progress dialog for both Saving (with an nsIWebBrowserPersist) and downloading (where necko creates an nsIDownload, which we implement). They are also factored so that other cocoa apps could reuse the downloading backend with their own progress dialog. r=pinkerton/bryner/ccarlen.

This commit is contained in:
sfraser%netscape.com 2002-07-24 05:53:14 +00:00
Родитель 1655a1a46f
Коммит eaff371e3b
90 изменённых файлов: 5294 добавлений и 2994 удалений

Просмотреть файл

@ -36,7 +36,6 @@
* ***** END LICENSE BLOCK ***** */
#import "CHBrowserView.h"
#import "ProgressDlgController.h"
#import "FindDlgController.h"
#import "nsCocoaBrowserService.h"
#import "mozView.h"
@ -65,18 +64,12 @@
// Saving of links/images/docs
#include "nsIWebBrowserFocus.h"
#include "nsIDOMHTMLDocument.h"
#include "nsIDOMNSDocument.h"
#include "nsIDOMLocation.h"
#include "nsIURL.h"
#include "nsIWebBrowserPersist.h"
#include "nsIProperties.h"
#include "nsIRequest.h"
#include "nsIChannel.h"
#include "nsIHttpChannel.h"
#include "nsIPref.h"
#include "nsIMIMEService.h"
#include "nsIMIMEInfo.h"
#include "nsIPrefService.h"
#include "nsISHistory.h"
#include "nsIHistoryEntry.h"
#include "nsISHEntry.h"
@ -84,6 +77,7 @@
#include "nsIContextMenuListener.h"
#include "nsITooltipListener.h"
#include "nsIEmbeddingSiteWindow2.h"
#include "SaveHeaderSniffer.h"
typedef unsigned int DragReference;
#include "nsIDragHelperService.h"
@ -677,265 +671,7 @@ nsCocoaBrowserListener::SetContainer(id <NSBrowserContainer> aContainer)
[mContainer retain];
}
// Implementation of a header sniffer class that is used when saving Web pages and images.
class nsHeaderSniffer : public nsIWebProgressListener
{
public:
nsHeaderSniffer(nsIWebBrowserPersist* aPersist, nsIFile* aFile, nsIURI* aURL,
nsIDOMDocument* aDocument, nsIInputStream* aPostData,
const nsCString& aSuggestedFilename, PRBool aBypassCache,
NSView* aFilterView, NSPopUpButton* aFilterList)
{
NS_INIT_REFCNT();
mPersist = aPersist;
mTmpFile = aFile;
mURL = aURL;
mDocument = aDocument;
mPostData = aPostData;
mDefaultFilename = aSuggestedFilename;
mBypassCache = aBypassCache;
mFilterView = aFilterView;
mFilterList = aFilterList;
}
virtual ~nsHeaderSniffer()
{
};
NS_DECL_ISUPPORTS
NS_DECL_NSIWEBPROGRESSLISTENER
protected:
void PerformSave();
private:
nsIWebBrowserPersist* mPersist; // Weak. It owns us as a listener.
nsCOMPtr<nsIFile> mTmpFile;
nsCOMPtr<nsIURI> mURL;
nsCOMPtr<nsIDOMDocument> mDocument;
nsCOMPtr<nsIInputStream> mPostData;
nsCString mDefaultFilename;
PRBool mBypassCache;
nsCString mContentType;
nsCString mContentDisposition;
NSView* mFilterView;
NSPopUpButton* mFilterList;
};
NS_IMPL_ISUPPORTS1(nsHeaderSniffer, nsIWebProgressListener)
// Implementation of nsIWebProgressListener
/* void onStateChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in long aStateFlags, in unsigned long aStatus); */
NS_IMETHODIMP
nsHeaderSniffer::OnStateChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, PRUint32 aStateFlags,
PRUint32 aStatus)
{
if (aStateFlags & nsIWebProgressListener::STATE_START) {
nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest));
channel->GetContentType(mContentType);
// 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);
PerformSave();
}
return NS_OK;
}
void nsHeaderSniffer::PerformSave()
{
// 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"));
if (!prefs)
return;
nsCOMPtr<nsIPrefBranch> dirBranch;
prefs->GetBranch("browser.download.", getter_AddRefs(dirBranch));
PRInt32 filterIndex = 0;
if (dirBranch) {
nsresult rv = dirBranch->GetIntPref("save_converter_index", &filterIndex);
if (NS_FAILED(rv))
filterIndex = 0;
}
if (mFilterList)
[mFilterList selectItemAtIndex: filterIndex];
// We need to figure out what file name to use.
nsCAutoString 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 = filename;
}
}
if (defaultFileName.IsEmpty()) {
nsCOMPtr<nsIURL> url(do_QueryInterface(mURL));
if (url)
url->GetFileName(defaultFileName); // (2) For file URLs, use the file name.
}
if (defaultFileName.IsEmpty() && mDocument && isHTML) {
nsCOMPtr<nsIDOMHTMLDocument> htmlDoc(do_QueryInterface(mDocument));
nsAutoString title;
if (htmlDoc)
htmlDoc->GetTitle(title); // (3) Use the title of the document.
defaultFileName.AssignWithConversion(title);
}
if (defaultFileName.IsEmpty()) {
// (4) Use the caller provided name.
defaultFileName = mDefaultFilename;
}
if (defaultFileName.IsEmpty() && mURL)
// (5) Use the host.
mURL->GetHost(defaultFileName);
// One last case to handle about:blank and other fruity untitled pages.
if (defaultFileName.IsEmpty())
defaultFileName = "untitled";
// Validate the file name to ensure legality.
for (PRUint32 i = 0; i < defaultFileName.Length(); i++)
if (defaultFileName[i] == ':' || defaultFileName[i] == '/')
defaultFileName.SetCharAt(i, ' ');
// 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));
if (!fileURL)
return;
fileURL->SetFilePath(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 += ".html";
setExtension = PR_TRUE;
}
}
if (!setExtension && fileExtension.IsEmpty()) {
nsCOMPtr<nsIMIMEService> mimeService(do_GetService("@mozilla.org/mime;1"));
if (!mimeService)
return;
nsCOMPtr<nsIMIMEInfo> mimeInfo;
mimeService->GetFromMIMEType(mContentType.get(), getter_AddRefs(mimeInfo));
if (!mimeInfo)
return;
PRUint32 extCount = 0;
char** extList = nsnull;
mimeInfo->GetFileExtensions(&extCount, &extList);
if (extCount > 0 && extList) {
defaultFileName += ".";
defaultFileName += extList[0];
}
}
// Now it's time to pose the save dialog.
NSSavePanel* savePanel = [NSSavePanel savePanel];
NSString* file = nil;
if (!defaultFileName.IsEmpty())
file = [[NSString alloc] initWithCString: defaultFileName.get()];
if (isHTML)
[savePanel setAccessoryView: mFilterView];
if ([savePanel runModalForDirectory: nil file: file] == NSFileHandlingPanelCancelButton)
return;
// Release the file string.
[file release];
// Update the filter index.
if (isHTML && mFilterList) {
filterIndex = [mFilterList indexOfSelectedItem];
dirBranch->SetIntPref("save_converter_index", filterIndex);
}
// Convert the content type to text/plain if it was selected in the filter.
if (isHTML && filterIndex == 2)
mContentType = "text/plain";
nsCOMPtr<nsISupports> sourceData;
if (isHTML && filterIndex != 1)
sourceData = do_QueryInterface(mDocument);
else
sourceData = do_QueryInterface(mURL);
nsCOMPtr<nsIWebBrowserPersist> webPersist(do_CreateInstance(persistContractID));
ProgressDlgController* progressDialog = [[ProgressDlgController alloc] initWithWindowNibName: @"ProgressDialog"];
[progressDialog setWebPersist: webPersist
source: sourceData.get()
destination: [savePanel filename]
contentType: mContentType.get()
postData: mPostData
bypassCache: mBypassCache];
[progressDialog showWindow: progressDialog];
}
/* void onProgressChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in long aCurSelfProgress, in long aMaxSelfProgress, in long aCurTotalProgress, in long aMaxTotalProgress); */
NS_IMETHODIMP
nsHeaderSniffer::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
nsHeaderSniffer::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
nsHeaderSniffer::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
nsHeaderSniffer::OnSecurityChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, PRUint32 state)
{
return NS_OK;
}
#pragma mark -
@implementation CHBrowserView
@ -1244,13 +980,17 @@ nsHeaderSniffer::OnSecurityChange(nsIWebProgress *aWebProgress, nsIRequest *aReq
shEntry->GetPostData(getter_AddRefs(postData));
}
// when saving, we first fire off a save with a nsHeaderSniffer as a progress
// listener. This allows us to look for the content-disposition header, which
// can supply a filename, and maybe has something to do with CGI-generated
// content (?)
nsCAutoString fileName(aFilename);
nsHeaderSniffer* sniffer = new nsHeaderSniffer(webPersist, tmpFile, aURI,
aDocument, postData, fileName, aBypassCache,
aFilterView, aFilterList);
if (!sniffer)
return;
webPersist->SetProgressListener(sniffer);
webPersist->SetProgressListener(sniffer); // owned
webPersist->SaveURI(aURI, nsnull, tmpFile);
}

Просмотреть файл

@ -89,8 +89,11 @@ app_getModuleInfo(nsStaticModuleInfo **info, PRUint32 *count);
nsresult rv;
ICStop (mInternetConfig);
nsCOMPtr<nsIPrefService> pref(do_GetService(NS_PREF_CONTRACTID, &rv));
if (!NS_FAILED(rv))
if (NS_SUCCEEDED(rv)) {
//NSLog(@"Saving prefs file");
pref->SavePrefFile(nsnull);
}
[super dealloc];
}

Просмотреть файл

@ -14,6 +14,7 @@
F512F52B02D1287F01072C9F,
F5A3669702CCFAF601DC3354,
F512F52C02D1287F01072C9F,
F50D9DE602ECC32301BB4219,
F512F52D02D1287F01072C9F,
);
isa = PBXGroup;
@ -471,6 +472,10 @@
F59236C202C89ACA0100012B,
F5A3669802CCFAF601DC3354,
F55C4DD402D2864E0130B065,
F50D9DE402ECC2C601BB4219,
F50D9DEF02EE0AB101BB4219,
F50D9DF302EE194001BB4219,
F50D9DF702EE2B9B01BB4219,
);
isa = PBXHeadersBuildPhase;
name = Headers;
@ -585,6 +590,10 @@
F53E012D02AEE93701A967F3,
F632AF8602B9AEBC01000103,
F59236C302C89ACA0100012B,
F50D9DE502ECC2C601BB4219,
F50D9DF002EE0AB101BB4219,
F50D9DF402EE194001BB4219,
F50D9DF802EE2B9B01BB4219,
);
isa = PBXSourcesBuildPhase;
name = Sources;
@ -840,6 +849,145 @@
name = Graphics;
refType = 4;
};
F50D9DE202ECC2C601BB4219 = {
isa = PBXFileReference;
path = nsDownloadListener.h;
refType = 4;
};
F50D9DE302ECC2C601BB4219 = {
isa = PBXFileReference;
path = nsDownloadListener.mm;
refType = 4;
};
F50D9DE402ECC2C601BB4219 = {
fileRef = F50D9DE202ECC2C601BB4219;
isa = PBXBuildFile;
settings = {
};
};
F50D9DE502ECC2C601BB4219 = {
fileRef = F50D9DE302ECC2C601BB4219;
isa = PBXBuildFile;
settings = {
};
};
F50D9DE602ECC32301BB4219 = {
children = (
F50D9DF902EE2C1D01BB4219,
F50D9DFA02EE2C1D01BB4219,
);
isa = PBXGroup;
name = Downloading;
path = "";
refType = 4;
};
F50D9DE702ECC36201BB4219 = {
fileRef = F50D9DE202ECC2C601BB4219;
isa = PBXBuildFile;
settings = {
};
};
F50D9DE802ECC36201BB4219 = {
fileRef = F632AF8302B9AEBB01000103;
isa = PBXBuildFile;
settings = {
};
};
F50D9DE902ECC36201BB4219 = {
fileRef = F50D9DE302ECC2C601BB4219;
isa = PBXBuildFile;
settings = {
};
};
F50D9DED02EE0AB101BB4219 = {
isa = PBXFileReference;
path = DownloadProgressDisplay.h;
refType = 4;
};
F50D9DEE02EE0AB101BB4219 = {
isa = PBXFileReference;
path = DownloadProgressDisplay.mm;
refType = 4;
};
F50D9DEF02EE0AB101BB4219 = {
fileRef = F50D9DED02EE0AB101BB4219;
isa = PBXBuildFile;
settings = {
};
};
F50D9DF002EE0AB101BB4219 = {
fileRef = F50D9DEE02EE0AB101BB4219;
isa = PBXBuildFile;
settings = {
};
};
F50D9DF102EE194001BB4219 = {
isa = PBXFileReference;
path = DownloadFactories.h;
refType = 4;
};
F50D9DF202EE194001BB4219 = {
isa = PBXFileReference;
path = DownloadFactories.mm;
refType = 4;
};
F50D9DF302EE194001BB4219 = {
fileRef = F50D9DF102EE194001BB4219;
isa = PBXBuildFile;
settings = {
};
};
F50D9DF402EE194001BB4219 = {
fileRef = F50D9DF202EE194001BB4219;
isa = PBXBuildFile;
settings = {
};
};
F50D9DF502EE2B9A01BB4219 = {
isa = PBXFileReference;
path = SaveHeaderSniffer.h;
refType = 4;
};
F50D9DF602EE2B9A01BB4219 = {
isa = PBXFileReference;
path = SaveHeaderSniffer.mm;
refType = 4;
};
F50D9DF702EE2B9B01BB4219 = {
fileRef = F50D9DF502EE2B9A01BB4219;
isa = PBXBuildFile;
settings = {
};
};
F50D9DF802EE2B9B01BB4219 = {
fileRef = F50D9DF602EE2B9A01BB4219;
isa = PBXBuildFile;
settings = {
};
};
F50D9DF902EE2C1D01BB4219 = {
children = (
F50D9DF102EE194001BB4219,
F50D9DF202EE194001BB4219,
F50D9DED02EE0AB101BB4219,
F50D9DEE02EE0AB101BB4219,
);
isa = PBXGroup;
name = Generic;
refType = 4;
};
F50D9DFA02EE2C1D01BB4219 = {
children = (
F50D9DF502EE2B9A01BB4219,
F50D9DF602EE2B9A01BB4219,
F517395B020CE3740189DA0C,
F50D9DE302ECC2C601BB4219,
);
isa = PBXGroup;
name = Chimera;
path = "";
refType = 4;
};
F50DCB4302C2856001A967F3 = {
isa = PBXFileReference;
name = libjsj.dylib;
@ -1143,7 +1291,6 @@
F512F52B02D1287F01072C9F = {
children = (
F5DE10E90209DC0601A967DF,
F517395B020CE3740189DA0C,
F528E21A020FD9620168DE43,
);
isa = PBXGroup;
@ -1176,7 +1323,6 @@
};
F512F53302D17A2601072C9F = {
children = (
F55C4DD302D2864D0130B065,
29B97316FDCFA39411CA2CEA,
F59236C002C89AC90100012B,
F5AE04BA0206A4FE01A967DF,
@ -1330,6 +1476,7 @@
F507BA480213AD5F01D93544,
F57074B5026BA85F01A80166,
F57074B9026BFD0101A80166,
2EEC3E61028138714B000102,
F57074BD026D80DF01A80166,
2E293A00027F33604B000102,
F5607CB5023944AD01A967DF,
@ -1344,6 +1491,8 @@
F53E013202AEEA2801A967F3,
F5A3669302CCFAF601DC3354,
F59236C102C89AC90100012B,
F50D9DE202ECC2C601BB4219,
F55C4DD302D2864D0130B065,
);
isa = PBXGroup;
name = Headers;
@ -4375,7 +4524,6 @@
F57074B6026BA85F01A80166,
F57074BA026BFD0101A80166,
F53E012C02AEE93601A967F3,
2EEC3E61028138714B000102,
2EEC3E62028138714B000102,
);
isa = PBXGroup;
@ -4959,6 +5107,8 @@
F53E013402AEEA2901A967F3,
F59236C402C89ACA0100012B,
F5A3669A02CCFB7A01DC3354,
F50D9DE702ECC36201BB4219,
F50D9DE802ECC36201BB4219,
);
isa = PBXHeadersBuildPhase;
name = Headers;
@ -5074,6 +5224,7 @@
F59236C502C89ACA0100012B,
F5A3669B02CCFB7A01DC3354,
F5A3669C02CCFB7A01DC3354,
F50D9DE902ECC36201BB4219,
);
isa = PBXSourcesBuildPhase;
name = Sources;

Просмотреть файл

120
camino/DownloadFactories.mm Normal file
Просмотреть файл

@ -0,0 +1,120 @@
/* ***** 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):
* 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 ***** */
// This file contains implementations of factories for various
// downloading-related interfaces.
#import "DownloadProgressDisplay.h"
#import "ProgressDlgController.h"
#include "nsCOMPtr.h"
#include "nsIFactory.h"
#include "nsDownloadListener.h"
#include "DownloadFactories.h"
// factory for nsIDownload objects
// XXX replace with generic factory stuff
class DownloadListenerFactory : public nsIFactory
{
public:
DownloadListenerFactory();
virtual ~DownloadListenerFactory();
NS_DECL_ISUPPORTS
NS_DECL_NSIFACTORY
protected:
DownloadControllerFactory* mControllerFactory; // factory which creates the Cocoa window controller
};
DownloadListenerFactory::DownloadListenerFactory()
: mControllerFactory(nil)
{
NS_INIT_ISUPPORTS();
mControllerFactory = [[[ChimeraDownloadControllerFactory alloc] init] retain];
}
DownloadListenerFactory::~DownloadListenerFactory()
{
[mControllerFactory release];
}
NS_IMPL_ISUPPORTS1(DownloadListenerFactory, nsIFactory);
/* void createInstance (in nsISupports aOuter, in nsIIDRef iid, [iid_is (iid), retval] out nsQIResult result); */
NS_IMETHODIMP
DownloadListenerFactory::CreateInstance(nsISupports *aOuter, const nsIID& aIID, void* *aResult)
{
nsresult rv;
if (aIID.Equals(NS_GET_IID(nsIDownload)))
{
nsDownloadListener* downloadListener = new nsDownloadListener(mControllerFactory);
if (!downloadListener) return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(downloadListener);
rv = downloadListener->QueryInterface(aIID, aResult);
NS_RELEASE(downloadListener);
return rv;
}
return NS_ERROR_NO_INTERFACE;
}
/* void lockFactory (in PRBool lock); */
NS_IMETHODIMP
DownloadListenerFactory::LockFactory(PRBool lock)
{
return NS_OK;
}
#pragma mark -
nsresult NewDownloadListenerFactory(nsIFactory* *outFactory)
{
DownloadListenerFactory* newFactory = new DownloadListenerFactory();
if (!newFactory) return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(newFactory);
nsresult rv = newFactory->QueryInterface(NS_GET_IID(nsIFactory), (void **)outFactory);
NS_RELEASE(newFactory);
return rv;
}

Просмотреть файл

@ -0,0 +1,161 @@
/* ***** 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):
* 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 ***** */
/*
The classes and protocol in this file allow Cocoa applications to easily
reuse the underlying download implementation, which deals with the complexity
of Gecko's downloading callbacks.
There are three things here:
1. The DownloadProgressDisplay protocol.
This is a formal protocol that needs to be implemented by
a window controller for your progress window. Its methods
will be called by the underlying C++ downloading classes.
2. The Obj-C DownloadControllerFactory class.
This class should be subclassed by an embedder, with an
implementation of 'createDownloadController' that hands back
a new instance of an NSWindowController that implements the
<DownloadProgressDisplay> protocol.
The underlying C++ classes use this factory to create the
progress window controller.
3. The nsDownloader C++ class
This base class exists to hide the complextity of the download
listener classes (which deal with Gecko callbacks) from the
window controller. Embedders don't need to do anything with it.
How these classes fit together:
There are 2 ways in which a download is initiated:
(i) File->Save.
Chimera does a complex dance here in order to get certain
information about the data being downloaded (it needs to
start the download before it can read some optional MIME headers).
CBrowserView creates an nsIWebBrowserPersist (WBP), and then a
nsHeaderSniffer, which implements nsIWebProgressListener and is set to
observer the WBP. When nsHeaderSniffer hears about the start of the
download, it decides on a file name, and what format to save the data
in. It then cancels the current WPB, makes another one, and does
a CreateInstance of an nsIDownload (making one of our nsDownloadListener
-- aka nsDownloder -- objects), and sets that as the nsIWebProgressListener.
The full download procedes from there.
(ii) Click to download (e.g. FTP link)
This is simpler. The backend (necko) does the CreateInstance of the
nsIDownload, and the download progresses.
In both cases, creating the nsDownloadListener and calling its Init() method
calls nsDownloder::CreateDownloadDisplay(). The nsDownloder has as a member
variable a DownloadControllerFactory (see above), which got passed to it
via our XPCOM factory for nsIDownload objects. It then uses that DownloadControllerFactory
to get an instance of the download progress window controller, which then
shows the download progress window.
Simple, eh?
*/
#import <AppKit/AppKit.h>
#include "nsISupports.h"
class nsDownloader;
// a formal protocol for something that implements progress display
// Embedders can make a window controller that conforms to this
// protocol, and reuse nsDownloadListener to get download UI.
@protocol DownloadProgressDisplay
- (void)onStartDownload;
- (void)onEndDownload;
- (void)setProgressTo:(long)aCurProgress ofMax:(long)aMaxProgress;
- (void)setDownloadListener:(nsDownloader*)aDownloader;
- (void)setSourceURL:(NSString*)aSourceURL;
- (void)setDestinationPath:(NSString*)aDestPath;
@end
// subclass this, and have your subclass instantiate and return your window
// controller in createDownloadController
@interface DownloadControllerFactory : NSObject
{
}
- (NSWindowController<DownloadProgressDisplay> *)createDownloadController;
@end
// Pure virtual base class for a generic downloader, that the progress UI can talk to.
// It implements nsISupports so that it can be refcounted. This class insulates the
// UI code from having to know too much about the nsIDownloadListener.
// It is responsible for creating the download UI, via the DownloadControllerFactory
// that it owns.
class nsDownloader : public nsISupports
{
public:
nsDownloader(DownloadControllerFactory* inControllerFactory);
virtual ~nsDownloader();
NS_DECL_ISUPPORTS
virtual void PauseDownload() = 0;
virtual void ResumeDownload() = 0;
virtual void CancelDownload() = 0;
virtual void DownloadDone() = 0;
virtual void CreateDownloadDisplay();
protected:
DownloadControllerFactory* mControllerFactory;
id <DownloadProgressDisplay> mDownloadDisplay; // something that implements the DownloadProgressDisplay protocol
};

Просмотреть файл

@ -0,0 +1,75 @@
/* ***** 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):
* 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 ***** */
#import "DownloadProgressDisplay.h"
@implementation DownloadControllerFactory
- (NSWindowController<DownloadProgressDisplay> *)createDownloadController
{
// a dummy implementation. You should provide a subclass that
// returns an instance of your progress dialog controller.
return nil;
}
@end
#pragma mark -
// see the header file for comments
nsDownloader::nsDownloader(DownloadControllerFactory* inControllerFactory)
: mControllerFactory(inControllerFactory)
, mDownloadDisplay(nil)
{
NS_INIT_ISUPPORTS();
[mControllerFactory retain];
}
nsDownloader::~nsDownloader()
{
[mControllerFactory release];
}
NS_IMPL_ISUPPORTS1(nsDownloader, nsISupports);
void
nsDownloader::CreateDownloadDisplay()
{
mDownloadDisplay = [mControllerFactory createDownloadController];
[mDownloadDisplay setDownloadListener:this];
}

6
camino/English.lproj/MainMenu.nib/info.nib сгенерированный
Просмотреть файл

@ -3,13 +3,13 @@
<plist version="0.9">
<dict>
<key>IBDocumentLocation</key>
<string>73 360 356 240 0 0 1152 848 </string>
<string>61 108 356 240 0 0 1152 746 </string>
<key>IBEditorPositions</key>
<dict>
<key>266</key>
<string>418 452 277 90 0 0 1152 746 </string>
<string>23 342 277 90 0 0 1152 746 </string>
<key>29</key>
<string>8 803 446 44 0 0 1152 848 </string>
<string>8 701 446 44 0 0 1152 746 </string>
</dict>
<key>IBFramework Version</key>
<string>248.0</string>

Двоичные данные
camino/English.lproj/MainMenu.nib/objects.nib сгенерированный

Двоичный файл не отображается.

19
camino/English.lproj/ProgressDialog.nib/classes.nib сгенерированный
Просмотреть файл

@ -1,19 +0,0 @@
{
IBClasses = (
{CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; },
{
CLASS = ProgressDlgController;
LANGUAGE = ObjC;
OUTLETS = {
mElapsedTimeLabel = id;
mFromField = id;
mProgressBar = id;
mStatusLabel = id;
mTimeLeftLabel = id;
mToField = id;
};
SUPERCLASS = NSWindowController;
}
);
IBVersion = 1;
}

4
camino/English.lproj/ProgressDialog.nib/info.nib сгенерированный
Просмотреть файл

@ -3,7 +3,7 @@
<plist version="0.9">
<dict>
<key>IBDocumentLocation</key>
<string>152 212 356 240 0 0 1024 746 </string>
<string>94 26 404 250 0 0 1152 746 </string>
<key>IBFramework Version</key>
<string>248.0</string>
<key>IBOpenObjects</key>
@ -11,6 +11,6 @@
<integer>5</integer>
</array>
<key>IBSystem Version</key>
<string>5Q125</string>
<string>5S66</string>
</dict>
</plist>

Двоичные данные
camino/English.lproj/ProgressDialog.nib/objects.nib сгенерированный

Двоичный файл не отображается.

6
camino/MainMenu.nib/info.nib сгенерированный
Просмотреть файл

@ -3,13 +3,13 @@
<plist version="0.9">
<dict>
<key>IBDocumentLocation</key>
<string>73 360 356 240 0 0 1152 848 </string>
<string>61 108 356 240 0 0 1152 746 </string>
<key>IBEditorPositions</key>
<dict>
<key>266</key>
<string>418 452 277 90 0 0 1152 746 </string>
<string>23 342 277 90 0 0 1152 746 </string>
<key>29</key>
<string>8 803 446 44 0 0 1152 848 </string>
<string>8 701 446 44 0 0 1152 746 </string>
</dict>
<key>IBFramework Version</key>
<string>248.0</string>

Двоичные данные
camino/MainMenu.nib/objects.nib сгенерированный

Двоичный файл не отображается.

19
camino/ProgressDialog.nib/classes.nib сгенерированный
Просмотреть файл

@ -1,19 +0,0 @@
{
IBClasses = (
{CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; },
{
CLASS = ProgressDlgController;
LANGUAGE = ObjC;
OUTLETS = {
mElapsedTimeLabel = id;
mFromField = id;
mProgressBar = id;
mStatusLabel = id;
mTimeLeftLabel = id;
mToField = id;
};
SUPERCLASS = NSWindowController;
}
);
IBVersion = 1;
}

4
camino/ProgressDialog.nib/info.nib сгенерированный
Просмотреть файл

@ -3,7 +3,7 @@
<plist version="0.9">
<dict>
<key>IBDocumentLocation</key>
<string>152 212 356 240 0 0 1024 746 </string>
<string>94 26 404 250 0 0 1152 746 </string>
<key>IBFramework Version</key>
<string>248.0</string>
<key>IBOpenObjects</key>
@ -11,6 +11,6 @@
<integer>5</integer>
</array>
<key>IBSystem Version</key>
<string>5Q125</string>
<string>5S66</string>
</dict>
</plist>

Двоичные данные
camino/ProgressDialog.nib/objects.nib сгенерированный

Двоичный файл не отображается.

Просмотреть файл

@ -36,6 +36,9 @@
* ***** END LICENSE BLOCK ***** */
#import <AppKit/AppKit.h>
#import "DownloadProgressDisplay.h"
#include "nscore.h"
class nsIWebBrowserPersist;
@ -43,42 +46,37 @@ class nsISupports;
class nsIInputStream;
class nsDownloadListener;
@interface ProgressDlgController : NSWindowController {
IBOutlet id mFromField;
IBOutlet id mToField;
IBOutlet id mStatusLabel;
IBOutlet id mTimeLeftLabel;
IBOutlet id mElapsedTimeLabel;
IBOutlet id mProgressBar;
@interface ChimeraDownloadControllerFactory : DownloadControllerFactory
@end
@interface ProgressDlgController : NSWindowController <DownloadProgressDisplay>
{
IBOutlet NSTextField *mElapsedTimeLabel;
IBOutlet NSTextField *mFromField;
IBOutlet NSTextField *mStatusLabel;
IBOutlet NSTextField *mTimeLeftLabel;
IBOutlet NSTextField *mToField;
IBOutlet NSProgressIndicator *mProgressBar;
NSToolbarItem *pauseResumeToggleToolbarItem;
NSToolbarItem *leaveOpenToggleToolbarItem;
BOOL mDownloadIsPaused;
BOOL mSaveFileDialogShouldStayOpen;
BOOL mDownloadIsComplete;
long int aCurrentProgress; // if progress bar is indeterminate, can still calc stats.
BOOL mDownloadIsPaused;
BOOL mSaveFileDialogShouldStayOpen;
BOOL mDownloadIsComplete;
long mCurrentProgress; // if progress bar is indeterminate, can still calc stats.
nsDownloadListener* mDownloadListener;
NSTimer *mDownloadTimer;
nsDownloader *mDownloader; // we hold a ref to this
NSTimer *mDownloadTimer;
}
-(void) setWebPersist: (nsIWebBrowserPersist*)aPersist
source: (nsISupports*)aSource
destination: (NSString*)aDestination
contentType: (const char*)aContentType
postData: (nsIInputStream*)aInputStream
bypassCache: (BOOL)aBypassCache;
-(void) setProgressBar:(long int)aCurProgress
maxProg:(long int)aMaxProgress;
-(void) setDownloadTimer;
-(void) setupDownloadTimer;
-(void) killDownloadTimer;
-(void) setDownloadProgress:(NSTimer *)aTimer;
-(NSString *) formatTime:(int)aSeconds;
-(NSString *) formatFuzzyTime:(int)aSeconds;
-(NSString *) formatBytes:(float)aBytes;
-(void) setSourceURL: (const PRUnichar*)aSource;
-(void) setDestination: (const PRUnichar*)aDestination;
@end

Просмотреть файл

@ -46,282 +46,58 @@
#include "nsILocalFile.h"
#include "nsIDOMHTMLDocument.h"
#include "nsIWebProgressListener.h"
#include "nsIDownload.h"
#include "nsIComponentManager.h"
#include "nsIPref.h"
class nsDownloadListener : public nsIWebProgressListener
{
public:
nsDownloadListener(ProgressDlgController* aController,
nsIWebBrowserPersist* aPersist,
nsISupports* aSource,
NSString* aDestination,
const char* aContentType,
nsIInputStream* aPostData,
BOOL aBypassCache)
{
NS_INIT_ISUPPORTS();
mController = aController;
mWebPersist = aPersist;
// The source is either a simple URL or a complete document.
mURL = do_QueryInterface(aSource);
if (!mURL)
mDocument = do_QueryInterface(aSource);
PRUint32 dstLen = [aDestination length];
PRUnichar* tmp = new PRUnichar[dstLen + sizeof(PRUnichar)];
tmp[dstLen] = (PRUnichar)'\0';
[aDestination getCharacters:tmp];
nsAutoString dstStr(tmp);
delete tmp;
NS_NewLocalFile(dstStr, PR_FALSE, getter_AddRefs(mDestination));
// XXX check for failure
mContentType = aContentType;
mPostData = aPostData;
mBypassCache = aBypassCache;
mNetworkTransfer = PR_FALSE;
mGotFirstStateChange = PR_FALSE;
};
virtual ~nsDownloadListener() {};
NS_DECL_ISUPPORTS
NS_DECL_NSIWEBPROGRESSLISTENER
public:
void BeginDownload();
void InitDialog();
void CancelDownload();
private: // Member variables
ProgressDlgController* mController; // Controller for our UI.
nsCOMPtr<nsIWebBrowserPersist> mWebPersist; // Our web persist object.
nsCOMPtr<nsIURL> mURL; // The URL of our source file. Null if we're saving a complete document.
nsCOMPtr<nsILocalFile> mDestination; // Our destination URL.
nsCString mContentType; // Our content type string.
nsCOMPtr<nsIDOMHTMLDocument> mDocument; // A DOM document. Null if we're only saving a simple URL.
nsCOMPtr<nsIInputStream> mPostData; // For complete documents, this is our post data from session history.
PRPackedBool mBypassCache; // Whether we should bypass the cache or not.
PRPackedBool mNetworkTransfer; // true if the first OnStateChange has the NETWORK bit set
PRPackedBool mGotFirstStateChange; // true after we've seen the first OnStateChange
};
NS_IMPL_ISUPPORTS1(nsDownloadListener, nsIWebProgressListener)
/* void onProgressChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in long aCurSelfProgress, in long aMaxSelfProgress, in long aCurTotalProgress, in long aMaxTotalProgress); */
NS_IMETHODIMP
nsDownloadListener::OnProgressChange(nsIWebProgress *aWebProgress,
nsIRequest *aRequest,
PRInt32 aCurSelfProgress,
PRInt32 aMaxSelfProgress,
PRInt32 aCurTotalProgress,
PRInt32 aMaxTotalProgress)
{
[mController setProgressBar:aCurTotalProgress maxProg:aMaxTotalProgress];
return NS_OK;
}
/* void onLocationChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in nsIURI location); */
NS_IMETHODIMP
nsDownloadListener::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
nsDownloadListener::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
nsDownloadListener::OnSecurityChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, PRUint32 state)
{
return NS_OK;
}
// Implementation of nsIWebProgressListener
/* void onStateChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in unsigned long aStateFlags, in unsigned long aStatus); */
NS_IMETHODIMP
nsDownloadListener::OnStateChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, PRUint32 aStateFlags,
PRUint32 aStatus)
{
// NSLog(@"State changed: state %u, status %u", aStateFlags, aStatus);
if (!mGotFirstStateChange) {
mNetworkTransfer = ((aStateFlags & STATE_IS_NETWORK) != 0);
mGotFirstStateChange = PR_TRUE;
}
// when the entire download finishes, stop the progress timer and clean up
// the window and controller. We will get this even in the event of a cancel,
// so this is the only place in the listener where we should kill the download.
if ((aStateFlags & STATE_STOP) && (!mNetworkTransfer || (aStateFlags & STATE_IS_NETWORK))) {
[mController killDownloadTimer];
[mController setDownloadProgress:nil];
}
return NS_OK;
}
void
nsDownloadListener::BeginDownload()
{
if (mWebPersist) {
mWebPersist->SetProgressListener(this);
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;
if (mURL)
mWebPersist->SaveURI(mURL, mPostData, mDestination);
else {
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;
mDestination->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)
filesFolder->Create(nsILocalFile::DIRECTORY_TYPE, 0755);
}
else
encodingFlags |= nsIWebBrowserPersist::ENCODE_FLAGS_FORMATTED |
nsIWebBrowserPersist::ENCODE_FLAGS_ABSOLUTE_LINKS |
nsIWebBrowserPersist::ENCODE_FLAGS_NOFRAMES_CONTENT;
mWebPersist->SaveDocument(mDocument, mDestination, filesFolder, mContentType.get(),
encodingFlags, 80);
}
}
InitDialog();
}
void
nsDownloadListener::InitDialog()
{
if (!mURL && !mDocument)
return;
if (mWebPersist) {
if (mURL) {
nsCAutoString spec;
mURL->GetSpec(spec);
nsAutoString spec2; spec2.AssignWithConversion(spec.get());
[mController setSourceURL: spec2.get()];
}
else {
nsAutoString spec;
mDocument->GetURL(spec);
[mController setSourceURL: spec.get()];
}
}
nsAutoString pathStr;
mDestination->GetPath(pathStr);
[mController setDestination: pathStr.get()];
[mController setDownloadTimer];
}
void
nsDownloadListener::CancelDownload()
{
if (mWebPersist)
mWebPersist->CancelSave();
}
static NSString *SaveFileToolbarIdentifier = @"Save File Dialog Toolbar";
static NSString *CancelToolbarItemIdentifier = @"Cancel Toolbar Item";
static NSString *SaveFileToolbarIdentifier = @"Save File Dialog Toolbar";
static NSString *CancelToolbarItemIdentifier = @"Cancel Toolbar Item";
static NSString *PauseResumeToolbarItemIdentifier = @"Pause and Resume Toggle Toolbar Item";
static NSString *ShowFileToolbarItemIdentifier = @"Show File Toolbar Item";
static NSString *OpenFileToolbarItemIdentifier = @"Open File Toolbar Item";
static NSString *LeaveOpenToolbarItemIdentifier = @"Leave Open Toggle Toolbar Item";
@implementation ChimeraDownloadControllerFactory : DownloadControllerFactory
- (NSWindowController<DownloadProgressDisplay> *)createDownloadController
{
NSWindowController* progressController = [[ProgressDlgController alloc] initWithWindowNibName: @"ProgressDialog"];
NSAssert([progressController conformsToProtocol:@protocol(DownloadProgressDisplay)],
@"progressController should conform to DownloadProgressDisplay protocol");
return progressController;
}
@end
#pragma mark -
@interface ProgressDlgController(Private)
-(void)setupToolbar;
@end
@implementation ProgressDlgController
-(void)setWebPersist:(nsIWebBrowserPersist*)aPersist
source:(nsISupports*)aSource
destination:(NSString*)aDestination
contentType:(const char*)aContentType
postData:(nsIInputStream*)aInputStream
bypassCache:(BOOL)aBypassCache
- (void)dealloc
{
mDownloadListener = new nsDownloadListener(self, aPersist, aSource,
aDestination, aContentType,
aInputStream, aBypassCache);
NS_ADDREF(mDownloadListener);
}
-(void) setProgressBar:(long int)curProgress maxProg:(long int)maxProgress
{
aCurrentProgress = curProgress; // fall back for stat calcs
if (![mProgressBar isIndeterminate]) { //most likely - just update value
if (curProgress == maxProgress) //handles little bug in FTP download size
[mProgressBar setMaxValue:maxProgress];
[mProgressBar setDoubleValue:curProgress];
}
else if (maxProgress > 0) { // ok, we're starting up with good max & cur values
[mProgressBar setIndeterminate:NO];
[mProgressBar setMaxValue:maxProgress];
[mProgressBar setDoubleValue:curProgress];
} // if neither case was true, it's barber pole city.
}
-(void) setSourceURL: (const PRUnichar*)aSource
{
[mFromField setStringValue: [NSString stringWithCharacters:aSource length:nsCRT::strlen(aSource)]];
}
-(void) setDestination: (const PRUnichar*)aDestination
{
[mToField setStringValue: [[NSString stringWithCharacters:aDestination length:nsCRT::strlen(aDestination)] stringByAbbreviatingWithTildeInPath]];
NS_IF_RELEASE(mDownloader);
[super dealloc];
}
- (void)windowDidLoad
{
mDownloadIsPaused = NO;
mDownloadIsComplete = NO;
nsCOMPtr<nsIPref> prefs(do_GetService(NS_PREF_CONTRACTID));
PRBool save = PR_FALSE;
prefs->GetBoolPref("browser.download.progressDnldDialog.keepAlive",&save);
prefs->GetBoolPref("browser.download.progressDnldDialog.keepAlive", &save);
mSaveFileDialogShouldStayOpen = save;
[self setupToolbar];
[mProgressBar setUsesThreadedAnimation:YES];
[mProgressBar startAnimation:self];
if (mDownloadListener)
mDownloadListener->BeginDownload();
[mProgressBar startAnimation:self]; // move to onStateChange
}
- (void)setupToolbar
@ -438,7 +214,9 @@ static NSString *LeaveOpenToolbarItemIdentifier = @"Leave Open Toggle Toolbar
-(void)cancel
{
mDownloadListener->CancelDownload();
if (mDownloader) // we should always have one
mDownloader->CancelDownload();
// clean up downloaded file. - do it here on in CancelDownload?
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *thePath = [[mToField stringValue] stringByExpandingTildeInPath];
@ -457,22 +235,29 @@ static NSString *LeaveOpenToolbarItemIdentifier = @"Leave Open Toggle Toolbar
-(void)pauseAndResumeDownload
{
if ( ! mDownloadIsPaused ) {
//Do logic to pause download
if ( !mDownloadIsPaused )
{
mDownloadIsPaused = YES;
[pauseResumeToggleToolbarItem setLabel:@"Resume"];
[pauseResumeToggleToolbarItem setPaletteLabel:@"Resume Download"];
[pauseResumeToggleToolbarItem setToolTip:@"Resume the paused FTP download"];
[pauseResumeToggleToolbarItem setImage:[NSImage imageNamed:@"saveResume"]];
[self killDownloadTimer];
} else {
//Do logic to resume download
if (mDownloader) // we should always have one
mDownloader->PauseDownload();
}
else
{
mDownloadIsPaused = NO;
[pauseResumeToggleToolbarItem setLabel:@"Pause"];
[pauseResumeToggleToolbarItem setPaletteLabel:@"Pause Download"];
[pauseResumeToggleToolbarItem setToolTip:@"Pause this FTP file download"];
[pauseResumeToggleToolbarItem setImage:[NSImage imageNamed:@"savePause"]];
[self setDownloadTimer];
[self setupDownloadTimer];
if (mDownloader) // we should always have one
mDownloader->ResumeDownload();
}
}
@ -531,12 +316,6 @@ static NSString *LeaveOpenToolbarItemIdentifier = @"Leave Open Toggle Toolbar
return YES;
}
- (void)dealloc
{
NS_IF_RELEASE(mDownloadListener);
[super dealloc];
}
- (void)killDownloadTimer
{
if (mDownloadTimer) {
@ -545,7 +324,7 @@ static NSString *LeaveOpenToolbarItemIdentifier = @"Leave Open Toggle Toolbar
mDownloadTimer = nil;
}
}
- (void)setDownloadTimer
- (void)setupDownloadTimer
{
[self killDownloadTimer];
mDownloadTimer = [[NSTimer scheduledTimerWithTimeInterval:1.0
@ -590,7 +369,7 @@ static NSString *LeaveOpenToolbarItemIdentifier = @"Leave Open Toggle Toolbar
return [[[NSString alloc] initWithString:[[NSBundle mainBundle] localizedStringForKey:@"UnderMin" value:@"Under a minute" table:@"ProgressDialog"]] autorelease];
}
// seconds becomes minutes and we keep checking.
seconds=seconds/60;
seconds = seconds/60;
if (seconds < 60) {
if (seconds < 2)
return [[[NSString alloc] initWithString:[[NSBundle mainBundle] localizedStringForKey:@"AboutMin" value:@"About a minute" table:@"ProgressDialog"]] autorelease];
@ -598,7 +377,7 @@ static NSString *LeaveOpenToolbarItemIdentifier = @"Leave Open Toggle Toolbar
return [[[NSString alloc] initWithFormat:[[NSBundle mainBundle] localizedStringForKey:@"AboutMins" value:@"About %d minutes" table:@"ProgressDialog"],seconds] autorelease];
}
//this download will never seemingly never end. now seconds become hours.
seconds=seconds/60;
seconds = seconds/60;
if (seconds < 2)
return [[[NSString alloc] initWithString:[[NSBundle mainBundle] localizedStringForKey:@"AboutHour" value:@"Over an hour" table:@"ProgressDialog"]] autorelease];
return [[[NSString alloc] initWithFormat:[[NSBundle mainBundle] localizedStringForKey:@"AboutHours" value:@"Over %d hours" table:@"ProgressDialog"],seconds] autorelease];
@ -629,8 +408,11 @@ static NSString *LeaveOpenToolbarItemIdentifier = @"Leave Open Toggle Toolbar
// this handles lots of things.
- (void)setDownloadProgress:(NSTimer *)downloadTimer;
{
// XXX this logic needs cleaning up.
// Ack! we're closing the window with the download still running!
if (mDownloadIsComplete) {
if (mDownloadIsComplete)
{
[[self window] performClose:self];
return;
}
@ -644,26 +426,28 @@ static NSString *LeaveOpenToolbarItemIdentifier = @"Leave Open Toggle Toolbar
[mElapsedTimeLabel setStringValue:[self formatTime:(++elapsedSec)]];
// for status field & time left
float maxBytes = ([mProgressBar maxValue]);
float byteSec = aCurrentProgress/elapsedSec;
float byteSec = mCurrentProgress/elapsedSec;
// OK - if downloadTimer is nil, we're done - fix maxBytes value for status report.
if (!downloadTimer)
maxBytes = aCurrentProgress;
maxBytes = mCurrentProgress;
// update status field
NSString *labelString = [[NSBundle mainBundle] localizedStringForKey:@"LabelString"
value:@"%@ of %@ total (at %@/sec)"
table:@"ProgressDialog"];
[mStatusLabel setStringValue: [NSString stringWithFormat:labelString, [self formatBytes:aCurrentProgress], [self formatBytes:maxBytes], [self formatBytes:byteSec]]];
[mStatusLabel setStringValue: [NSString stringWithFormat:labelString, [self formatBytes:mCurrentProgress], [self formatBytes:maxBytes], [self formatBytes:byteSec]]];
// updating estimated time left field
// if maxBytes < 0, can't calc time left.
// if !downloadTimer, download is finished. either way, make sure time left is 0.
if ((maxBytes > 0) && (downloadTimer)) {
int secToGo = (int)ceil((elapsedSec*maxBytes/aCurrentProgress)-elapsedSec);
if ((maxBytes > 0) && (downloadTimer))
{
int secToGo = (int)ceil((elapsedSec*maxBytes/mCurrentProgress) - elapsedSec);
[mTimeLeftLabel setStringValue:[self formatFuzzyTime:secToGo]];
}
else if (!downloadTimer) { // download done. Set remaining time to 0, fix progress bar & cancel button
else if (!downloadTimer)
{ // download done. Set remaining time to 0, fix progress bar & cancel button
mDownloadIsComplete = YES; // all done. we got a STATE_STOP
[mTimeLeftLabel setStringValue:@""];
[self setProgressBar:aCurrentProgress maxProg:aCurrentProgress];
[self setProgressTo:mCurrentProgress ofMax:mCurrentProgress];
if (!mSaveFileDialogShouldStayOpen)
[[self window] performClose:self]; // close window
else
@ -673,4 +457,59 @@ static NSString *LeaveOpenToolbarItemIdentifier = @"Leave Open Toggle Toolbar
[mTimeLeftLabel setStringValue:@"???"];
}
#pragma mark -
// DownloadProgressDisplay protocol methods
- (void)onStartDownload
{
[self showWindow: self];
[self setupDownloadTimer];
}
- (void)onEndDownload
{
[self killDownloadTimer];
[self setDownloadProgress:nil];
}
- (void)setProgressTo:(long)aCurProgress ofMax:(long)aMaxProgress
{
mCurrentProgress = aCurProgress; // fall back for stat calcs
if (![mProgressBar isIndeterminate]) //most likely - just update value
{
if (aCurProgress == aMaxProgress) //handles little bug in FTP download size
[mProgressBar setMaxValue:aMaxProgress];
[mProgressBar setDoubleValue:aCurProgress];
}
else if (aMaxProgress > 0) // ok, we're starting up with good max & cur values
{
[mProgressBar setIndeterminate:NO];
[mProgressBar setMaxValue:aMaxProgress];
[mProgressBar setDoubleValue:aCurProgress];
} // if neither case was true, it's barber pole city.
}
-(void) setDownloadListener: (nsDownloader*)aDownloader
{
if (mDownloader != aDownloader)
NS_IF_RELEASE(mDownloader);
NS_IF_ADDREF(mDownloader = aDownloader);
}
- (void)setSourceURL:(NSString*)aSourceURL
{
[mFromField setStringValue: aSourceURL];
[mFromField display]; // force an immmeditate update
}
- (void)setDestinationPath:(NSString*)aDestPath
{
[mToField setStringValue: [aDestPath stringByAbbreviatingWithTildeInPath]];
[mToField display]; // force an immmeditate update
}
@end

Просмотреть файл

Просмотреть файл

Просмотреть файл

@ -55,7 +55,7 @@ class nsCocoaBrowserService : public nsIWindowCreator,
public nsIPromptService,
public nsIFactory,
public nsIBadCertListener, public nsISecurityWarningDialogs, public nsINSSDialogs,
public nsIHelperAppLauncherDialog, public nsIDownload, public nsIWebProgressListener
public nsIHelperAppLauncherDialog
{
public:
nsCocoaBrowserService();
@ -69,8 +69,6 @@ public:
NS_DECL_NSIBADCERTLISTENER
NS_DECL_NSISECURITYWARNINGDIALOGS
NS_DECL_NSIHELPERAPPLAUNCHERDIALOG
NS_DECL_NSIDOWNLOAD
NS_DECL_NSIWEBPROGRESSLISTENER
static nsresult InitEmbedding();
static void TermEmbedding();

Просмотреть файл

@ -35,14 +35,15 @@
*
* ***** END LICENSE BLOCK ***** */
#include "nsCocoaBrowserService.h"
#import "nsCocoaBrowserService.h"
#import "DownloadFactories.h"
#import "CHBrowserView.h"
#include "nsIWindowWatcher.h"
#include "nsIWebBrowserChrome.h"
#include "nsIEmbeddingSiteWindow.h"
#include "nsIProfile.h"
#include "nsIPrefService.h"
#include "CHBrowserView.h"
#include "nsCRT.h"
#include "nsString.h"
#include "nsIPrompt.h"
@ -74,13 +75,14 @@ nsCocoaBrowserService::~nsCocoaBrowserService()
{
}
NS_IMPL_ISUPPORTS9(nsCocoaBrowserService,
NS_IMPL_ISUPPORTS7(nsCocoaBrowserService,
nsIWindowCreator,
nsIPromptService,
nsIFactory,
nsIBadCertListener, nsISecurityWarningDialogs, nsINSSDialogs,
nsIHelperAppLauncherDialog, nsIDownload, nsIWebProgressListener)
nsIHelperAppLauncherDialog)
/* static */
nsresult
nsCocoaBrowserService::InitEmbedding()
{
@ -103,7 +105,7 @@ nsCocoaBrowserService::InitEmbedding()
#define NS_PROMPTSERVICE_CID \
{0xa2112d6a, 0x0e28, 0x421f, {0xb4, 0x6a, 0x25, 0xc0, 0xb3, 0x8, 0xcb, 0xd0}}
static NS_DEFINE_CID(kPromptServiceCID, NS_PROMPTSERVICE_CID);
nsresult rv = cr->RegisterFactory(kPromptServiceCID, "Prompt Service", "@mozilla.org/embedcomp/prompt-service;1",
nsresult rv = cr->RegisterFactory(kPromptServiceCID, "Prompt Service", "@mozilla.org/embedcomp/prompt-service;1",
sSingleton);
if (NS_FAILED(rv))
return rv;
@ -127,14 +129,18 @@ nsCocoaBrowserService::InitEmbedding()
rv = cr->RegisterFactory(kHelperDlgCID, NS_IHELPERAPPLAUNCHERDLG_CLASSNAME, NS_IHELPERAPPLAUNCHERDLG_CONTRACTID,
sSingleton);
// replace the downloader with our own which does rely on the xpfe downlaod manager
// replace the downloader with our own which does not rely on the xpfe downlaod manager
nsCOMPtr<nsIFactory> downloadFactory;
rv = NewDownloadListenerFactory(getter_AddRefs(downloadFactory));
if (NS_FAILED(rv)) return rv;
static NS_DEFINE_CID(kDownloadCID, NS_DOWNLOAD_CID);
rv = cr->RegisterFactory(kDownloadCID, "Download", NS_DOWNLOAD_CONTRACTID,
sSingleton);
rv = cr->RegisterFactory(kDownloadCID, "Download", NS_DOWNLOAD_CONTRACTID, downloadFactory);
return rv;
}
/* static */
void
nsCocoaBrowserService::BrowserClosed()
{
@ -149,6 +155,7 @@ nsCocoaBrowserService::BrowserClosed()
}
}
/* static */
void
nsCocoaBrowserService::TermEmbedding()
{
@ -195,8 +202,15 @@ nsCocoaBrowserService::CreateInstance(nsISupports *aOuter,
const nsIID & aIID,
void **aResult)
{
NS_ENSURE_ARG_POINTER(aResult);
/*
if (aIID.Equals(NS_GET_IID(nsIHelperAppLauncherDialog)))
{
}
*/
return sSingleton->QueryInterface(aIID, aResult);
}
@ -828,14 +842,12 @@ nsCocoaBrowserService::ConfirmPostToInsecureFromSecure(nsIInterfaceRequestor *ct
NS_IMETHODIMP
nsCocoaBrowserService::Show(nsIHelperAppLauncher* inLauncher, nsISupports* inContext)
{
NSLog(@"Show");
return inLauncher->SaveToDisk(nsnull, PR_FALSE);
}
NS_IMETHODIMP
nsCocoaBrowserService::PromptForSaveToFile(nsISupports *aWindowContext, const PRUnichar *aDefaultFile, const PRUnichar *aSuggestedFileExtension, nsILocalFile **_retval)
{
NSLog(@"PromptForSaveToFile");
NSString* filename = [NSString stringWithCharacters:aDefaultFile length:nsCRT::strlen(aDefaultFile)];
NSSavePanel *thePanel = [NSSavePanel savePanel];
@ -844,7 +856,7 @@ NSLog(@"PromptForSaveToFile");
// use nil for the path given to runModalForDirectory
int runResult = [thePanel runModalForDirectory: nil file:filename];
if (runResult == NSOKButton) {
NSLog([thePanel filename]);
// NSLog(@"Saving to %@", [thePanel filename]);
NSString *theName = [thePanel filename];
return NS_NewNativeLocalFile(nsDependentCString([theName fileSystemRepresentation]), PR_FALSE, _retval);
}
@ -856,140 +868,6 @@ NSLog([thePanel filename]);
NS_IMETHODIMP
nsCocoaBrowserService::ShowProgressDialog(nsIHelperAppLauncher *aLauncher, nsISupports *aContext)
{
return NS_OK;
}
NS_IMETHODIMP
nsCocoaBrowserService::Init(nsIURI* aSource,
nsILocalFile* aTarget,
const PRUnichar* aDisplayName,
const PRUnichar* aOpeningWith,
PRInt64 aStartTime,
nsIWebBrowserPersist* aPersist)
{
NSLog(@"nsIDownload::Init");
return NS_OK;
}
NS_IMETHODIMP
nsCocoaBrowserService::GetDisplayName(PRUnichar** aDisplayName)
{
NS_ERROR("NS_ERROR_NOT_IMPLEMENTED");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsCocoaBrowserService::SetDisplayName(const PRUnichar* aDisplayName)
{
return NS_OK;
}
NS_IMETHODIMP
nsCocoaBrowserService::GetOpeningWith(PRUnichar** aOpeningWith)
{
NS_ERROR("NS_ERROR_NOT_IMPLEMENTED");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsCocoaBrowserService::GetSource(nsIURI** aSource)
{
NS_ERROR("NS_ERROR_NOT_IMPLEMENTED");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsCocoaBrowserService::GetTarget(nsILocalFile** aTarget)
{
NS_ERROR("NS_ERROR_NOT_IMPLEMENTED");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsCocoaBrowserService::GetStartTime(PRInt64* aStartTime)
{
NS_ERROR("NS_ERROR_NOT_IMPLEMENTED");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsCocoaBrowserService::GetPercentComplete(PRInt32* aPercentComplete)
{
NS_ERROR("NS_ERROR_NOT_IMPLEMENTED");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsCocoaBrowserService::GetListener(nsIWebProgressListener** aListener)
{
NS_ERROR("NS_ERROR_NOT_IMPLEMENTED");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsCocoaBrowserService::SetListener(nsIWebProgressListener* aListener)
{
return NS_OK;
}
NS_IMETHODIMP
nsCocoaBrowserService::GetObserver(nsIObserver** aObserver)
{
NS_ERROR("NS_ERROR_NOT_IMPLEMENTED");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsCocoaBrowserService::SetObserver(nsIObserver* aObserver)
{
return NS_OK;
}
NS_IMETHODIMP
nsCocoaBrowserService::GetPersist(nsIWebBrowserPersist** aPersist)
{
NS_ERROR("NS_ERROR_NOT_IMPLEMENTED");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsCocoaBrowserService::OnStateChange(nsIWebProgress* aWebProgress,
nsIRequest* aRequest, PRUint32 aStateFlags,
PRUint32 aStatus)
{
return NS_OK;
}
NS_IMETHODIMP
nsCocoaBrowserService::OnStatusChange(nsIWebProgress *aWebProgress,
nsIRequest *aRequest, nsresult aStatus,
const PRUnichar *aMessage)
{
return NS_OK;
}
NS_IMETHODIMP
nsCocoaBrowserService::OnLocationChange(nsIWebProgress *aWebProgress,
nsIRequest *aRequest, nsIURI *aLocation)
{
return NS_OK;
}
NS_IMETHODIMP
nsCocoaBrowserService::OnProgressChange(nsIWebProgress *aWebProgress,
nsIRequest *aRequest,
PRInt32 aCurSelfProgress,
PRInt32 aMaxSelfProgress,
PRInt32 aCurTotalProgress,
PRInt32 aMaxTotalProgress)
{
return NS_OK;
}
NS_IMETHODIMP
nsCocoaBrowserService::OnSecurityChange(nsIWebProgress *aWebProgress,
nsIRequest *aRequest, PRUint32 aState)
{
NSLog(@"nsCocoaBrowserService::ShowProgressDialog");
return NS_OK;
}

Просмотреть файл

@ -0,0 +1,88 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Netscape 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/NPL/
*
* 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):
* 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 NPL, 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 NPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#import <Foundation/Foundation.h>
#import <Appkit/Appkit.h>
#import "DownloadProgressDisplay.h"
#include "nsString.h"
#include "nsIDownload.h"
#include "nsIWebProgressListener.h"
#include "nsIWebBrowserPersist.h"
#include "nsIURI.h"
#include "nsILocalFile.h"
// maybe this should replace nsHeaderSniffer too?
class nsDownloadListener : public nsDownloader,
public nsIDownload,
public nsIWebProgressListener
{
public:
nsDownloadListener(DownloadControllerFactory* inDownloadControllerFactory);
virtual ~nsDownloadListener();
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSIDOWNLOAD
NS_DECL_NSIWEBPROGRESSLISTENER
public:
//void BeginDownload();
void InitDialog();
virtual void PauseDownload();
virtual void ResumeDownload();
virtual void CancelDownload();
virtual void DownloadDone();
private:
nsCOMPtr<nsIWebBrowserPersist> mWebPersist; // Our web persist object.
nsCOMPtr<nsIURI> mURI; // The URI of our source file. Null if we're saving a complete document.
nsCOMPtr<nsILocalFile> mDestination; // Our destination URL.
PRInt64 mStartTime; // When the download started
PRPackedBool mBypassCache; // Whether we should bypass the cache or not.
PRPackedBool mNetworkTransfer; // true if the first OnStateChange has the NETWORK bit set
PRPackedBool mGotFirstStateChange; // true after we've seen the first OnStateChange
PRPackedBool mUserCanceled; // true if the user canceled the download
};

Просмотреть файл

@ -0,0 +1,308 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Netscape 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/NPL/
*
* 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):
* 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 NPL, 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 NPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsDownloadListener.h"
#include "nsIWebProgress.h"
#include "nsIRequest.h"
#include "nsIURL.h"
#include "netCore.h"
nsDownloadListener::nsDownloadListener(DownloadControllerFactory* inControllerFactory)
: nsDownloader(inControllerFactory)
, mBypassCache(PR_FALSE)
, mNetworkTransfer(PR_FALSE)
, mGotFirstStateChange(PR_FALSE)
, mUserCanceled(PR_FALSE)
{
}
nsDownloadListener::~nsDownloadListener()
{
}
NS_IMPL_ISUPPORTS_INHERITED2(nsDownloadListener, nsDownloader, nsIDownload, nsIWebProgressListener)
#pragma mark -
/* void init (in nsIURI aSource, in nsILocalFile aTarget, in wstring aDisplayName, in wstring openingWith, in long long startTime, in nsIWebBrowserPersist aPersist); */
NS_IMETHODIMP
nsDownloadListener::Init(nsIURI *aSource, nsILocalFile *aTarget, const PRUnichar *aDisplayName,
const PRUnichar *openingWith, PRInt64 startTime, nsIWebBrowserPersist *aPersist)
{
CreateDownloadDisplay(); // call the base class to make the download UI
if (aPersist) // only true for File->Save As.
{
mWebPersist = aPersist;
mWebPersist->SetProgressListener(this); // we form a cycle here, since we're a listener.
// we'll break this cycle in DownloadDone()
}
mDestination = aTarget;
mURI = aSource;
mStartTime = startTime;
InitDialog();
return NS_OK;
}
/* readonly attribute nsIURI source; */
NS_IMETHODIMP
nsDownloadListener::GetSource(nsIURI * *aSource)
{
NS_ENSURE_ARG_POINTER(aSource);
NS_IF_ADDREF(*aSource = mURI);
return NS_OK;
}
/* readonly attribute nsILocalFile target; */
NS_IMETHODIMP
nsDownloadListener::GetTarget(nsILocalFile * *aTarget)
{
NS_ENSURE_ARG_POINTER(aTarget);
NS_IF_ADDREF(*aTarget = mDestination);
return NS_OK;
}
/* readonly attribute nsIWebBrowserPersist persist; */
NS_IMETHODIMP
nsDownloadListener::GetPersist(nsIWebBrowserPersist * *aPersist)
{
NS_ENSURE_ARG_POINTER(aPersist);
NS_IF_ADDREF(*aPersist = mWebPersist);
return NS_OK;
}
/* readonly attribute PRInt32 percentComplete; */
NS_IMETHODIMP
nsDownloadListener::GetPercentComplete(PRInt32 *aPercentComplete)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
/* attribute wstring displayName; */
NS_IMETHODIMP
nsDownloadListener::GetDisplayName(PRUnichar * *aDisplayName)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsDownloadListener::SetDisplayName(const PRUnichar * aDisplayName)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
/* readonly attribute long long startTime; */
NS_IMETHODIMP
nsDownloadListener::GetStartTime(PRInt64 *aStartTime)
{
NS_ENSURE_ARG(aStartTime);
*aStartTime = mStartTime;
return NS_OK;
}
/* readonly attribute wstring openingWith; */
NS_IMETHODIMP
nsDownloadListener::GetOpeningWith(PRUnichar * *aOpeningWith)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
/* attribute nsIWebProgressListener listener; */
NS_IMETHODIMP
nsDownloadListener::GetListener(nsIWebProgressListener * *aListener)
{
NS_ENSURE_ARG_POINTER(aListener);
NS_IF_ADDREF(*aListener = (nsIWebProgressListener *)this);
return NS_OK;
}
NS_IMETHODIMP
nsDownloadListener::SetListener(nsIWebProgressListener * aListener)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
/* attribute nsIObserver observer; */
NS_IMETHODIMP
nsDownloadListener::GetObserver(nsIObserver * *aObserver)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsDownloadListener::SetObserver(nsIObserver * aObserver)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
#pragma mark -
/* void onProgressChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in long aCurSelfProgress, in long aMaxSelfProgress, in long aCurTotalProgress, in long aMaxTotalProgress); */
NS_IMETHODIMP
nsDownloadListener::OnProgressChange(nsIWebProgress *aWebProgress,
nsIRequest *aRequest,
PRInt32 aCurSelfProgress,
PRInt32 aMaxSelfProgress,
PRInt32 aCurTotalProgress,
PRInt32 aMaxTotalProgress)
{
if (mUserCanceled)
{
if (aRequest)
aRequest->Cancel(NS_BINDING_ABORTED);
mUserCanceled = false;
}
[mDownloadDisplay setProgressTo:aCurTotalProgress ofMax:aMaxTotalProgress];
return NS_OK;
}
/* void onLocationChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in nsIURI location); */
NS_IMETHODIMP
nsDownloadListener::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
nsDownloadListener::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
nsDownloadListener::OnSecurityChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, PRUint32 state)
{
return NS_OK;
}
// Implementation of nsIWebProgressListener
/* void onStateChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in unsigned long aStateFlags, in unsigned long aStatus); */
NS_IMETHODIMP
nsDownloadListener::OnStateChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, PRUint32 aStateFlags,
PRUint32 aStatus)
{
// NSLog(@"State changed: state %u, status %u", aStateFlags, aStatus);
if (!mGotFirstStateChange) {
mNetworkTransfer = ((aStateFlags & STATE_IS_NETWORK) != 0);
mGotFirstStateChange = PR_TRUE;
}
// when the entire download finishes, stop the progress timer and clean up
// the window and controller. We will get this even in the event of a cancel,
// so this is the only place in the listener where we should kill the download.
if ((aStateFlags & STATE_STOP) && (!mNetworkTransfer || (aStateFlags & STATE_IS_NETWORK))) {
DownloadDone();
}
return NS_OK;
}
#pragma mark -
void
nsDownloadListener::InitDialog()
{
// dialog has to be shown before the outlets get hooked up
[mDownloadDisplay onStartDownload];
if (mURI)
{
nsCAutoString spec;
mURI->GetSpec(spec);
[mDownloadDisplay setSourceURL: [NSString stringWithUTF8String:spec.get()]];
}
nsAutoString pathStr;
mDestination->GetPath(pathStr);
[mDownloadDisplay setDestinationPath: [NSString stringWithCharacters:pathStr.get() length:pathStr.Length()]];
}
void
nsDownloadListener::PauseDownload()
{
// write me
}
void
nsDownloadListener::ResumeDownload()
{
// write me
}
void
nsDownloadListener::CancelDownload()
{
mUserCanceled = PR_TRUE;
if (mWebPersist)
{
mWebPersist->CancelSave();
mUserCanceled = PR_FALSE;
}
// delete any files we've created...
}
void
nsDownloadListener::DownloadDone()
{
// break the reference cycle by removing ourselves as a listener
if (mWebPersist)
{
mWebPersist->SetProgressListener(nsnull);
mWebPersist = nsnull;
}
[mDownloadDisplay onEndDownload];
}
#pragma mark -

Просмотреть файл

@ -14,6 +14,7 @@
F512F52B02D1287F01072C9F,
F5A3669702CCFAF601DC3354,
F512F52C02D1287F01072C9F,
F50D9DE602ECC32301BB4219,
F512F52D02D1287F01072C9F,
);
isa = PBXGroup;
@ -471,6 +472,10 @@
F59236C202C89ACA0100012B,
F5A3669802CCFAF601DC3354,
F55C4DD402D2864E0130B065,
F50D9DE402ECC2C601BB4219,
F50D9DEF02EE0AB101BB4219,
F50D9DF302EE194001BB4219,
F50D9DF702EE2B9B01BB4219,
);
isa = PBXHeadersBuildPhase;
name = Headers;
@ -585,6 +590,10 @@
F53E012D02AEE93701A967F3,
F632AF8602B9AEBC01000103,
F59236C302C89ACA0100012B,
F50D9DE502ECC2C601BB4219,
F50D9DF002EE0AB101BB4219,
F50D9DF402EE194001BB4219,
F50D9DF802EE2B9B01BB4219,
);
isa = PBXSourcesBuildPhase;
name = Sources;
@ -840,6 +849,145 @@
name = Graphics;
refType = 4;
};
F50D9DE202ECC2C601BB4219 = {
isa = PBXFileReference;
path = nsDownloadListener.h;
refType = 4;
};
F50D9DE302ECC2C601BB4219 = {
isa = PBXFileReference;
path = nsDownloadListener.mm;
refType = 4;
};
F50D9DE402ECC2C601BB4219 = {
fileRef = F50D9DE202ECC2C601BB4219;
isa = PBXBuildFile;
settings = {
};
};
F50D9DE502ECC2C601BB4219 = {
fileRef = F50D9DE302ECC2C601BB4219;
isa = PBXBuildFile;
settings = {
};
};
F50D9DE602ECC32301BB4219 = {
children = (
F50D9DF902EE2C1D01BB4219,
F50D9DFA02EE2C1D01BB4219,
);
isa = PBXGroup;
name = Downloading;
path = "";
refType = 4;
};
F50D9DE702ECC36201BB4219 = {
fileRef = F50D9DE202ECC2C601BB4219;
isa = PBXBuildFile;
settings = {
};
};
F50D9DE802ECC36201BB4219 = {
fileRef = F632AF8302B9AEBB01000103;
isa = PBXBuildFile;
settings = {
};
};
F50D9DE902ECC36201BB4219 = {
fileRef = F50D9DE302ECC2C601BB4219;
isa = PBXBuildFile;
settings = {
};
};
F50D9DED02EE0AB101BB4219 = {
isa = PBXFileReference;
path = DownloadProgressDisplay.h;
refType = 4;
};
F50D9DEE02EE0AB101BB4219 = {
isa = PBXFileReference;
path = DownloadProgressDisplay.mm;
refType = 4;
};
F50D9DEF02EE0AB101BB4219 = {
fileRef = F50D9DED02EE0AB101BB4219;
isa = PBXBuildFile;
settings = {
};
};
F50D9DF002EE0AB101BB4219 = {
fileRef = F50D9DEE02EE0AB101BB4219;
isa = PBXBuildFile;
settings = {
};
};
F50D9DF102EE194001BB4219 = {
isa = PBXFileReference;
path = DownloadFactories.h;
refType = 4;
};
F50D9DF202EE194001BB4219 = {
isa = PBXFileReference;
path = DownloadFactories.mm;
refType = 4;
};
F50D9DF302EE194001BB4219 = {
fileRef = F50D9DF102EE194001BB4219;
isa = PBXBuildFile;
settings = {
};
};
F50D9DF402EE194001BB4219 = {
fileRef = F50D9DF202EE194001BB4219;
isa = PBXBuildFile;
settings = {
};
};
F50D9DF502EE2B9A01BB4219 = {
isa = PBXFileReference;
path = SaveHeaderSniffer.h;
refType = 4;
};
F50D9DF602EE2B9A01BB4219 = {
isa = PBXFileReference;
path = SaveHeaderSniffer.mm;
refType = 4;
};
F50D9DF702EE2B9B01BB4219 = {
fileRef = F50D9DF502EE2B9A01BB4219;
isa = PBXBuildFile;
settings = {
};
};
F50D9DF802EE2B9B01BB4219 = {
fileRef = F50D9DF602EE2B9A01BB4219;
isa = PBXBuildFile;
settings = {
};
};
F50D9DF902EE2C1D01BB4219 = {
children = (
F50D9DF102EE194001BB4219,
F50D9DF202EE194001BB4219,
F50D9DED02EE0AB101BB4219,
F50D9DEE02EE0AB101BB4219,
);
isa = PBXGroup;
name = Generic;
refType = 4;
};
F50D9DFA02EE2C1D01BB4219 = {
children = (
F50D9DF502EE2B9A01BB4219,
F50D9DF602EE2B9A01BB4219,
F517395B020CE3740189DA0C,
F50D9DE302ECC2C601BB4219,
);
isa = PBXGroup;
name = Chimera;
path = "";
refType = 4;
};
F50DCB4302C2856001A967F3 = {
isa = PBXFileReference;
name = libjsj.dylib;
@ -1143,7 +1291,6 @@
F512F52B02D1287F01072C9F = {
children = (
F5DE10E90209DC0601A967DF,
F517395B020CE3740189DA0C,
F528E21A020FD9620168DE43,
);
isa = PBXGroup;
@ -1176,7 +1323,6 @@
};
F512F53302D17A2601072C9F = {
children = (
F55C4DD302D2864D0130B065,
29B97316FDCFA39411CA2CEA,
F59236C002C89AC90100012B,
F5AE04BA0206A4FE01A967DF,
@ -1330,6 +1476,7 @@
F507BA480213AD5F01D93544,
F57074B5026BA85F01A80166,
F57074B9026BFD0101A80166,
2EEC3E61028138714B000102,
F57074BD026D80DF01A80166,
2E293A00027F33604B000102,
F5607CB5023944AD01A967DF,
@ -1344,6 +1491,8 @@
F53E013202AEEA2801A967F3,
F5A3669302CCFAF601DC3354,
F59236C102C89AC90100012B,
F50D9DE202ECC2C601BB4219,
F55C4DD302D2864D0130B065,
);
isa = PBXGroup;
name = Headers;
@ -4375,7 +4524,6 @@
F57074B6026BA85F01A80166,
F57074BA026BFD0101A80166,
F53E012C02AEE93601A967F3,
2EEC3E61028138714B000102,
2EEC3E62028138714B000102,
);
isa = PBXGroup;
@ -4959,6 +5107,8 @@
F53E013402AEEA2901A967F3,
F59236C402C89ACA0100012B,
F5A3669A02CCFB7A01DC3354,
F50D9DE702ECC36201BB4219,
F50D9DE802ECC36201BB4219,
);
isa = PBXHeadersBuildPhase;
name = Headers;
@ -5074,6 +5224,7 @@
F59236C502C89ACA0100012B,
F5A3669B02CCFB7A01DC3354,
F5A3669C02CCFB7A01DC3354,
F50D9DE902ECC36201BB4219,
);
isa = PBXSourcesBuildPhase;
name = Sources;

Просмотреть файл

@ -3,13 +3,13 @@
<plist version="0.9">
<dict>
<key>IBDocumentLocation</key>
<string>73 360 356 240 0 0 1152 848 </string>
<string>61 108 356 240 0 0 1152 746 </string>
<key>IBEditorPositions</key>
<dict>
<key>266</key>
<string>418 452 277 90 0 0 1152 746 </string>
<string>23 342 277 90 0 0 1152 746 </string>
<key>29</key>
<string>8 803 446 44 0 0 1152 848 </string>
<string>8 701 446 44 0 0 1152 746 </string>
</dict>
<key>IBFramework Version</key>
<string>248.0</string>

Двоичные данные
camino/resources/localized/English.lproj/MainMenu.nib/objects.nib сгенерированный

Двоичный файл не отображается.

Просмотреть файл

@ -5,12 +5,12 @@
CLASS = ProgressDlgController;
LANGUAGE = ObjC;
OUTLETS = {
mElapsedTimeLabel = id;
mFromField = id;
mProgressBar = id;
mStatusLabel = id;
mTimeLeftLabel = id;
mToField = id;
mElapsedTimeLabel = NSTextField;
mFromField = NSTextField;
mProgressBar = NSProgressIndicator;
mStatusLabel = NSTextField;
mTimeLeftLabel = NSTextField;
mToField = NSTextField;
};
SUPERCLASS = NSWindowController;
}

Просмотреть файл

@ -3,7 +3,7 @@
<plist version="0.9">
<dict>
<key>IBDocumentLocation</key>
<string>152 212 356 240 0 0 1024 746 </string>
<string>94 26 404 250 0 0 1152 746 </string>
<key>IBFramework Version</key>
<string>248.0</string>
<key>IBOpenObjects</key>
@ -11,6 +11,6 @@
<integer>5</integer>
</array>
<key>IBSystem Version</key>
<string>5Q125</string>
<string>5S66</string>
</dict>
</plist>

Двоичные данные
camino/resources/localized/English.lproj/ProgressDialog.nib/objects.nib сгенерированный

Двоичный файл не отображается.

Просмотреть файл

@ -36,6 +36,9 @@
* ***** END LICENSE BLOCK ***** */
#import <AppKit/AppKit.h>
#import "DownloadProgressDisplay.h"
#include "nscore.h"
class nsIWebBrowserPersist;
@ -43,42 +46,37 @@ class nsISupports;
class nsIInputStream;
class nsDownloadListener;
@interface ProgressDlgController : NSWindowController {
IBOutlet id mFromField;
IBOutlet id mToField;
IBOutlet id mStatusLabel;
IBOutlet id mTimeLeftLabel;
IBOutlet id mElapsedTimeLabel;
IBOutlet id mProgressBar;
@interface ChimeraDownloadControllerFactory : DownloadControllerFactory
@end
@interface ProgressDlgController : NSWindowController <DownloadProgressDisplay>
{
IBOutlet NSTextField *mElapsedTimeLabel;
IBOutlet NSTextField *mFromField;
IBOutlet NSTextField *mStatusLabel;
IBOutlet NSTextField *mTimeLeftLabel;
IBOutlet NSTextField *mToField;
IBOutlet NSProgressIndicator *mProgressBar;
NSToolbarItem *pauseResumeToggleToolbarItem;
NSToolbarItem *leaveOpenToggleToolbarItem;
BOOL mDownloadIsPaused;
BOOL mSaveFileDialogShouldStayOpen;
BOOL mDownloadIsComplete;
long int aCurrentProgress; // if progress bar is indeterminate, can still calc stats.
BOOL mDownloadIsPaused;
BOOL mSaveFileDialogShouldStayOpen;
BOOL mDownloadIsComplete;
long mCurrentProgress; // if progress bar is indeterminate, can still calc stats.
nsDownloadListener* mDownloadListener;
NSTimer *mDownloadTimer;
nsDownloader *mDownloader; // we hold a ref to this
NSTimer *mDownloadTimer;
}
-(void) setWebPersist: (nsIWebBrowserPersist*)aPersist
source: (nsISupports*)aSource
destination: (NSString*)aDestination
contentType: (const char*)aContentType
postData: (nsIInputStream*)aInputStream
bypassCache: (BOOL)aBypassCache;
-(void) setProgressBar:(long int)aCurProgress
maxProg:(long int)aMaxProgress;
-(void) setDownloadTimer;
-(void) setupDownloadTimer;
-(void) killDownloadTimer;
-(void) setDownloadProgress:(NSTimer *)aTimer;
-(NSString *) formatTime:(int)aSeconds;
-(NSString *) formatFuzzyTime:(int)aSeconds;
-(NSString *) formatBytes:(float)aBytes;
-(void) setSourceURL: (const PRUnichar*)aSource;
-(void) setDestination: (const PRUnichar*)aDestination;
@end

Просмотреть файл

@ -46,282 +46,58 @@
#include "nsILocalFile.h"
#include "nsIDOMHTMLDocument.h"
#include "nsIWebProgressListener.h"
#include "nsIDownload.h"
#include "nsIComponentManager.h"
#include "nsIPref.h"
class nsDownloadListener : public nsIWebProgressListener
{
public:
nsDownloadListener(ProgressDlgController* aController,
nsIWebBrowserPersist* aPersist,
nsISupports* aSource,
NSString* aDestination,
const char* aContentType,
nsIInputStream* aPostData,
BOOL aBypassCache)
{
NS_INIT_ISUPPORTS();
mController = aController;
mWebPersist = aPersist;
// The source is either a simple URL or a complete document.
mURL = do_QueryInterface(aSource);
if (!mURL)
mDocument = do_QueryInterface(aSource);
PRUint32 dstLen = [aDestination length];
PRUnichar* tmp = new PRUnichar[dstLen + sizeof(PRUnichar)];
tmp[dstLen] = (PRUnichar)'\0';
[aDestination getCharacters:tmp];
nsAutoString dstStr(tmp);
delete tmp;
NS_NewLocalFile(dstStr, PR_FALSE, getter_AddRefs(mDestination));
// XXX check for failure
mContentType = aContentType;
mPostData = aPostData;
mBypassCache = aBypassCache;
mNetworkTransfer = PR_FALSE;
mGotFirstStateChange = PR_FALSE;
};
virtual ~nsDownloadListener() {};
NS_DECL_ISUPPORTS
NS_DECL_NSIWEBPROGRESSLISTENER
public:
void BeginDownload();
void InitDialog();
void CancelDownload();
private: // Member variables
ProgressDlgController* mController; // Controller for our UI.
nsCOMPtr<nsIWebBrowserPersist> mWebPersist; // Our web persist object.
nsCOMPtr<nsIURL> mURL; // The URL of our source file. Null if we're saving a complete document.
nsCOMPtr<nsILocalFile> mDestination; // Our destination URL.
nsCString mContentType; // Our content type string.
nsCOMPtr<nsIDOMHTMLDocument> mDocument; // A DOM document. Null if we're only saving a simple URL.
nsCOMPtr<nsIInputStream> mPostData; // For complete documents, this is our post data from session history.
PRPackedBool mBypassCache; // Whether we should bypass the cache or not.
PRPackedBool mNetworkTransfer; // true if the first OnStateChange has the NETWORK bit set
PRPackedBool mGotFirstStateChange; // true after we've seen the first OnStateChange
};
NS_IMPL_ISUPPORTS1(nsDownloadListener, nsIWebProgressListener)
/* void onProgressChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in long aCurSelfProgress, in long aMaxSelfProgress, in long aCurTotalProgress, in long aMaxTotalProgress); */
NS_IMETHODIMP
nsDownloadListener::OnProgressChange(nsIWebProgress *aWebProgress,
nsIRequest *aRequest,
PRInt32 aCurSelfProgress,
PRInt32 aMaxSelfProgress,
PRInt32 aCurTotalProgress,
PRInt32 aMaxTotalProgress)
{
[mController setProgressBar:aCurTotalProgress maxProg:aMaxTotalProgress];
return NS_OK;
}
/* void onLocationChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in nsIURI location); */
NS_IMETHODIMP
nsDownloadListener::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
nsDownloadListener::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
nsDownloadListener::OnSecurityChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, PRUint32 state)
{
return NS_OK;
}
// Implementation of nsIWebProgressListener
/* void onStateChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in unsigned long aStateFlags, in unsigned long aStatus); */
NS_IMETHODIMP
nsDownloadListener::OnStateChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, PRUint32 aStateFlags,
PRUint32 aStatus)
{
// NSLog(@"State changed: state %u, status %u", aStateFlags, aStatus);
if (!mGotFirstStateChange) {
mNetworkTransfer = ((aStateFlags & STATE_IS_NETWORK) != 0);
mGotFirstStateChange = PR_TRUE;
}
// when the entire download finishes, stop the progress timer and clean up
// the window and controller. We will get this even in the event of a cancel,
// so this is the only place in the listener where we should kill the download.
if ((aStateFlags & STATE_STOP) && (!mNetworkTransfer || (aStateFlags & STATE_IS_NETWORK))) {
[mController killDownloadTimer];
[mController setDownloadProgress:nil];
}
return NS_OK;
}
void
nsDownloadListener::BeginDownload()
{
if (mWebPersist) {
mWebPersist->SetProgressListener(this);
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;
if (mURL)
mWebPersist->SaveURI(mURL, mPostData, mDestination);
else {
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;
mDestination->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)
filesFolder->Create(nsILocalFile::DIRECTORY_TYPE, 0755);
}
else
encodingFlags |= nsIWebBrowserPersist::ENCODE_FLAGS_FORMATTED |
nsIWebBrowserPersist::ENCODE_FLAGS_ABSOLUTE_LINKS |
nsIWebBrowserPersist::ENCODE_FLAGS_NOFRAMES_CONTENT;
mWebPersist->SaveDocument(mDocument, mDestination, filesFolder, mContentType.get(),
encodingFlags, 80);
}
}
InitDialog();
}
void
nsDownloadListener::InitDialog()
{
if (!mURL && !mDocument)
return;
if (mWebPersist) {
if (mURL) {
nsCAutoString spec;
mURL->GetSpec(spec);
nsAutoString spec2; spec2.AssignWithConversion(spec.get());
[mController setSourceURL: spec2.get()];
}
else {
nsAutoString spec;
mDocument->GetURL(spec);
[mController setSourceURL: spec.get()];
}
}
nsAutoString pathStr;
mDestination->GetPath(pathStr);
[mController setDestination: pathStr.get()];
[mController setDownloadTimer];
}
void
nsDownloadListener::CancelDownload()
{
if (mWebPersist)
mWebPersist->CancelSave();
}
static NSString *SaveFileToolbarIdentifier = @"Save File Dialog Toolbar";
static NSString *CancelToolbarItemIdentifier = @"Cancel Toolbar Item";
static NSString *SaveFileToolbarIdentifier = @"Save File Dialog Toolbar";
static NSString *CancelToolbarItemIdentifier = @"Cancel Toolbar Item";
static NSString *PauseResumeToolbarItemIdentifier = @"Pause and Resume Toggle Toolbar Item";
static NSString *ShowFileToolbarItemIdentifier = @"Show File Toolbar Item";
static NSString *OpenFileToolbarItemIdentifier = @"Open File Toolbar Item";
static NSString *LeaveOpenToolbarItemIdentifier = @"Leave Open Toggle Toolbar Item";
@implementation ChimeraDownloadControllerFactory : DownloadControllerFactory
- (NSWindowController<DownloadProgressDisplay> *)createDownloadController
{
NSWindowController* progressController = [[ProgressDlgController alloc] initWithWindowNibName: @"ProgressDialog"];
NSAssert([progressController conformsToProtocol:@protocol(DownloadProgressDisplay)],
@"progressController should conform to DownloadProgressDisplay protocol");
return progressController;
}
@end
#pragma mark -
@interface ProgressDlgController(Private)
-(void)setupToolbar;
@end
@implementation ProgressDlgController
-(void)setWebPersist:(nsIWebBrowserPersist*)aPersist
source:(nsISupports*)aSource
destination:(NSString*)aDestination
contentType:(const char*)aContentType
postData:(nsIInputStream*)aInputStream
bypassCache:(BOOL)aBypassCache
- (void)dealloc
{
mDownloadListener = new nsDownloadListener(self, aPersist, aSource,
aDestination, aContentType,
aInputStream, aBypassCache);
NS_ADDREF(mDownloadListener);
}
-(void) setProgressBar:(long int)curProgress maxProg:(long int)maxProgress
{
aCurrentProgress = curProgress; // fall back for stat calcs
if (![mProgressBar isIndeterminate]) { //most likely - just update value
if (curProgress == maxProgress) //handles little bug in FTP download size
[mProgressBar setMaxValue:maxProgress];
[mProgressBar setDoubleValue:curProgress];
}
else if (maxProgress > 0) { // ok, we're starting up with good max & cur values
[mProgressBar setIndeterminate:NO];
[mProgressBar setMaxValue:maxProgress];
[mProgressBar setDoubleValue:curProgress];
} // if neither case was true, it's barber pole city.
}
-(void) setSourceURL: (const PRUnichar*)aSource
{
[mFromField setStringValue: [NSString stringWithCharacters:aSource length:nsCRT::strlen(aSource)]];
}
-(void) setDestination: (const PRUnichar*)aDestination
{
[mToField setStringValue: [[NSString stringWithCharacters:aDestination length:nsCRT::strlen(aDestination)] stringByAbbreviatingWithTildeInPath]];
NS_IF_RELEASE(mDownloader);
[super dealloc];
}
- (void)windowDidLoad
{
mDownloadIsPaused = NO;
mDownloadIsComplete = NO;
nsCOMPtr<nsIPref> prefs(do_GetService(NS_PREF_CONTRACTID));
PRBool save = PR_FALSE;
prefs->GetBoolPref("browser.download.progressDnldDialog.keepAlive",&save);
prefs->GetBoolPref("browser.download.progressDnldDialog.keepAlive", &save);
mSaveFileDialogShouldStayOpen = save;
[self setupToolbar];
[mProgressBar setUsesThreadedAnimation:YES];
[mProgressBar startAnimation:self];
if (mDownloadListener)
mDownloadListener->BeginDownload();
[mProgressBar startAnimation:self]; // move to onStateChange
}
- (void)setupToolbar
@ -438,7 +214,9 @@ static NSString *LeaveOpenToolbarItemIdentifier = @"Leave Open Toggle Toolbar
-(void)cancel
{
mDownloadListener->CancelDownload();
if (mDownloader) // we should always have one
mDownloader->CancelDownload();
// clean up downloaded file. - do it here on in CancelDownload?
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *thePath = [[mToField stringValue] stringByExpandingTildeInPath];
@ -457,22 +235,29 @@ static NSString *LeaveOpenToolbarItemIdentifier = @"Leave Open Toggle Toolbar
-(void)pauseAndResumeDownload
{
if ( ! mDownloadIsPaused ) {
//Do logic to pause download
if ( !mDownloadIsPaused )
{
mDownloadIsPaused = YES;
[pauseResumeToggleToolbarItem setLabel:@"Resume"];
[pauseResumeToggleToolbarItem setPaletteLabel:@"Resume Download"];
[pauseResumeToggleToolbarItem setToolTip:@"Resume the paused FTP download"];
[pauseResumeToggleToolbarItem setImage:[NSImage imageNamed:@"saveResume"]];
[self killDownloadTimer];
} else {
//Do logic to resume download
if (mDownloader) // we should always have one
mDownloader->PauseDownload();
}
else
{
mDownloadIsPaused = NO;
[pauseResumeToggleToolbarItem setLabel:@"Pause"];
[pauseResumeToggleToolbarItem setPaletteLabel:@"Pause Download"];
[pauseResumeToggleToolbarItem setToolTip:@"Pause this FTP file download"];
[pauseResumeToggleToolbarItem setImage:[NSImage imageNamed:@"savePause"]];
[self setDownloadTimer];
[self setupDownloadTimer];
if (mDownloader) // we should always have one
mDownloader->ResumeDownload();
}
}
@ -531,12 +316,6 @@ static NSString *LeaveOpenToolbarItemIdentifier = @"Leave Open Toggle Toolbar
return YES;
}
- (void)dealloc
{
NS_IF_RELEASE(mDownloadListener);
[super dealloc];
}
- (void)killDownloadTimer
{
if (mDownloadTimer) {
@ -545,7 +324,7 @@ static NSString *LeaveOpenToolbarItemIdentifier = @"Leave Open Toggle Toolbar
mDownloadTimer = nil;
}
}
- (void)setDownloadTimer
- (void)setupDownloadTimer
{
[self killDownloadTimer];
mDownloadTimer = [[NSTimer scheduledTimerWithTimeInterval:1.0
@ -590,7 +369,7 @@ static NSString *LeaveOpenToolbarItemIdentifier = @"Leave Open Toggle Toolbar
return [[[NSString alloc] initWithString:[[NSBundle mainBundle] localizedStringForKey:@"UnderMin" value:@"Under a minute" table:@"ProgressDialog"]] autorelease];
}
// seconds becomes minutes and we keep checking.
seconds=seconds/60;
seconds = seconds/60;
if (seconds < 60) {
if (seconds < 2)
return [[[NSString alloc] initWithString:[[NSBundle mainBundle] localizedStringForKey:@"AboutMin" value:@"About a minute" table:@"ProgressDialog"]] autorelease];
@ -598,7 +377,7 @@ static NSString *LeaveOpenToolbarItemIdentifier = @"Leave Open Toggle Toolbar
return [[[NSString alloc] initWithFormat:[[NSBundle mainBundle] localizedStringForKey:@"AboutMins" value:@"About %d minutes" table:@"ProgressDialog"],seconds] autorelease];
}
//this download will never seemingly never end. now seconds become hours.
seconds=seconds/60;
seconds = seconds/60;
if (seconds < 2)
return [[[NSString alloc] initWithString:[[NSBundle mainBundle] localizedStringForKey:@"AboutHour" value:@"Over an hour" table:@"ProgressDialog"]] autorelease];
return [[[NSString alloc] initWithFormat:[[NSBundle mainBundle] localizedStringForKey:@"AboutHours" value:@"Over %d hours" table:@"ProgressDialog"],seconds] autorelease];
@ -629,8 +408,11 @@ static NSString *LeaveOpenToolbarItemIdentifier = @"Leave Open Toggle Toolbar
// this handles lots of things.
- (void)setDownloadProgress:(NSTimer *)downloadTimer;
{
// XXX this logic needs cleaning up.
// Ack! we're closing the window with the download still running!
if (mDownloadIsComplete) {
if (mDownloadIsComplete)
{
[[self window] performClose:self];
return;
}
@ -644,26 +426,28 @@ static NSString *LeaveOpenToolbarItemIdentifier = @"Leave Open Toggle Toolbar
[mElapsedTimeLabel setStringValue:[self formatTime:(++elapsedSec)]];
// for status field & time left
float maxBytes = ([mProgressBar maxValue]);
float byteSec = aCurrentProgress/elapsedSec;
float byteSec = mCurrentProgress/elapsedSec;
// OK - if downloadTimer is nil, we're done - fix maxBytes value for status report.
if (!downloadTimer)
maxBytes = aCurrentProgress;
maxBytes = mCurrentProgress;
// update status field
NSString *labelString = [[NSBundle mainBundle] localizedStringForKey:@"LabelString"
value:@"%@ of %@ total (at %@/sec)"
table:@"ProgressDialog"];
[mStatusLabel setStringValue: [NSString stringWithFormat:labelString, [self formatBytes:aCurrentProgress], [self formatBytes:maxBytes], [self formatBytes:byteSec]]];
[mStatusLabel setStringValue: [NSString stringWithFormat:labelString, [self formatBytes:mCurrentProgress], [self formatBytes:maxBytes], [self formatBytes:byteSec]]];
// updating estimated time left field
// if maxBytes < 0, can't calc time left.
// if !downloadTimer, download is finished. either way, make sure time left is 0.
if ((maxBytes > 0) && (downloadTimer)) {
int secToGo = (int)ceil((elapsedSec*maxBytes/aCurrentProgress)-elapsedSec);
if ((maxBytes > 0) && (downloadTimer))
{
int secToGo = (int)ceil((elapsedSec*maxBytes/mCurrentProgress) - elapsedSec);
[mTimeLeftLabel setStringValue:[self formatFuzzyTime:secToGo]];
}
else if (!downloadTimer) { // download done. Set remaining time to 0, fix progress bar & cancel button
else if (!downloadTimer)
{ // download done. Set remaining time to 0, fix progress bar & cancel button
mDownloadIsComplete = YES; // all done. we got a STATE_STOP
[mTimeLeftLabel setStringValue:@""];
[self setProgressBar:aCurrentProgress maxProg:aCurrentProgress];
[self setProgressTo:mCurrentProgress ofMax:mCurrentProgress];
if (!mSaveFileDialogShouldStayOpen)
[[self window] performClose:self]; // close window
else
@ -673,4 +457,59 @@ static NSString *LeaveOpenToolbarItemIdentifier = @"Leave Open Toggle Toolbar
[mTimeLeftLabel setStringValue:@"???"];
}
#pragma mark -
// DownloadProgressDisplay protocol methods
- (void)onStartDownload
{
[self showWindow: self];
[self setupDownloadTimer];
}
- (void)onEndDownload
{
[self killDownloadTimer];
[self setDownloadProgress:nil];
}
- (void)setProgressTo:(long)aCurProgress ofMax:(long)aMaxProgress
{
mCurrentProgress = aCurProgress; // fall back for stat calcs
if (![mProgressBar isIndeterminate]) //most likely - just update value
{
if (aCurProgress == aMaxProgress) //handles little bug in FTP download size
[mProgressBar setMaxValue:aMaxProgress];
[mProgressBar setDoubleValue:aCurProgress];
}
else if (aMaxProgress > 0) // ok, we're starting up with good max & cur values
{
[mProgressBar setIndeterminate:NO];
[mProgressBar setMaxValue:aMaxProgress];
[mProgressBar setDoubleValue:aCurProgress];
} // if neither case was true, it's barber pole city.
}
-(void) setDownloadListener: (nsDownloader*)aDownloader
{
if (mDownloader != aDownloader)
NS_IF_RELEASE(mDownloader);
NS_IF_ADDREF(mDownloader = aDownloader);
}
- (void)setSourceURL:(NSString*)aSourceURL
{
[mFromField setStringValue: aSourceURL];
[mFromField display]; // force an immmeditate update
}
- (void)setDestinationPath:(NSString*)aDestPath
{
[mToField setStringValue: [aDestPath stringByAbbreviatingWithTildeInPath]];
[mToField display]; // force an immmeditate update
}
@end

Просмотреть файл

@ -0,0 +1,84 @@
/* ***** 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 ***** */
#import <Foundation/Foundation.h>
#import <Appkit/Appkit.h>
#include "nsString.h"
#include "nsIWebProgressListener.h"
#include "nsIWebBrowserPersist.h"
#include "nsIURI.h"
#include "nsILocalFile.h"
#include "nsIInputStream.h"
#include "nsIDOMDocument.h"
// Implementation of a header sniffer class that is used when saving Web pages and images.
class nsHeaderSniffer : public nsIWebProgressListener
{
public:
nsHeaderSniffer(nsIWebBrowserPersist* aPersist, nsIFile* aFile, nsIURI* aURL,
nsIDOMDocument* aDocument, nsIInputStream* aPostData,
const nsCString& aSuggestedFilename, PRBool aBypassCache,
NSView* aFilterView, NSPopUpButton* aFilterList);
virtual ~nsHeaderSniffer();
NS_DECL_ISUPPORTS
NS_DECL_NSIWEBPROGRESSLISTENER
protected:
nsresult PerformSave(nsIURI* inOriginalURI);
nsresult InitiateDownload(nsISupports* inSourceData, nsString& inFileName, nsIURI* inOriginalURI);
private:
nsIWebBrowserPersist* mPersist; // Weak. It owns us as a listener.
nsCOMPtr<nsIFile> mTmpFile;
nsCOMPtr<nsIURI> mURL;
nsCOMPtr<nsIDOMDocument> mDocument;
nsCOMPtr<nsIInputStream> mPostData;
nsCString mDefaultFilename;
PRBool mBypassCache;
nsCString mContentType;
nsCString mContentDisposition;
NSView* mFilterView;
NSPopUpButton* mFilterList;
};

Просмотреть файл

@ -0,0 +1,386 @@
/* ***** 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 "SaveHeaderSniffer.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"
const char* const persistContractID = "@mozilla.org/embedding/browser/nsWebBrowserPersist;1";
nsHeaderSniffer::nsHeaderSniffer(nsIWebBrowserPersist* aPersist, nsIFile* aFile, nsIURI* aURL,
nsIDOMDocument* aDocument, nsIInputStream* aPostData,
const nsCString& aSuggestedFilename, PRBool aBypassCache,
NSView* aFilterView, NSPopUpButton* aFilterList)
: mPersist(aPersist)
, mTmpFile(aFile)
, mURL(aURL)
, mDocument(aDocument)
, mPostData(aPostData)
, mDefaultFilename(aSuggestedFilename)
, mBypassCache(aBypassCache)
, mFilterView(aFilterView)
, mFilterList(aFilterList)
{
NS_INIT_ISUPPORTS();
}
nsHeaderSniffer::~nsHeaderSniffer()
{
}
NS_IMPL_ISUPPORTS1(nsHeaderSniffer, nsIWebProgressListener)
#pragma mark -
// Implementation of nsIWebProgressListener
/* void onStateChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in long aStateFlags, in unsigned long aStatus); */
NS_IMETHODIMP
nsHeaderSniffer::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 ourslves 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);
if (NS_FAILED(rv))
{
// put up some UI
NSLog(@"Error saving web page");
}
}
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
nsHeaderSniffer::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
nsHeaderSniffer::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
nsHeaderSniffer::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
nsHeaderSniffer::OnSecurityChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, PRUint32 state)
{
return NS_OK;
}
#pragma mark -
nsresult nsHeaderSniffer::PerformSave(nsIURI* inOriginalURI)
{
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 (dirBranch) {
nsresult rv = dirBranch->GetIntPref("save_converter_index", &filterIndex);
if (NS_FAILED(rv))
filterIndex = 0;
}
if (mFilterList)
[mFilterList selectItemAtIndex: filterIndex];
// We need to figure out what file name to use.
nsCAutoString 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 = filename;
}
}
if (defaultFileName.IsEmpty()) {
nsCOMPtr<nsIURL> url(do_QueryInterface(mURL));
if (url)
url->GetFileName(defaultFileName); // (2) For file URLs, use the file name.
}
if (defaultFileName.IsEmpty() && mDocument && isHTML) {
nsCOMPtr<nsIDOMHTMLDocument> htmlDoc(do_QueryInterface(mDocument));
nsAutoString title;
if (htmlDoc)
htmlDoc->GetTitle(title); // (3) Use the title of the document.
defaultFileName.AssignWithConversion(title);
}
if (defaultFileName.IsEmpty()) {
// (4) Use the caller provided name.
defaultFileName = mDefaultFilename;
}
if (defaultFileName.IsEmpty() && mURL)
// (5) Use the host.
mURL->GetHost(defaultFileName);
// One last case to handle about:blank and other fruity untitled pages.
if (defaultFileName.IsEmpty())
defaultFileName = "untitled";
// Validate the file name to ensure legality.
for (PRUint32 i = 0; i < defaultFileName.Length(); i++)
if (defaultFileName[i] == ':' || defaultFileName[i] == '/')
defaultFileName.SetCharAt(i, ' ');
// 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(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 += ".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 += ".";
defaultFileName += extList[0];
}
}
// Now it's time to pose the save dialog.
NSSavePanel* savePanel = [NSSavePanel savePanel];
NSString* file = nil;
if (!defaultFileName.IsEmpty())
file = [[NSString alloc] initWithCString: defaultFileName.get()];
if (isHTML)
[savePanel setAccessoryView: mFilterView];
if ([savePanel runModalForDirectory: nil file: file] == NSFileHandlingPanelCancelButton)
return NS_OK;
// Release the file string.
[file release];
// Update the filter index.
if (isHTML && mFilterList) {
filterIndex = [mFilterList indexOfSelectedItem];
dirBranch->SetIntPref("save_converter_index", filterIndex);
}
// Convert the content type to text/plain if it was selected in the filter.
if (isHTML && filterIndex == 2)
mContentType = "text/plain";
nsCOMPtr<nsISupports> sourceData;
if (isHTML && filterIndex != 1)
sourceData = do_QueryInterface(mDocument);
else
sourceData = do_QueryInterface(mURL);
NSString* destName = [savePanel filename];
PRUint32 dstLen = [destName length];
PRUnichar* tmp = new PRUnichar[dstLen + sizeof(PRUnichar)];
tmp[dstLen] = (PRUnichar)'\0';
[destName getCharacters:tmp];
nsAutoString dstString(tmp);
delete tmp;
return InitiateDownload(sourceData, dstString, 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 nsHeaderSniffer::InitiateDownload(nsISupports* inSourceData, nsString& inFileName, 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);
nsCOMPtr<nsILocalFile> destFile;
rv = NS_NewLocalFile(inFileName, PR_FALSE, getter_AddRefs(destFile));
if (NS_FAILED(rv)) return rv;
PRInt64 timeNow = PR_Now();
nsCOMPtr<nsIDownload> downloader = do_CreateInstance(NS_DOWNLOAD_CONTRACTID);
// dlListener attaches to its progress dialog here, which gains ownership
rv = downloader->Init(inOriginalURI, destFile, inFileName.get(), nsString().get(), 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;
if (sourceURI)
{
rv = webPersist->SaveURI(sourceURI, mPostData, destFile);
}
else
{
nsCOMPtr<nsIDOMHTMLDocument> 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;
destFile->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, destFile, filesFolder, mContentType.get(), encodingFlags, 80);
}
return rv;
}

Просмотреть файл

@ -0,0 +1,88 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Netscape 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/NPL/
*
* 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):
* 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 NPL, 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 NPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#import <Foundation/Foundation.h>
#import <Appkit/Appkit.h>
#import "DownloadProgressDisplay.h"
#include "nsString.h"
#include "nsIDownload.h"
#include "nsIWebProgressListener.h"
#include "nsIWebBrowserPersist.h"
#include "nsIURI.h"
#include "nsILocalFile.h"
// maybe this should replace nsHeaderSniffer too?
class nsDownloadListener : public nsDownloader,
public nsIDownload,
public nsIWebProgressListener
{
public:
nsDownloadListener(DownloadControllerFactory* inDownloadControllerFactory);
virtual ~nsDownloadListener();
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSIDOWNLOAD
NS_DECL_NSIWEBPROGRESSLISTENER
public:
//void BeginDownload();
void InitDialog();
virtual void PauseDownload();
virtual void ResumeDownload();
virtual void CancelDownload();
virtual void DownloadDone();
private:
nsCOMPtr<nsIWebBrowserPersist> mWebPersist; // Our web persist object.
nsCOMPtr<nsIURI> mURI; // The URI of our source file. Null if we're saving a complete document.
nsCOMPtr<nsILocalFile> mDestination; // Our destination URL.
PRInt64 mStartTime; // When the download started
PRPackedBool mBypassCache; // Whether we should bypass the cache or not.
PRPackedBool mNetworkTransfer; // true if the first OnStateChange has the NETWORK bit set
PRPackedBool mGotFirstStateChange; // true after we've seen the first OnStateChange
PRPackedBool mUserCanceled; // true if the user canceled the download
};

Просмотреть файл

@ -0,0 +1,308 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Netscape 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/NPL/
*
* 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):
* 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 NPL, 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 NPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsDownloadListener.h"
#include "nsIWebProgress.h"
#include "nsIRequest.h"
#include "nsIURL.h"
#include "netCore.h"
nsDownloadListener::nsDownloadListener(DownloadControllerFactory* inControllerFactory)
: nsDownloader(inControllerFactory)
, mBypassCache(PR_FALSE)
, mNetworkTransfer(PR_FALSE)
, mGotFirstStateChange(PR_FALSE)
, mUserCanceled(PR_FALSE)
{
}
nsDownloadListener::~nsDownloadListener()
{
}
NS_IMPL_ISUPPORTS_INHERITED2(nsDownloadListener, nsDownloader, nsIDownload, nsIWebProgressListener)
#pragma mark -
/* void init (in nsIURI aSource, in nsILocalFile aTarget, in wstring aDisplayName, in wstring openingWith, in long long startTime, in nsIWebBrowserPersist aPersist); */
NS_IMETHODIMP
nsDownloadListener::Init(nsIURI *aSource, nsILocalFile *aTarget, const PRUnichar *aDisplayName,
const PRUnichar *openingWith, PRInt64 startTime, nsIWebBrowserPersist *aPersist)
{
CreateDownloadDisplay(); // call the base class to make the download UI
if (aPersist) // only true for File->Save As.
{
mWebPersist = aPersist;
mWebPersist->SetProgressListener(this); // we form a cycle here, since we're a listener.
// we'll break this cycle in DownloadDone()
}
mDestination = aTarget;
mURI = aSource;
mStartTime = startTime;
InitDialog();
return NS_OK;
}
/* readonly attribute nsIURI source; */
NS_IMETHODIMP
nsDownloadListener::GetSource(nsIURI * *aSource)
{
NS_ENSURE_ARG_POINTER(aSource);
NS_IF_ADDREF(*aSource = mURI);
return NS_OK;
}
/* readonly attribute nsILocalFile target; */
NS_IMETHODIMP
nsDownloadListener::GetTarget(nsILocalFile * *aTarget)
{
NS_ENSURE_ARG_POINTER(aTarget);
NS_IF_ADDREF(*aTarget = mDestination);
return NS_OK;
}
/* readonly attribute nsIWebBrowserPersist persist; */
NS_IMETHODIMP
nsDownloadListener::GetPersist(nsIWebBrowserPersist * *aPersist)
{
NS_ENSURE_ARG_POINTER(aPersist);
NS_IF_ADDREF(*aPersist = mWebPersist);
return NS_OK;
}
/* readonly attribute PRInt32 percentComplete; */
NS_IMETHODIMP
nsDownloadListener::GetPercentComplete(PRInt32 *aPercentComplete)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
/* attribute wstring displayName; */
NS_IMETHODIMP
nsDownloadListener::GetDisplayName(PRUnichar * *aDisplayName)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsDownloadListener::SetDisplayName(const PRUnichar * aDisplayName)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
/* readonly attribute long long startTime; */
NS_IMETHODIMP
nsDownloadListener::GetStartTime(PRInt64 *aStartTime)
{
NS_ENSURE_ARG(aStartTime);
*aStartTime = mStartTime;
return NS_OK;
}
/* readonly attribute wstring openingWith; */
NS_IMETHODIMP
nsDownloadListener::GetOpeningWith(PRUnichar * *aOpeningWith)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
/* attribute nsIWebProgressListener listener; */
NS_IMETHODIMP
nsDownloadListener::GetListener(nsIWebProgressListener * *aListener)
{
NS_ENSURE_ARG_POINTER(aListener);
NS_IF_ADDREF(*aListener = (nsIWebProgressListener *)this);
return NS_OK;
}
NS_IMETHODIMP
nsDownloadListener::SetListener(nsIWebProgressListener * aListener)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
/* attribute nsIObserver observer; */
NS_IMETHODIMP
nsDownloadListener::GetObserver(nsIObserver * *aObserver)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsDownloadListener::SetObserver(nsIObserver * aObserver)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
#pragma mark -
/* void onProgressChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in long aCurSelfProgress, in long aMaxSelfProgress, in long aCurTotalProgress, in long aMaxTotalProgress); */
NS_IMETHODIMP
nsDownloadListener::OnProgressChange(nsIWebProgress *aWebProgress,
nsIRequest *aRequest,
PRInt32 aCurSelfProgress,
PRInt32 aMaxSelfProgress,
PRInt32 aCurTotalProgress,
PRInt32 aMaxTotalProgress)
{
if (mUserCanceled)
{
if (aRequest)
aRequest->Cancel(NS_BINDING_ABORTED);
mUserCanceled = false;
}
[mDownloadDisplay setProgressTo:aCurTotalProgress ofMax:aMaxTotalProgress];
return NS_OK;
}
/* void onLocationChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in nsIURI location); */
NS_IMETHODIMP
nsDownloadListener::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
nsDownloadListener::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
nsDownloadListener::OnSecurityChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, PRUint32 state)
{
return NS_OK;
}
// Implementation of nsIWebProgressListener
/* void onStateChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in unsigned long aStateFlags, in unsigned long aStatus); */
NS_IMETHODIMP
nsDownloadListener::OnStateChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, PRUint32 aStateFlags,
PRUint32 aStatus)
{
// NSLog(@"State changed: state %u, status %u", aStateFlags, aStatus);
if (!mGotFirstStateChange) {
mNetworkTransfer = ((aStateFlags & STATE_IS_NETWORK) != 0);
mGotFirstStateChange = PR_TRUE;
}
// when the entire download finishes, stop the progress timer and clean up
// the window and controller. We will get this even in the event of a cancel,
// so this is the only place in the listener where we should kill the download.
if ((aStateFlags & STATE_STOP) && (!mNetworkTransfer || (aStateFlags & STATE_IS_NETWORK))) {
DownloadDone();
}
return NS_OK;
}
#pragma mark -
void
nsDownloadListener::InitDialog()
{
// dialog has to be shown before the outlets get hooked up
[mDownloadDisplay onStartDownload];
if (mURI)
{
nsCAutoString spec;
mURI->GetSpec(spec);
[mDownloadDisplay setSourceURL: [NSString stringWithUTF8String:spec.get()]];
}
nsAutoString pathStr;
mDestination->GetPath(pathStr);
[mDownloadDisplay setDestinationPath: [NSString stringWithCharacters:pathStr.get() length:pathStr.Length()]];
}
void
nsDownloadListener::PauseDownload()
{
// write me
}
void
nsDownloadListener::ResumeDownload()
{
// write me
}
void
nsDownloadListener::CancelDownload()
{
mUserCanceled = PR_TRUE;
if (mWebPersist)
{
mWebPersist->CancelSave();
mUserCanceled = PR_FALSE;
}
// delete any files we've created...
}
void
nsDownloadListener::DownloadDone()
{
// break the reference cycle by removing ourselves as a listener
if (mWebPersist)
{
mWebPersist->SetProgressListener(nsnull);
mWebPersist = nsnull;
}
[mDownloadDisplay onEndDownload];
}
#pragma mark -

Просмотреть файл

@ -55,7 +55,7 @@ class nsCocoaBrowserService : public nsIWindowCreator,
public nsIPromptService,
public nsIFactory,
public nsIBadCertListener, public nsISecurityWarningDialogs, public nsINSSDialogs,
public nsIHelperAppLauncherDialog, public nsIDownload, public nsIWebProgressListener
public nsIHelperAppLauncherDialog
{
public:
nsCocoaBrowserService();
@ -69,8 +69,6 @@ public:
NS_DECL_NSIBADCERTLISTENER
NS_DECL_NSISECURITYWARNINGDIALOGS
NS_DECL_NSIHELPERAPPLAUNCHERDIALOG
NS_DECL_NSIDOWNLOAD
NS_DECL_NSIWEBPROGRESSLISTENER
static nsresult InitEmbedding();
static void TermEmbedding();

Просмотреть файл

@ -35,14 +35,15 @@
*
* ***** END LICENSE BLOCK ***** */
#include "nsCocoaBrowserService.h"
#import "nsCocoaBrowserService.h"
#import "DownloadFactories.h"
#import "CHBrowserView.h"
#include "nsIWindowWatcher.h"
#include "nsIWebBrowserChrome.h"
#include "nsIEmbeddingSiteWindow.h"
#include "nsIProfile.h"
#include "nsIPrefService.h"
#include "CHBrowserView.h"
#include "nsCRT.h"
#include "nsString.h"
#include "nsIPrompt.h"
@ -74,13 +75,14 @@ nsCocoaBrowserService::~nsCocoaBrowserService()
{
}
NS_IMPL_ISUPPORTS9(nsCocoaBrowserService,
NS_IMPL_ISUPPORTS7(nsCocoaBrowserService,
nsIWindowCreator,
nsIPromptService,
nsIFactory,
nsIBadCertListener, nsISecurityWarningDialogs, nsINSSDialogs,
nsIHelperAppLauncherDialog, nsIDownload, nsIWebProgressListener)
nsIHelperAppLauncherDialog)
/* static */
nsresult
nsCocoaBrowserService::InitEmbedding()
{
@ -103,7 +105,7 @@ nsCocoaBrowserService::InitEmbedding()
#define NS_PROMPTSERVICE_CID \
{0xa2112d6a, 0x0e28, 0x421f, {0xb4, 0x6a, 0x25, 0xc0, 0xb3, 0x8, 0xcb, 0xd0}}
static NS_DEFINE_CID(kPromptServiceCID, NS_PROMPTSERVICE_CID);
nsresult rv = cr->RegisterFactory(kPromptServiceCID, "Prompt Service", "@mozilla.org/embedcomp/prompt-service;1",
nsresult rv = cr->RegisterFactory(kPromptServiceCID, "Prompt Service", "@mozilla.org/embedcomp/prompt-service;1",
sSingleton);
if (NS_FAILED(rv))
return rv;
@ -127,14 +129,18 @@ nsCocoaBrowserService::InitEmbedding()
rv = cr->RegisterFactory(kHelperDlgCID, NS_IHELPERAPPLAUNCHERDLG_CLASSNAME, NS_IHELPERAPPLAUNCHERDLG_CONTRACTID,
sSingleton);
// replace the downloader with our own which does rely on the xpfe downlaod manager
// replace the downloader with our own which does not rely on the xpfe downlaod manager
nsCOMPtr<nsIFactory> downloadFactory;
rv = NewDownloadListenerFactory(getter_AddRefs(downloadFactory));
if (NS_FAILED(rv)) return rv;
static NS_DEFINE_CID(kDownloadCID, NS_DOWNLOAD_CID);
rv = cr->RegisterFactory(kDownloadCID, "Download", NS_DOWNLOAD_CONTRACTID,
sSingleton);
rv = cr->RegisterFactory(kDownloadCID, "Download", NS_DOWNLOAD_CONTRACTID, downloadFactory);
return rv;
}
/* static */
void
nsCocoaBrowserService::BrowserClosed()
{
@ -149,6 +155,7 @@ nsCocoaBrowserService::BrowserClosed()
}
}
/* static */
void
nsCocoaBrowserService::TermEmbedding()
{
@ -195,8 +202,15 @@ nsCocoaBrowserService::CreateInstance(nsISupports *aOuter,
const nsIID & aIID,
void **aResult)
{
NS_ENSURE_ARG_POINTER(aResult);
/*
if (aIID.Equals(NS_GET_IID(nsIHelperAppLauncherDialog)))
{
}
*/
return sSingleton->QueryInterface(aIID, aResult);
}
@ -828,14 +842,12 @@ nsCocoaBrowserService::ConfirmPostToInsecureFromSecure(nsIInterfaceRequestor *ct
NS_IMETHODIMP
nsCocoaBrowserService::Show(nsIHelperAppLauncher* inLauncher, nsISupports* inContext)
{
NSLog(@"Show");
return inLauncher->SaveToDisk(nsnull, PR_FALSE);
}
NS_IMETHODIMP
nsCocoaBrowserService::PromptForSaveToFile(nsISupports *aWindowContext, const PRUnichar *aDefaultFile, const PRUnichar *aSuggestedFileExtension, nsILocalFile **_retval)
{
NSLog(@"PromptForSaveToFile");
NSString* filename = [NSString stringWithCharacters:aDefaultFile length:nsCRT::strlen(aDefaultFile)];
NSSavePanel *thePanel = [NSSavePanel savePanel];
@ -844,7 +856,7 @@ NSLog(@"PromptForSaveToFile");
// use nil for the path given to runModalForDirectory
int runResult = [thePanel runModalForDirectory: nil file:filename];
if (runResult == NSOKButton) {
NSLog([thePanel filename]);
// NSLog(@"Saving to %@", [thePanel filename]);
NSString *theName = [thePanel filename];
return NS_NewNativeLocalFile(nsDependentCString([theName fileSystemRepresentation]), PR_FALSE, _retval);
}
@ -856,140 +868,6 @@ NSLog([thePanel filename]);
NS_IMETHODIMP
nsCocoaBrowserService::ShowProgressDialog(nsIHelperAppLauncher *aLauncher, nsISupports *aContext)
{
return NS_OK;
}
NS_IMETHODIMP
nsCocoaBrowserService::Init(nsIURI* aSource,
nsILocalFile* aTarget,
const PRUnichar* aDisplayName,
const PRUnichar* aOpeningWith,
PRInt64 aStartTime,
nsIWebBrowserPersist* aPersist)
{
NSLog(@"nsIDownload::Init");
return NS_OK;
}
NS_IMETHODIMP
nsCocoaBrowserService::GetDisplayName(PRUnichar** aDisplayName)
{
NS_ERROR("NS_ERROR_NOT_IMPLEMENTED");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsCocoaBrowserService::SetDisplayName(const PRUnichar* aDisplayName)
{
return NS_OK;
}
NS_IMETHODIMP
nsCocoaBrowserService::GetOpeningWith(PRUnichar** aOpeningWith)
{
NS_ERROR("NS_ERROR_NOT_IMPLEMENTED");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsCocoaBrowserService::GetSource(nsIURI** aSource)
{
NS_ERROR("NS_ERROR_NOT_IMPLEMENTED");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsCocoaBrowserService::GetTarget(nsILocalFile** aTarget)
{
NS_ERROR("NS_ERROR_NOT_IMPLEMENTED");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsCocoaBrowserService::GetStartTime(PRInt64* aStartTime)
{
NS_ERROR("NS_ERROR_NOT_IMPLEMENTED");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsCocoaBrowserService::GetPercentComplete(PRInt32* aPercentComplete)
{
NS_ERROR("NS_ERROR_NOT_IMPLEMENTED");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsCocoaBrowserService::GetListener(nsIWebProgressListener** aListener)
{
NS_ERROR("NS_ERROR_NOT_IMPLEMENTED");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsCocoaBrowserService::SetListener(nsIWebProgressListener* aListener)
{
return NS_OK;
}
NS_IMETHODIMP
nsCocoaBrowserService::GetObserver(nsIObserver** aObserver)
{
NS_ERROR("NS_ERROR_NOT_IMPLEMENTED");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsCocoaBrowserService::SetObserver(nsIObserver* aObserver)
{
return NS_OK;
}
NS_IMETHODIMP
nsCocoaBrowserService::GetPersist(nsIWebBrowserPersist** aPersist)
{
NS_ERROR("NS_ERROR_NOT_IMPLEMENTED");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsCocoaBrowserService::OnStateChange(nsIWebProgress* aWebProgress,
nsIRequest* aRequest, PRUint32 aStateFlags,
PRUint32 aStatus)
{
return NS_OK;
}
NS_IMETHODIMP
nsCocoaBrowserService::OnStatusChange(nsIWebProgress *aWebProgress,
nsIRequest *aRequest, nsresult aStatus,
const PRUnichar *aMessage)
{
return NS_OK;
}
NS_IMETHODIMP
nsCocoaBrowserService::OnLocationChange(nsIWebProgress *aWebProgress,
nsIRequest *aRequest, nsIURI *aLocation)
{
return NS_OK;
}
NS_IMETHODIMP
nsCocoaBrowserService::OnProgressChange(nsIWebProgress *aWebProgress,
nsIRequest *aRequest,
PRInt32 aCurSelfProgress,
PRInt32 aMaxSelfProgress,
PRInt32 aCurTotalProgress,
PRInt32 aMaxTotalProgress)
{
return NS_OK;
}
NS_IMETHODIMP
nsCocoaBrowserService::OnSecurityChange(nsIWebProgress *aWebProgress,
nsIRequest *aRequest, PRUint32 aState)
{
NSLog(@"nsCocoaBrowserService::ShowProgressDialog");
return NS_OK;
}

Просмотреть файл

@ -36,7 +36,6 @@
* ***** END LICENSE BLOCK ***** */
#import "CHBrowserView.h"
#import "ProgressDlgController.h"
#import "FindDlgController.h"
#import "nsCocoaBrowserService.h"
#import "mozView.h"
@ -65,18 +64,12 @@
// Saving of links/images/docs
#include "nsIWebBrowserFocus.h"
#include "nsIDOMHTMLDocument.h"
#include "nsIDOMNSDocument.h"
#include "nsIDOMLocation.h"
#include "nsIURL.h"
#include "nsIWebBrowserPersist.h"
#include "nsIProperties.h"
#include "nsIRequest.h"
#include "nsIChannel.h"
#include "nsIHttpChannel.h"
#include "nsIPref.h"
#include "nsIMIMEService.h"
#include "nsIMIMEInfo.h"
#include "nsIPrefService.h"
#include "nsISHistory.h"
#include "nsIHistoryEntry.h"
#include "nsISHEntry.h"
@ -84,6 +77,7 @@
#include "nsIContextMenuListener.h"
#include "nsITooltipListener.h"
#include "nsIEmbeddingSiteWindow2.h"
#include "SaveHeaderSniffer.h"
typedef unsigned int DragReference;
#include "nsIDragHelperService.h"
@ -677,265 +671,7 @@ nsCocoaBrowserListener::SetContainer(id <NSBrowserContainer> aContainer)
[mContainer retain];
}
// Implementation of a header sniffer class that is used when saving Web pages and images.
class nsHeaderSniffer : public nsIWebProgressListener
{
public:
nsHeaderSniffer(nsIWebBrowserPersist* aPersist, nsIFile* aFile, nsIURI* aURL,
nsIDOMDocument* aDocument, nsIInputStream* aPostData,
const nsCString& aSuggestedFilename, PRBool aBypassCache,
NSView* aFilterView, NSPopUpButton* aFilterList)
{
NS_INIT_REFCNT();
mPersist = aPersist;
mTmpFile = aFile;
mURL = aURL;
mDocument = aDocument;
mPostData = aPostData;
mDefaultFilename = aSuggestedFilename;
mBypassCache = aBypassCache;
mFilterView = aFilterView;
mFilterList = aFilterList;
}
virtual ~nsHeaderSniffer()
{
};
NS_DECL_ISUPPORTS
NS_DECL_NSIWEBPROGRESSLISTENER
protected:
void PerformSave();
private:
nsIWebBrowserPersist* mPersist; // Weak. It owns us as a listener.
nsCOMPtr<nsIFile> mTmpFile;
nsCOMPtr<nsIURI> mURL;
nsCOMPtr<nsIDOMDocument> mDocument;
nsCOMPtr<nsIInputStream> mPostData;
nsCString mDefaultFilename;
PRBool mBypassCache;
nsCString mContentType;
nsCString mContentDisposition;
NSView* mFilterView;
NSPopUpButton* mFilterList;
};
NS_IMPL_ISUPPORTS1(nsHeaderSniffer, nsIWebProgressListener)
// Implementation of nsIWebProgressListener
/* void onStateChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in long aStateFlags, in unsigned long aStatus); */
NS_IMETHODIMP
nsHeaderSniffer::OnStateChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, PRUint32 aStateFlags,
PRUint32 aStatus)
{
if (aStateFlags & nsIWebProgressListener::STATE_START) {
nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest));
channel->GetContentType(mContentType);
// 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);
PerformSave();
}
return NS_OK;
}
void nsHeaderSniffer::PerformSave()
{
// 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"));
if (!prefs)
return;
nsCOMPtr<nsIPrefBranch> dirBranch;
prefs->GetBranch("browser.download.", getter_AddRefs(dirBranch));
PRInt32 filterIndex = 0;
if (dirBranch) {
nsresult rv = dirBranch->GetIntPref("save_converter_index", &filterIndex);
if (NS_FAILED(rv))
filterIndex = 0;
}
if (mFilterList)
[mFilterList selectItemAtIndex: filterIndex];
// We need to figure out what file name to use.
nsCAutoString 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 = filename;
}
}
if (defaultFileName.IsEmpty()) {
nsCOMPtr<nsIURL> url(do_QueryInterface(mURL));
if (url)
url->GetFileName(defaultFileName); // (2) For file URLs, use the file name.
}
if (defaultFileName.IsEmpty() && mDocument && isHTML) {
nsCOMPtr<nsIDOMHTMLDocument> htmlDoc(do_QueryInterface(mDocument));
nsAutoString title;
if (htmlDoc)
htmlDoc->GetTitle(title); // (3) Use the title of the document.
defaultFileName.AssignWithConversion(title);
}
if (defaultFileName.IsEmpty()) {
// (4) Use the caller provided name.
defaultFileName = mDefaultFilename;
}
if (defaultFileName.IsEmpty() && mURL)
// (5) Use the host.
mURL->GetHost(defaultFileName);
// One last case to handle about:blank and other fruity untitled pages.
if (defaultFileName.IsEmpty())
defaultFileName = "untitled";
// Validate the file name to ensure legality.
for (PRUint32 i = 0; i < defaultFileName.Length(); i++)
if (defaultFileName[i] == ':' || defaultFileName[i] == '/')
defaultFileName.SetCharAt(i, ' ');
// 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));
if (!fileURL)
return;
fileURL->SetFilePath(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 += ".html";
setExtension = PR_TRUE;
}
}
if (!setExtension && fileExtension.IsEmpty()) {
nsCOMPtr<nsIMIMEService> mimeService(do_GetService("@mozilla.org/mime;1"));
if (!mimeService)
return;
nsCOMPtr<nsIMIMEInfo> mimeInfo;
mimeService->GetFromMIMEType(mContentType.get(), getter_AddRefs(mimeInfo));
if (!mimeInfo)
return;
PRUint32 extCount = 0;
char** extList = nsnull;
mimeInfo->GetFileExtensions(&extCount, &extList);
if (extCount > 0 && extList) {
defaultFileName += ".";
defaultFileName += extList[0];
}
}
// Now it's time to pose the save dialog.
NSSavePanel* savePanel = [NSSavePanel savePanel];
NSString* file = nil;
if (!defaultFileName.IsEmpty())
file = [[NSString alloc] initWithCString: defaultFileName.get()];
if (isHTML)
[savePanel setAccessoryView: mFilterView];
if ([savePanel runModalForDirectory: nil file: file] == NSFileHandlingPanelCancelButton)
return;
// Release the file string.
[file release];
// Update the filter index.
if (isHTML && mFilterList) {
filterIndex = [mFilterList indexOfSelectedItem];
dirBranch->SetIntPref("save_converter_index", filterIndex);
}
// Convert the content type to text/plain if it was selected in the filter.
if (isHTML && filterIndex == 2)
mContentType = "text/plain";
nsCOMPtr<nsISupports> sourceData;
if (isHTML && filterIndex != 1)
sourceData = do_QueryInterface(mDocument);
else
sourceData = do_QueryInterface(mURL);
nsCOMPtr<nsIWebBrowserPersist> webPersist(do_CreateInstance(persistContractID));
ProgressDlgController* progressDialog = [[ProgressDlgController alloc] initWithWindowNibName: @"ProgressDialog"];
[progressDialog setWebPersist: webPersist
source: sourceData.get()
destination: [savePanel filename]
contentType: mContentType.get()
postData: mPostData
bypassCache: mBypassCache];
[progressDialog showWindow: progressDialog];
}
/* void onProgressChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in long aCurSelfProgress, in long aMaxSelfProgress, in long aCurTotalProgress, in long aMaxTotalProgress); */
NS_IMETHODIMP
nsHeaderSniffer::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
nsHeaderSniffer::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
nsHeaderSniffer::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
nsHeaderSniffer::OnSecurityChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, PRUint32 state)
{
return NS_OK;
}
#pragma mark -
@implementation CHBrowserView
@ -1244,13 +980,17 @@ nsHeaderSniffer::OnSecurityChange(nsIWebProgress *aWebProgress, nsIRequest *aReq
shEntry->GetPostData(getter_AddRefs(postData));
}
// when saving, we first fire off a save with a nsHeaderSniffer as a progress
// listener. This allows us to look for the content-disposition header, which
// can supply a filename, and maybe has something to do with CGI-generated
// content (?)
nsCAutoString fileName(aFilename);
nsHeaderSniffer* sniffer = new nsHeaderSniffer(webPersist, tmpFile, aURI,
aDocument, postData, fileName, aBypassCache,
aFilterView, aFilterList);
if (!sniffer)
return;
webPersist->SetProgressListener(sniffer);
webPersist->SetProgressListener(sniffer); // owned
webPersist->SaveURI(aURI, nsnull, tmpFile);
}

Просмотреть файл

Просмотреть файл

@ -0,0 +1,120 @@
/* ***** 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):
* 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 ***** */
// This file contains implementations of factories for various
// downloading-related interfaces.
#import "DownloadProgressDisplay.h"
#import "ProgressDlgController.h"
#include "nsCOMPtr.h"
#include "nsIFactory.h"
#include "nsDownloadListener.h"
#include "DownloadFactories.h"
// factory for nsIDownload objects
// XXX replace with generic factory stuff
class DownloadListenerFactory : public nsIFactory
{
public:
DownloadListenerFactory();
virtual ~DownloadListenerFactory();
NS_DECL_ISUPPORTS
NS_DECL_NSIFACTORY
protected:
DownloadControllerFactory* mControllerFactory; // factory which creates the Cocoa window controller
};
DownloadListenerFactory::DownloadListenerFactory()
: mControllerFactory(nil)
{
NS_INIT_ISUPPORTS();
mControllerFactory = [[[ChimeraDownloadControllerFactory alloc] init] retain];
}
DownloadListenerFactory::~DownloadListenerFactory()
{
[mControllerFactory release];
}
NS_IMPL_ISUPPORTS1(DownloadListenerFactory, nsIFactory);
/* void createInstance (in nsISupports aOuter, in nsIIDRef iid, [iid_is (iid), retval] out nsQIResult result); */
NS_IMETHODIMP
DownloadListenerFactory::CreateInstance(nsISupports *aOuter, const nsIID& aIID, void* *aResult)
{
nsresult rv;
if (aIID.Equals(NS_GET_IID(nsIDownload)))
{
nsDownloadListener* downloadListener = new nsDownloadListener(mControllerFactory);
if (!downloadListener) return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(downloadListener);
rv = downloadListener->QueryInterface(aIID, aResult);
NS_RELEASE(downloadListener);
return rv;
}
return NS_ERROR_NO_INTERFACE;
}
/* void lockFactory (in PRBool lock); */
NS_IMETHODIMP
DownloadListenerFactory::LockFactory(PRBool lock)
{
return NS_OK;
}
#pragma mark -
nsresult NewDownloadListenerFactory(nsIFactory* *outFactory)
{
DownloadListenerFactory* newFactory = new DownloadListenerFactory();
if (!newFactory) return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(newFactory);
nsresult rv = newFactory->QueryInterface(NS_GET_IID(nsIFactory), (void **)outFactory);
NS_RELEASE(newFactory);
return rv;
}

Просмотреть файл

@ -0,0 +1,161 @@
/* ***** 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):
* 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 ***** */
/*
The classes and protocol in this file allow Cocoa applications to easily
reuse the underlying download implementation, which deals with the complexity
of Gecko's downloading callbacks.
There are three things here:
1. The DownloadProgressDisplay protocol.
This is a formal protocol that needs to be implemented by
a window controller for your progress window. Its methods
will be called by the underlying C++ downloading classes.
2. The Obj-C DownloadControllerFactory class.
This class should be subclassed by an embedder, with an
implementation of 'createDownloadController' that hands back
a new instance of an NSWindowController that implements the
<DownloadProgressDisplay> protocol.
The underlying C++ classes use this factory to create the
progress window controller.
3. The nsDownloader C++ class
This base class exists to hide the complextity of the download
listener classes (which deal with Gecko callbacks) from the
window controller. Embedders don't need to do anything with it.
How these classes fit together:
There are 2 ways in which a download is initiated:
(i) File->Save.
Chimera does a complex dance here in order to get certain
information about the data being downloaded (it needs to
start the download before it can read some optional MIME headers).
CBrowserView creates an nsIWebBrowserPersist (WBP), and then a
nsHeaderSniffer, which implements nsIWebProgressListener and is set to
observer the WBP. When nsHeaderSniffer hears about the start of the
download, it decides on a file name, and what format to save the data
in. It then cancels the current WPB, makes another one, and does
a CreateInstance of an nsIDownload (making one of our nsDownloadListener
-- aka nsDownloder -- objects), and sets that as the nsIWebProgressListener.
The full download procedes from there.
(ii) Click to download (e.g. FTP link)
This is simpler. The backend (necko) does the CreateInstance of the
nsIDownload, and the download progresses.
In both cases, creating the nsDownloadListener and calling its Init() method
calls nsDownloder::CreateDownloadDisplay(). The nsDownloder has as a member
variable a DownloadControllerFactory (see above), which got passed to it
via our XPCOM factory for nsIDownload objects. It then uses that DownloadControllerFactory
to get an instance of the download progress window controller, which then
shows the download progress window.
Simple, eh?
*/
#import <AppKit/AppKit.h>
#include "nsISupports.h"
class nsDownloader;
// a formal protocol for something that implements progress display
// Embedders can make a window controller that conforms to this
// protocol, and reuse nsDownloadListener to get download UI.
@protocol DownloadProgressDisplay
- (void)onStartDownload;
- (void)onEndDownload;
- (void)setProgressTo:(long)aCurProgress ofMax:(long)aMaxProgress;
- (void)setDownloadListener:(nsDownloader*)aDownloader;
- (void)setSourceURL:(NSString*)aSourceURL;
- (void)setDestinationPath:(NSString*)aDestPath;
@end
// subclass this, and have your subclass instantiate and return your window
// controller in createDownloadController
@interface DownloadControllerFactory : NSObject
{
}
- (NSWindowController<DownloadProgressDisplay> *)createDownloadController;
@end
// Pure virtual base class for a generic downloader, that the progress UI can talk to.
// It implements nsISupports so that it can be refcounted. This class insulates the
// UI code from having to know too much about the nsIDownloadListener.
// It is responsible for creating the download UI, via the DownloadControllerFactory
// that it owns.
class nsDownloader : public nsISupports
{
public:
nsDownloader(DownloadControllerFactory* inControllerFactory);
virtual ~nsDownloader();
NS_DECL_ISUPPORTS
virtual void PauseDownload() = 0;
virtual void ResumeDownload() = 0;
virtual void CancelDownload() = 0;
virtual void DownloadDone() = 0;
virtual void CreateDownloadDisplay();
protected:
DownloadControllerFactory* mControllerFactory;
id <DownloadProgressDisplay> mDownloadDisplay; // something that implements the DownloadProgressDisplay protocol
};

Просмотреть файл

@ -0,0 +1,75 @@
/* ***** 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):
* 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 ***** */
#import "DownloadProgressDisplay.h"
@implementation DownloadControllerFactory
- (NSWindowController<DownloadProgressDisplay> *)createDownloadController
{
// a dummy implementation. You should provide a subclass that
// returns an instance of your progress dialog controller.
return nil;
}
@end
#pragma mark -
// see the header file for comments
nsDownloader::nsDownloader(DownloadControllerFactory* inControllerFactory)
: mControllerFactory(inControllerFactory)
, mDownloadDisplay(nil)
{
NS_INIT_ISUPPORTS();
[mControllerFactory retain];
}
nsDownloader::~nsDownloader()
{
[mControllerFactory release];
}
NS_IMPL_ISUPPORTS1(nsDownloader, nsISupports);
void
nsDownloader::CreateDownloadDisplay()
{
mDownloadDisplay = [mControllerFactory createDownloadController];
[mDownloadDisplay setDownloadListener:this];
}

Просмотреть файл

@ -89,8 +89,11 @@ app_getModuleInfo(nsStaticModuleInfo **info, PRUint32 *count);
nsresult rv;
ICStop (mInternetConfig);
nsCOMPtr<nsIPrefService> pref(do_GetService(NS_PREF_CONTRACTID, &rv));
if (!NS_FAILED(rv))
if (NS_SUCCEEDED(rv)) {
//NSLog(@"Saving prefs file");
pref->SavePrefFile(nsnull);
}
[super dealloc];
}

Просмотреть файл

@ -36,7 +36,6 @@
* ***** END LICENSE BLOCK ***** */
#import "CHBrowserView.h"
#import "ProgressDlgController.h"
#import "FindDlgController.h"
#import "nsCocoaBrowserService.h"
#import "mozView.h"
@ -65,18 +64,12 @@
// Saving of links/images/docs
#include "nsIWebBrowserFocus.h"
#include "nsIDOMHTMLDocument.h"
#include "nsIDOMNSDocument.h"
#include "nsIDOMLocation.h"
#include "nsIURL.h"
#include "nsIWebBrowserPersist.h"
#include "nsIProperties.h"
#include "nsIRequest.h"
#include "nsIChannel.h"
#include "nsIHttpChannel.h"
#include "nsIPref.h"
#include "nsIMIMEService.h"
#include "nsIMIMEInfo.h"
#include "nsIPrefService.h"
#include "nsISHistory.h"
#include "nsIHistoryEntry.h"
#include "nsISHEntry.h"
@ -84,6 +77,7 @@
#include "nsIContextMenuListener.h"
#include "nsITooltipListener.h"
#include "nsIEmbeddingSiteWindow2.h"
#include "SaveHeaderSniffer.h"
typedef unsigned int DragReference;
#include "nsIDragHelperService.h"
@ -677,265 +671,7 @@ nsCocoaBrowserListener::SetContainer(id <NSBrowserContainer> aContainer)
[mContainer retain];
}
// Implementation of a header sniffer class that is used when saving Web pages and images.
class nsHeaderSniffer : public nsIWebProgressListener
{
public:
nsHeaderSniffer(nsIWebBrowserPersist* aPersist, nsIFile* aFile, nsIURI* aURL,
nsIDOMDocument* aDocument, nsIInputStream* aPostData,
const nsCString& aSuggestedFilename, PRBool aBypassCache,
NSView* aFilterView, NSPopUpButton* aFilterList)
{
NS_INIT_REFCNT();
mPersist = aPersist;
mTmpFile = aFile;
mURL = aURL;
mDocument = aDocument;
mPostData = aPostData;
mDefaultFilename = aSuggestedFilename;
mBypassCache = aBypassCache;
mFilterView = aFilterView;
mFilterList = aFilterList;
}
virtual ~nsHeaderSniffer()
{
};
NS_DECL_ISUPPORTS
NS_DECL_NSIWEBPROGRESSLISTENER
protected:
void PerformSave();
private:
nsIWebBrowserPersist* mPersist; // Weak. It owns us as a listener.
nsCOMPtr<nsIFile> mTmpFile;
nsCOMPtr<nsIURI> mURL;
nsCOMPtr<nsIDOMDocument> mDocument;
nsCOMPtr<nsIInputStream> mPostData;
nsCString mDefaultFilename;
PRBool mBypassCache;
nsCString mContentType;
nsCString mContentDisposition;
NSView* mFilterView;
NSPopUpButton* mFilterList;
};
NS_IMPL_ISUPPORTS1(nsHeaderSniffer, nsIWebProgressListener)
// Implementation of nsIWebProgressListener
/* void onStateChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in long aStateFlags, in unsigned long aStatus); */
NS_IMETHODIMP
nsHeaderSniffer::OnStateChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, PRUint32 aStateFlags,
PRUint32 aStatus)
{
if (aStateFlags & nsIWebProgressListener::STATE_START) {
nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest));
channel->GetContentType(mContentType);
// 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);
PerformSave();
}
return NS_OK;
}
void nsHeaderSniffer::PerformSave()
{
// 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"));
if (!prefs)
return;
nsCOMPtr<nsIPrefBranch> dirBranch;
prefs->GetBranch("browser.download.", getter_AddRefs(dirBranch));
PRInt32 filterIndex = 0;
if (dirBranch) {
nsresult rv = dirBranch->GetIntPref("save_converter_index", &filterIndex);
if (NS_FAILED(rv))
filterIndex = 0;
}
if (mFilterList)
[mFilterList selectItemAtIndex: filterIndex];
// We need to figure out what file name to use.
nsCAutoString 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 = filename;
}
}
if (defaultFileName.IsEmpty()) {
nsCOMPtr<nsIURL> url(do_QueryInterface(mURL));
if (url)
url->GetFileName(defaultFileName); // (2) For file URLs, use the file name.
}
if (defaultFileName.IsEmpty() && mDocument && isHTML) {
nsCOMPtr<nsIDOMHTMLDocument> htmlDoc(do_QueryInterface(mDocument));
nsAutoString title;
if (htmlDoc)
htmlDoc->GetTitle(title); // (3) Use the title of the document.
defaultFileName.AssignWithConversion(title);
}
if (defaultFileName.IsEmpty()) {
// (4) Use the caller provided name.
defaultFileName = mDefaultFilename;
}
if (defaultFileName.IsEmpty() && mURL)
// (5) Use the host.
mURL->GetHost(defaultFileName);
// One last case to handle about:blank and other fruity untitled pages.
if (defaultFileName.IsEmpty())
defaultFileName = "untitled";
// Validate the file name to ensure legality.
for (PRUint32 i = 0; i < defaultFileName.Length(); i++)
if (defaultFileName[i] == ':' || defaultFileName[i] == '/')
defaultFileName.SetCharAt(i, ' ');
// 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));
if (!fileURL)
return;
fileURL->SetFilePath(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 += ".html";
setExtension = PR_TRUE;
}
}
if (!setExtension && fileExtension.IsEmpty()) {
nsCOMPtr<nsIMIMEService> mimeService(do_GetService("@mozilla.org/mime;1"));
if (!mimeService)
return;
nsCOMPtr<nsIMIMEInfo> mimeInfo;
mimeService->GetFromMIMEType(mContentType.get(), getter_AddRefs(mimeInfo));
if (!mimeInfo)
return;
PRUint32 extCount = 0;
char** extList = nsnull;
mimeInfo->GetFileExtensions(&extCount, &extList);
if (extCount > 0 && extList) {
defaultFileName += ".";
defaultFileName += extList[0];
}
}
// Now it's time to pose the save dialog.
NSSavePanel* savePanel = [NSSavePanel savePanel];
NSString* file = nil;
if (!defaultFileName.IsEmpty())
file = [[NSString alloc] initWithCString: defaultFileName.get()];
if (isHTML)
[savePanel setAccessoryView: mFilterView];
if ([savePanel runModalForDirectory: nil file: file] == NSFileHandlingPanelCancelButton)
return;
// Release the file string.
[file release];
// Update the filter index.
if (isHTML && mFilterList) {
filterIndex = [mFilterList indexOfSelectedItem];
dirBranch->SetIntPref("save_converter_index", filterIndex);
}
// Convert the content type to text/plain if it was selected in the filter.
if (isHTML && filterIndex == 2)
mContentType = "text/plain";
nsCOMPtr<nsISupports> sourceData;
if (isHTML && filterIndex != 1)
sourceData = do_QueryInterface(mDocument);
else
sourceData = do_QueryInterface(mURL);
nsCOMPtr<nsIWebBrowserPersist> webPersist(do_CreateInstance(persistContractID));
ProgressDlgController* progressDialog = [[ProgressDlgController alloc] initWithWindowNibName: @"ProgressDialog"];
[progressDialog setWebPersist: webPersist
source: sourceData.get()
destination: [savePanel filename]
contentType: mContentType.get()
postData: mPostData
bypassCache: mBypassCache];
[progressDialog showWindow: progressDialog];
}
/* void onProgressChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in long aCurSelfProgress, in long aMaxSelfProgress, in long aCurTotalProgress, in long aMaxTotalProgress); */
NS_IMETHODIMP
nsHeaderSniffer::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
nsHeaderSniffer::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
nsHeaderSniffer::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
nsHeaderSniffer::OnSecurityChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, PRUint32 state)
{
return NS_OK;
}
#pragma mark -
@implementation CHBrowserView
@ -1244,13 +980,17 @@ nsHeaderSniffer::OnSecurityChange(nsIWebProgress *aWebProgress, nsIRequest *aReq
shEntry->GetPostData(getter_AddRefs(postData));
}
// when saving, we first fire off a save with a nsHeaderSniffer as a progress
// listener. This allows us to look for the content-disposition header, which
// can supply a filename, and maybe has something to do with CGI-generated
// content (?)
nsCAutoString fileName(aFilename);
nsHeaderSniffer* sniffer = new nsHeaderSniffer(webPersist, tmpFile, aURI,
aDocument, postData, fileName, aBypassCache,
aFilterView, aFilterList);
if (!sniffer)
return;
webPersist->SetProgressListener(sniffer);
webPersist->SetProgressListener(sniffer); // owned
webPersist->SaveURI(aURI, nsnull, tmpFile);
}

Просмотреть файл

@ -89,8 +89,11 @@ app_getModuleInfo(nsStaticModuleInfo **info, PRUint32 *count);
nsresult rv;
ICStop (mInternetConfig);
nsCOMPtr<nsIPrefService> pref(do_GetService(NS_PREF_CONTRACTID, &rv));
if (!NS_FAILED(rv))
if (NS_SUCCEEDED(rv)) {
//NSLog(@"Saving prefs file");
pref->SavePrefFile(nsnull);
}
[super dealloc];
}

Просмотреть файл

@ -14,6 +14,7 @@
F512F52B02D1287F01072C9F,
F5A3669702CCFAF601DC3354,
F512F52C02D1287F01072C9F,
F50D9DE602ECC32301BB4219,
F512F52D02D1287F01072C9F,
);
isa = PBXGroup;
@ -471,6 +472,10 @@
F59236C202C89ACA0100012B,
F5A3669802CCFAF601DC3354,
F55C4DD402D2864E0130B065,
F50D9DE402ECC2C601BB4219,
F50D9DEF02EE0AB101BB4219,
F50D9DF302EE194001BB4219,
F50D9DF702EE2B9B01BB4219,
);
isa = PBXHeadersBuildPhase;
name = Headers;
@ -585,6 +590,10 @@
F53E012D02AEE93701A967F3,
F632AF8602B9AEBC01000103,
F59236C302C89ACA0100012B,
F50D9DE502ECC2C601BB4219,
F50D9DF002EE0AB101BB4219,
F50D9DF402EE194001BB4219,
F50D9DF802EE2B9B01BB4219,
);
isa = PBXSourcesBuildPhase;
name = Sources;
@ -840,6 +849,145 @@
name = Graphics;
refType = 4;
};
F50D9DE202ECC2C601BB4219 = {
isa = PBXFileReference;
path = nsDownloadListener.h;
refType = 4;
};
F50D9DE302ECC2C601BB4219 = {
isa = PBXFileReference;
path = nsDownloadListener.mm;
refType = 4;
};
F50D9DE402ECC2C601BB4219 = {
fileRef = F50D9DE202ECC2C601BB4219;
isa = PBXBuildFile;
settings = {
};
};
F50D9DE502ECC2C601BB4219 = {
fileRef = F50D9DE302ECC2C601BB4219;
isa = PBXBuildFile;
settings = {
};
};
F50D9DE602ECC32301BB4219 = {
children = (
F50D9DF902EE2C1D01BB4219,
F50D9DFA02EE2C1D01BB4219,
);
isa = PBXGroup;
name = Downloading;
path = "";
refType = 4;
};
F50D9DE702ECC36201BB4219 = {
fileRef = F50D9DE202ECC2C601BB4219;
isa = PBXBuildFile;
settings = {
};
};
F50D9DE802ECC36201BB4219 = {
fileRef = F632AF8302B9AEBB01000103;
isa = PBXBuildFile;
settings = {
};
};
F50D9DE902ECC36201BB4219 = {
fileRef = F50D9DE302ECC2C601BB4219;
isa = PBXBuildFile;
settings = {
};
};
F50D9DED02EE0AB101BB4219 = {
isa = PBXFileReference;
path = DownloadProgressDisplay.h;
refType = 4;
};
F50D9DEE02EE0AB101BB4219 = {
isa = PBXFileReference;
path = DownloadProgressDisplay.mm;
refType = 4;
};
F50D9DEF02EE0AB101BB4219 = {
fileRef = F50D9DED02EE0AB101BB4219;
isa = PBXBuildFile;
settings = {
};
};
F50D9DF002EE0AB101BB4219 = {
fileRef = F50D9DEE02EE0AB101BB4219;
isa = PBXBuildFile;
settings = {
};
};
F50D9DF102EE194001BB4219 = {
isa = PBXFileReference;
path = DownloadFactories.h;
refType = 4;
};
F50D9DF202EE194001BB4219 = {
isa = PBXFileReference;
path = DownloadFactories.mm;
refType = 4;
};
F50D9DF302EE194001BB4219 = {
fileRef = F50D9DF102EE194001BB4219;
isa = PBXBuildFile;
settings = {
};
};
F50D9DF402EE194001BB4219 = {
fileRef = F50D9DF202EE194001BB4219;
isa = PBXBuildFile;
settings = {
};
};
F50D9DF502EE2B9A01BB4219 = {
isa = PBXFileReference;
path = SaveHeaderSniffer.h;
refType = 4;
};
F50D9DF602EE2B9A01BB4219 = {
isa = PBXFileReference;
path = SaveHeaderSniffer.mm;
refType = 4;
};
F50D9DF702EE2B9B01BB4219 = {
fileRef = F50D9DF502EE2B9A01BB4219;
isa = PBXBuildFile;
settings = {
};
};
F50D9DF802EE2B9B01BB4219 = {
fileRef = F50D9DF602EE2B9A01BB4219;
isa = PBXBuildFile;
settings = {
};
};
F50D9DF902EE2C1D01BB4219 = {
children = (
F50D9DF102EE194001BB4219,
F50D9DF202EE194001BB4219,
F50D9DED02EE0AB101BB4219,
F50D9DEE02EE0AB101BB4219,
);
isa = PBXGroup;
name = Generic;
refType = 4;
};
F50D9DFA02EE2C1D01BB4219 = {
children = (
F50D9DF502EE2B9A01BB4219,
F50D9DF602EE2B9A01BB4219,
F517395B020CE3740189DA0C,
F50D9DE302ECC2C601BB4219,
);
isa = PBXGroup;
name = Chimera;
path = "";
refType = 4;
};
F50DCB4302C2856001A967F3 = {
isa = PBXFileReference;
name = libjsj.dylib;
@ -1143,7 +1291,6 @@
F512F52B02D1287F01072C9F = {
children = (
F5DE10E90209DC0601A967DF,
F517395B020CE3740189DA0C,
F528E21A020FD9620168DE43,
);
isa = PBXGroup;
@ -1176,7 +1323,6 @@
};
F512F53302D17A2601072C9F = {
children = (
F55C4DD302D2864D0130B065,
29B97316FDCFA39411CA2CEA,
F59236C002C89AC90100012B,
F5AE04BA0206A4FE01A967DF,
@ -1330,6 +1476,7 @@
F507BA480213AD5F01D93544,
F57074B5026BA85F01A80166,
F57074B9026BFD0101A80166,
2EEC3E61028138714B000102,
F57074BD026D80DF01A80166,
2E293A00027F33604B000102,
F5607CB5023944AD01A967DF,
@ -1344,6 +1491,8 @@
F53E013202AEEA2801A967F3,
F5A3669302CCFAF601DC3354,
F59236C102C89AC90100012B,
F50D9DE202ECC2C601BB4219,
F55C4DD302D2864D0130B065,
);
isa = PBXGroup;
name = Headers;
@ -4375,7 +4524,6 @@
F57074B6026BA85F01A80166,
F57074BA026BFD0101A80166,
F53E012C02AEE93601A967F3,
2EEC3E61028138714B000102,
2EEC3E62028138714B000102,
);
isa = PBXGroup;
@ -4959,6 +5107,8 @@
F53E013402AEEA2901A967F3,
F59236C402C89ACA0100012B,
F5A3669A02CCFB7A01DC3354,
F50D9DE702ECC36201BB4219,
F50D9DE802ECC36201BB4219,
);
isa = PBXHeadersBuildPhase;
name = Headers;
@ -5074,6 +5224,7 @@
F59236C502C89ACA0100012B,
F5A3669B02CCFB7A01DC3354,
F5A3669C02CCFB7A01DC3354,
F50D9DE902ECC36201BB4219,
);
isa = PBXSourcesBuildPhase;
name = Sources;

Просмотреть файл

Просмотреть файл

@ -0,0 +1,120 @@
/* ***** 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):
* 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 ***** */
// This file contains implementations of factories for various
// downloading-related interfaces.
#import "DownloadProgressDisplay.h"
#import "ProgressDlgController.h"
#include "nsCOMPtr.h"
#include "nsIFactory.h"
#include "nsDownloadListener.h"
#include "DownloadFactories.h"
// factory for nsIDownload objects
// XXX replace with generic factory stuff
class DownloadListenerFactory : public nsIFactory
{
public:
DownloadListenerFactory();
virtual ~DownloadListenerFactory();
NS_DECL_ISUPPORTS
NS_DECL_NSIFACTORY
protected:
DownloadControllerFactory* mControllerFactory; // factory which creates the Cocoa window controller
};
DownloadListenerFactory::DownloadListenerFactory()
: mControllerFactory(nil)
{
NS_INIT_ISUPPORTS();
mControllerFactory = [[[ChimeraDownloadControllerFactory alloc] init] retain];
}
DownloadListenerFactory::~DownloadListenerFactory()
{
[mControllerFactory release];
}
NS_IMPL_ISUPPORTS1(DownloadListenerFactory, nsIFactory);
/* void createInstance (in nsISupports aOuter, in nsIIDRef iid, [iid_is (iid), retval] out nsQIResult result); */
NS_IMETHODIMP
DownloadListenerFactory::CreateInstance(nsISupports *aOuter, const nsIID& aIID, void* *aResult)
{
nsresult rv;
if (aIID.Equals(NS_GET_IID(nsIDownload)))
{
nsDownloadListener* downloadListener = new nsDownloadListener(mControllerFactory);
if (!downloadListener) return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(downloadListener);
rv = downloadListener->QueryInterface(aIID, aResult);
NS_RELEASE(downloadListener);
return rv;
}
return NS_ERROR_NO_INTERFACE;
}
/* void lockFactory (in PRBool lock); */
NS_IMETHODIMP
DownloadListenerFactory::LockFactory(PRBool lock)
{
return NS_OK;
}
#pragma mark -
nsresult NewDownloadListenerFactory(nsIFactory* *outFactory)
{
DownloadListenerFactory* newFactory = new DownloadListenerFactory();
if (!newFactory) return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(newFactory);
nsresult rv = newFactory->QueryInterface(NS_GET_IID(nsIFactory), (void **)outFactory);
NS_RELEASE(newFactory);
return rv;
}

Просмотреть файл

@ -0,0 +1,161 @@
/* ***** 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):
* 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 ***** */
/*
The classes and protocol in this file allow Cocoa applications to easily
reuse the underlying download implementation, which deals with the complexity
of Gecko's downloading callbacks.
There are three things here:
1. The DownloadProgressDisplay protocol.
This is a formal protocol that needs to be implemented by
a window controller for your progress window. Its methods
will be called by the underlying C++ downloading classes.
2. The Obj-C DownloadControllerFactory class.
This class should be subclassed by an embedder, with an
implementation of 'createDownloadController' that hands back
a new instance of an NSWindowController that implements the
<DownloadProgressDisplay> protocol.
The underlying C++ classes use this factory to create the
progress window controller.
3. The nsDownloader C++ class
This base class exists to hide the complextity of the download
listener classes (which deal with Gecko callbacks) from the
window controller. Embedders don't need to do anything with it.
How these classes fit together:
There are 2 ways in which a download is initiated:
(i) File->Save.
Chimera does a complex dance here in order to get certain
information about the data being downloaded (it needs to
start the download before it can read some optional MIME headers).
CBrowserView creates an nsIWebBrowserPersist (WBP), and then a
nsHeaderSniffer, which implements nsIWebProgressListener and is set to
observer the WBP. When nsHeaderSniffer hears about the start of the
download, it decides on a file name, and what format to save the data
in. It then cancels the current WPB, makes another one, and does
a CreateInstance of an nsIDownload (making one of our nsDownloadListener
-- aka nsDownloder -- objects), and sets that as the nsIWebProgressListener.
The full download procedes from there.
(ii) Click to download (e.g. FTP link)
This is simpler. The backend (necko) does the CreateInstance of the
nsIDownload, and the download progresses.
In both cases, creating the nsDownloadListener and calling its Init() method
calls nsDownloder::CreateDownloadDisplay(). The nsDownloder has as a member
variable a DownloadControllerFactory (see above), which got passed to it
via our XPCOM factory for nsIDownload objects. It then uses that DownloadControllerFactory
to get an instance of the download progress window controller, which then
shows the download progress window.
Simple, eh?
*/
#import <AppKit/AppKit.h>
#include "nsISupports.h"
class nsDownloader;
// a formal protocol for something that implements progress display
// Embedders can make a window controller that conforms to this
// protocol, and reuse nsDownloadListener to get download UI.
@protocol DownloadProgressDisplay
- (void)onStartDownload;
- (void)onEndDownload;
- (void)setProgressTo:(long)aCurProgress ofMax:(long)aMaxProgress;
- (void)setDownloadListener:(nsDownloader*)aDownloader;
- (void)setSourceURL:(NSString*)aSourceURL;
- (void)setDestinationPath:(NSString*)aDestPath;
@end
// subclass this, and have your subclass instantiate and return your window
// controller in createDownloadController
@interface DownloadControllerFactory : NSObject
{
}
- (NSWindowController<DownloadProgressDisplay> *)createDownloadController;
@end
// Pure virtual base class for a generic downloader, that the progress UI can talk to.
// It implements nsISupports so that it can be refcounted. This class insulates the
// UI code from having to know too much about the nsIDownloadListener.
// It is responsible for creating the download UI, via the DownloadControllerFactory
// that it owns.
class nsDownloader : public nsISupports
{
public:
nsDownloader(DownloadControllerFactory* inControllerFactory);
virtual ~nsDownloader();
NS_DECL_ISUPPORTS
virtual void PauseDownload() = 0;
virtual void ResumeDownload() = 0;
virtual void CancelDownload() = 0;
virtual void DownloadDone() = 0;
virtual void CreateDownloadDisplay();
protected:
DownloadControllerFactory* mControllerFactory;
id <DownloadProgressDisplay> mDownloadDisplay; // something that implements the DownloadProgressDisplay protocol
};

Просмотреть файл

@ -0,0 +1,75 @@
/* ***** 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):
* 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 ***** */
#import "DownloadProgressDisplay.h"
@implementation DownloadControllerFactory
- (NSWindowController<DownloadProgressDisplay> *)createDownloadController
{
// a dummy implementation. You should provide a subclass that
// returns an instance of your progress dialog controller.
return nil;
}
@end
#pragma mark -
// see the header file for comments
nsDownloader::nsDownloader(DownloadControllerFactory* inControllerFactory)
: mControllerFactory(inControllerFactory)
, mDownloadDisplay(nil)
{
NS_INIT_ISUPPORTS();
[mControllerFactory retain];
}
nsDownloader::~nsDownloader()
{
[mControllerFactory release];
}
NS_IMPL_ISUPPORTS1(nsDownloader, nsISupports);
void
nsDownloader::CreateDownloadDisplay()
{
mDownloadDisplay = [mControllerFactory createDownloadController];
[mDownloadDisplay setDownloadListener:this];
}

6
chimera/English.lproj/MainMenu.nib/info.nib сгенерированный
Просмотреть файл

@ -3,13 +3,13 @@
<plist version="0.9">
<dict>
<key>IBDocumentLocation</key>
<string>73 360 356 240 0 0 1152 848 </string>
<string>61 108 356 240 0 0 1152 746 </string>
<key>IBEditorPositions</key>
<dict>
<key>266</key>
<string>418 452 277 90 0 0 1152 746 </string>
<string>23 342 277 90 0 0 1152 746 </string>
<key>29</key>
<string>8 803 446 44 0 0 1152 848 </string>
<string>8 701 446 44 0 0 1152 746 </string>
</dict>
<key>IBFramework Version</key>
<string>248.0</string>

Двоичные данные
chimera/English.lproj/MainMenu.nib/objects.nib сгенерированный

Двоичный файл не отображается.

19
chimera/English.lproj/ProgressDialog.nib/classes.nib сгенерированный
Просмотреть файл

@ -1,19 +0,0 @@
{
IBClasses = (
{CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; },
{
CLASS = ProgressDlgController;
LANGUAGE = ObjC;
OUTLETS = {
mElapsedTimeLabel = id;
mFromField = id;
mProgressBar = id;
mStatusLabel = id;
mTimeLeftLabel = id;
mToField = id;
};
SUPERCLASS = NSWindowController;
}
);
IBVersion = 1;
}

4
chimera/English.lproj/ProgressDialog.nib/info.nib сгенерированный
Просмотреть файл

@ -3,7 +3,7 @@
<plist version="0.9">
<dict>
<key>IBDocumentLocation</key>
<string>152 212 356 240 0 0 1024 746 </string>
<string>94 26 404 250 0 0 1152 746 </string>
<key>IBFramework Version</key>
<string>248.0</string>
<key>IBOpenObjects</key>
@ -11,6 +11,6 @@
<integer>5</integer>
</array>
<key>IBSystem Version</key>
<string>5Q125</string>
<string>5S66</string>
</dict>
</plist>

Двоичные данные
chimera/English.lproj/ProgressDialog.nib/objects.nib сгенерированный

Двоичный файл не отображается.

6
chimera/MainMenu.nib/info.nib сгенерированный
Просмотреть файл

@ -3,13 +3,13 @@
<plist version="0.9">
<dict>
<key>IBDocumentLocation</key>
<string>73 360 356 240 0 0 1152 848 </string>
<string>61 108 356 240 0 0 1152 746 </string>
<key>IBEditorPositions</key>
<dict>
<key>266</key>
<string>418 452 277 90 0 0 1152 746 </string>
<string>23 342 277 90 0 0 1152 746 </string>
<key>29</key>
<string>8 803 446 44 0 0 1152 848 </string>
<string>8 701 446 44 0 0 1152 746 </string>
</dict>
<key>IBFramework Version</key>
<string>248.0</string>

Двоичные данные
chimera/MainMenu.nib/objects.nib сгенерированный

Двоичный файл не отображается.

19
chimera/ProgressDialog.nib/classes.nib сгенерированный
Просмотреть файл

@ -1,19 +0,0 @@
{
IBClasses = (
{CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; },
{
CLASS = ProgressDlgController;
LANGUAGE = ObjC;
OUTLETS = {
mElapsedTimeLabel = id;
mFromField = id;
mProgressBar = id;
mStatusLabel = id;
mTimeLeftLabel = id;
mToField = id;
};
SUPERCLASS = NSWindowController;
}
);
IBVersion = 1;
}

4
chimera/ProgressDialog.nib/info.nib сгенерированный
Просмотреть файл

@ -3,7 +3,7 @@
<plist version="0.9">
<dict>
<key>IBDocumentLocation</key>
<string>152 212 356 240 0 0 1024 746 </string>
<string>94 26 404 250 0 0 1152 746 </string>
<key>IBFramework Version</key>
<string>248.0</string>
<key>IBOpenObjects</key>
@ -11,6 +11,6 @@
<integer>5</integer>
</array>
<key>IBSystem Version</key>
<string>5Q125</string>
<string>5S66</string>
</dict>
</plist>

Двоичные данные
chimera/ProgressDialog.nib/objects.nib сгенерированный

Двоичный файл не отображается.

Просмотреть файл

@ -36,6 +36,9 @@
* ***** END LICENSE BLOCK ***** */
#import <AppKit/AppKit.h>
#import "DownloadProgressDisplay.h"
#include "nscore.h"
class nsIWebBrowserPersist;
@ -43,42 +46,37 @@ class nsISupports;
class nsIInputStream;
class nsDownloadListener;
@interface ProgressDlgController : NSWindowController {
IBOutlet id mFromField;
IBOutlet id mToField;
IBOutlet id mStatusLabel;
IBOutlet id mTimeLeftLabel;
IBOutlet id mElapsedTimeLabel;
IBOutlet id mProgressBar;
@interface ChimeraDownloadControllerFactory : DownloadControllerFactory
@end
@interface ProgressDlgController : NSWindowController <DownloadProgressDisplay>
{
IBOutlet NSTextField *mElapsedTimeLabel;
IBOutlet NSTextField *mFromField;
IBOutlet NSTextField *mStatusLabel;
IBOutlet NSTextField *mTimeLeftLabel;
IBOutlet NSTextField *mToField;
IBOutlet NSProgressIndicator *mProgressBar;
NSToolbarItem *pauseResumeToggleToolbarItem;
NSToolbarItem *leaveOpenToggleToolbarItem;
BOOL mDownloadIsPaused;
BOOL mSaveFileDialogShouldStayOpen;
BOOL mDownloadIsComplete;
long int aCurrentProgress; // if progress bar is indeterminate, can still calc stats.
BOOL mDownloadIsPaused;
BOOL mSaveFileDialogShouldStayOpen;
BOOL mDownloadIsComplete;
long mCurrentProgress; // if progress bar is indeterminate, can still calc stats.
nsDownloadListener* mDownloadListener;
NSTimer *mDownloadTimer;
nsDownloader *mDownloader; // we hold a ref to this
NSTimer *mDownloadTimer;
}
-(void) setWebPersist: (nsIWebBrowserPersist*)aPersist
source: (nsISupports*)aSource
destination: (NSString*)aDestination
contentType: (const char*)aContentType
postData: (nsIInputStream*)aInputStream
bypassCache: (BOOL)aBypassCache;
-(void) setProgressBar:(long int)aCurProgress
maxProg:(long int)aMaxProgress;
-(void) setDownloadTimer;
-(void) setupDownloadTimer;
-(void) killDownloadTimer;
-(void) setDownloadProgress:(NSTimer *)aTimer;
-(NSString *) formatTime:(int)aSeconds;
-(NSString *) formatFuzzyTime:(int)aSeconds;
-(NSString *) formatBytes:(float)aBytes;
-(void) setSourceURL: (const PRUnichar*)aSource;
-(void) setDestination: (const PRUnichar*)aDestination;
@end

Просмотреть файл

@ -46,282 +46,58 @@
#include "nsILocalFile.h"
#include "nsIDOMHTMLDocument.h"
#include "nsIWebProgressListener.h"
#include "nsIDownload.h"
#include "nsIComponentManager.h"
#include "nsIPref.h"
class nsDownloadListener : public nsIWebProgressListener
{
public:
nsDownloadListener(ProgressDlgController* aController,
nsIWebBrowserPersist* aPersist,
nsISupports* aSource,
NSString* aDestination,
const char* aContentType,
nsIInputStream* aPostData,
BOOL aBypassCache)
{
NS_INIT_ISUPPORTS();
mController = aController;
mWebPersist = aPersist;
// The source is either a simple URL or a complete document.
mURL = do_QueryInterface(aSource);
if (!mURL)
mDocument = do_QueryInterface(aSource);
PRUint32 dstLen = [aDestination length];
PRUnichar* tmp = new PRUnichar[dstLen + sizeof(PRUnichar)];
tmp[dstLen] = (PRUnichar)'\0';
[aDestination getCharacters:tmp];
nsAutoString dstStr(tmp);
delete tmp;
NS_NewLocalFile(dstStr, PR_FALSE, getter_AddRefs(mDestination));
// XXX check for failure
mContentType = aContentType;
mPostData = aPostData;
mBypassCache = aBypassCache;
mNetworkTransfer = PR_FALSE;
mGotFirstStateChange = PR_FALSE;
};
virtual ~nsDownloadListener() {};
NS_DECL_ISUPPORTS
NS_DECL_NSIWEBPROGRESSLISTENER
public:
void BeginDownload();
void InitDialog();
void CancelDownload();
private: // Member variables
ProgressDlgController* mController; // Controller for our UI.
nsCOMPtr<nsIWebBrowserPersist> mWebPersist; // Our web persist object.
nsCOMPtr<nsIURL> mURL; // The URL of our source file. Null if we're saving a complete document.
nsCOMPtr<nsILocalFile> mDestination; // Our destination URL.
nsCString mContentType; // Our content type string.
nsCOMPtr<nsIDOMHTMLDocument> mDocument; // A DOM document. Null if we're only saving a simple URL.
nsCOMPtr<nsIInputStream> mPostData; // For complete documents, this is our post data from session history.
PRPackedBool mBypassCache; // Whether we should bypass the cache or not.
PRPackedBool mNetworkTransfer; // true if the first OnStateChange has the NETWORK bit set
PRPackedBool mGotFirstStateChange; // true after we've seen the first OnStateChange
};
NS_IMPL_ISUPPORTS1(nsDownloadListener, nsIWebProgressListener)
/* void onProgressChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in long aCurSelfProgress, in long aMaxSelfProgress, in long aCurTotalProgress, in long aMaxTotalProgress); */
NS_IMETHODIMP
nsDownloadListener::OnProgressChange(nsIWebProgress *aWebProgress,
nsIRequest *aRequest,
PRInt32 aCurSelfProgress,
PRInt32 aMaxSelfProgress,
PRInt32 aCurTotalProgress,
PRInt32 aMaxTotalProgress)
{
[mController setProgressBar:aCurTotalProgress maxProg:aMaxTotalProgress];
return NS_OK;
}
/* void onLocationChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in nsIURI location); */
NS_IMETHODIMP
nsDownloadListener::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
nsDownloadListener::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
nsDownloadListener::OnSecurityChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, PRUint32 state)
{
return NS_OK;
}
// Implementation of nsIWebProgressListener
/* void onStateChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in unsigned long aStateFlags, in unsigned long aStatus); */
NS_IMETHODIMP
nsDownloadListener::OnStateChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, PRUint32 aStateFlags,
PRUint32 aStatus)
{
// NSLog(@"State changed: state %u, status %u", aStateFlags, aStatus);
if (!mGotFirstStateChange) {
mNetworkTransfer = ((aStateFlags & STATE_IS_NETWORK) != 0);
mGotFirstStateChange = PR_TRUE;
}
// when the entire download finishes, stop the progress timer and clean up
// the window and controller. We will get this even in the event of a cancel,
// so this is the only place in the listener where we should kill the download.
if ((aStateFlags & STATE_STOP) && (!mNetworkTransfer || (aStateFlags & STATE_IS_NETWORK))) {
[mController killDownloadTimer];
[mController setDownloadProgress:nil];
}
return NS_OK;
}
void
nsDownloadListener::BeginDownload()
{
if (mWebPersist) {
mWebPersist->SetProgressListener(this);
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;
if (mURL)
mWebPersist->SaveURI(mURL, mPostData, mDestination);
else {
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;
mDestination->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)
filesFolder->Create(nsILocalFile::DIRECTORY_TYPE, 0755);
}
else
encodingFlags |= nsIWebBrowserPersist::ENCODE_FLAGS_FORMATTED |
nsIWebBrowserPersist::ENCODE_FLAGS_ABSOLUTE_LINKS |
nsIWebBrowserPersist::ENCODE_FLAGS_NOFRAMES_CONTENT;
mWebPersist->SaveDocument(mDocument, mDestination, filesFolder, mContentType.get(),
encodingFlags, 80);
}
}
InitDialog();
}
void
nsDownloadListener::InitDialog()
{
if (!mURL && !mDocument)
return;
if (mWebPersist) {
if (mURL) {
nsCAutoString spec;
mURL->GetSpec(spec);
nsAutoString spec2; spec2.AssignWithConversion(spec.get());
[mController setSourceURL: spec2.get()];
}
else {
nsAutoString spec;
mDocument->GetURL(spec);
[mController setSourceURL: spec.get()];
}
}
nsAutoString pathStr;
mDestination->GetPath(pathStr);
[mController setDestination: pathStr.get()];
[mController setDownloadTimer];
}
void
nsDownloadListener::CancelDownload()
{
if (mWebPersist)
mWebPersist->CancelSave();
}
static NSString *SaveFileToolbarIdentifier = @"Save File Dialog Toolbar";
static NSString *CancelToolbarItemIdentifier = @"Cancel Toolbar Item";
static NSString *SaveFileToolbarIdentifier = @"Save File Dialog Toolbar";
static NSString *CancelToolbarItemIdentifier = @"Cancel Toolbar Item";
static NSString *PauseResumeToolbarItemIdentifier = @"Pause and Resume Toggle Toolbar Item";
static NSString *ShowFileToolbarItemIdentifier = @"Show File Toolbar Item";
static NSString *OpenFileToolbarItemIdentifier = @"Open File Toolbar Item";
static NSString *LeaveOpenToolbarItemIdentifier = @"Leave Open Toggle Toolbar Item";
@implementation ChimeraDownloadControllerFactory : DownloadControllerFactory
- (NSWindowController<DownloadProgressDisplay> *)createDownloadController
{
NSWindowController* progressController = [[ProgressDlgController alloc] initWithWindowNibName: @"ProgressDialog"];
NSAssert([progressController conformsToProtocol:@protocol(DownloadProgressDisplay)],
@"progressController should conform to DownloadProgressDisplay protocol");
return progressController;
}
@end
#pragma mark -
@interface ProgressDlgController(Private)
-(void)setupToolbar;
@end
@implementation ProgressDlgController
-(void)setWebPersist:(nsIWebBrowserPersist*)aPersist
source:(nsISupports*)aSource
destination:(NSString*)aDestination
contentType:(const char*)aContentType
postData:(nsIInputStream*)aInputStream
bypassCache:(BOOL)aBypassCache
- (void)dealloc
{
mDownloadListener = new nsDownloadListener(self, aPersist, aSource,
aDestination, aContentType,
aInputStream, aBypassCache);
NS_ADDREF(mDownloadListener);
}
-(void) setProgressBar:(long int)curProgress maxProg:(long int)maxProgress
{
aCurrentProgress = curProgress; // fall back for stat calcs
if (![mProgressBar isIndeterminate]) { //most likely - just update value
if (curProgress == maxProgress) //handles little bug in FTP download size
[mProgressBar setMaxValue:maxProgress];
[mProgressBar setDoubleValue:curProgress];
}
else if (maxProgress > 0) { // ok, we're starting up with good max & cur values
[mProgressBar setIndeterminate:NO];
[mProgressBar setMaxValue:maxProgress];
[mProgressBar setDoubleValue:curProgress];
} // if neither case was true, it's barber pole city.
}
-(void) setSourceURL: (const PRUnichar*)aSource
{
[mFromField setStringValue: [NSString stringWithCharacters:aSource length:nsCRT::strlen(aSource)]];
}
-(void) setDestination: (const PRUnichar*)aDestination
{
[mToField setStringValue: [[NSString stringWithCharacters:aDestination length:nsCRT::strlen(aDestination)] stringByAbbreviatingWithTildeInPath]];
NS_IF_RELEASE(mDownloader);
[super dealloc];
}
- (void)windowDidLoad
{
mDownloadIsPaused = NO;
mDownloadIsComplete = NO;
nsCOMPtr<nsIPref> prefs(do_GetService(NS_PREF_CONTRACTID));
PRBool save = PR_FALSE;
prefs->GetBoolPref("browser.download.progressDnldDialog.keepAlive",&save);
prefs->GetBoolPref("browser.download.progressDnldDialog.keepAlive", &save);
mSaveFileDialogShouldStayOpen = save;
[self setupToolbar];
[mProgressBar setUsesThreadedAnimation:YES];
[mProgressBar startAnimation:self];
if (mDownloadListener)
mDownloadListener->BeginDownload();
[mProgressBar startAnimation:self]; // move to onStateChange
}
- (void)setupToolbar
@ -438,7 +214,9 @@ static NSString *LeaveOpenToolbarItemIdentifier = @"Leave Open Toggle Toolbar
-(void)cancel
{
mDownloadListener->CancelDownload();
if (mDownloader) // we should always have one
mDownloader->CancelDownload();
// clean up downloaded file. - do it here on in CancelDownload?
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *thePath = [[mToField stringValue] stringByExpandingTildeInPath];
@ -457,22 +235,29 @@ static NSString *LeaveOpenToolbarItemIdentifier = @"Leave Open Toggle Toolbar
-(void)pauseAndResumeDownload
{
if ( ! mDownloadIsPaused ) {
//Do logic to pause download
if ( !mDownloadIsPaused )
{
mDownloadIsPaused = YES;
[pauseResumeToggleToolbarItem setLabel:@"Resume"];
[pauseResumeToggleToolbarItem setPaletteLabel:@"Resume Download"];
[pauseResumeToggleToolbarItem setToolTip:@"Resume the paused FTP download"];
[pauseResumeToggleToolbarItem setImage:[NSImage imageNamed:@"saveResume"]];
[self killDownloadTimer];
} else {
//Do logic to resume download
if (mDownloader) // we should always have one
mDownloader->PauseDownload();
}
else
{
mDownloadIsPaused = NO;
[pauseResumeToggleToolbarItem setLabel:@"Pause"];
[pauseResumeToggleToolbarItem setPaletteLabel:@"Pause Download"];
[pauseResumeToggleToolbarItem setToolTip:@"Pause this FTP file download"];
[pauseResumeToggleToolbarItem setImage:[NSImage imageNamed:@"savePause"]];
[self setDownloadTimer];
[self setupDownloadTimer];
if (mDownloader) // we should always have one
mDownloader->ResumeDownload();
}
}
@ -531,12 +316,6 @@ static NSString *LeaveOpenToolbarItemIdentifier = @"Leave Open Toggle Toolbar
return YES;
}
- (void)dealloc
{
NS_IF_RELEASE(mDownloadListener);
[super dealloc];
}
- (void)killDownloadTimer
{
if (mDownloadTimer) {
@ -545,7 +324,7 @@ static NSString *LeaveOpenToolbarItemIdentifier = @"Leave Open Toggle Toolbar
mDownloadTimer = nil;
}
}
- (void)setDownloadTimer
- (void)setupDownloadTimer
{
[self killDownloadTimer];
mDownloadTimer = [[NSTimer scheduledTimerWithTimeInterval:1.0
@ -590,7 +369,7 @@ static NSString *LeaveOpenToolbarItemIdentifier = @"Leave Open Toggle Toolbar
return [[[NSString alloc] initWithString:[[NSBundle mainBundle] localizedStringForKey:@"UnderMin" value:@"Under a minute" table:@"ProgressDialog"]] autorelease];
}
// seconds becomes minutes and we keep checking.
seconds=seconds/60;
seconds = seconds/60;
if (seconds < 60) {
if (seconds < 2)
return [[[NSString alloc] initWithString:[[NSBundle mainBundle] localizedStringForKey:@"AboutMin" value:@"About a minute" table:@"ProgressDialog"]] autorelease];
@ -598,7 +377,7 @@ static NSString *LeaveOpenToolbarItemIdentifier = @"Leave Open Toggle Toolbar
return [[[NSString alloc] initWithFormat:[[NSBundle mainBundle] localizedStringForKey:@"AboutMins" value:@"About %d minutes" table:@"ProgressDialog"],seconds] autorelease];
}
//this download will never seemingly never end. now seconds become hours.
seconds=seconds/60;
seconds = seconds/60;
if (seconds < 2)
return [[[NSString alloc] initWithString:[[NSBundle mainBundle] localizedStringForKey:@"AboutHour" value:@"Over an hour" table:@"ProgressDialog"]] autorelease];
return [[[NSString alloc] initWithFormat:[[NSBundle mainBundle] localizedStringForKey:@"AboutHours" value:@"Over %d hours" table:@"ProgressDialog"],seconds] autorelease];
@ -629,8 +408,11 @@ static NSString *LeaveOpenToolbarItemIdentifier = @"Leave Open Toggle Toolbar
// this handles lots of things.
- (void)setDownloadProgress:(NSTimer *)downloadTimer;
{
// XXX this logic needs cleaning up.
// Ack! we're closing the window with the download still running!
if (mDownloadIsComplete) {
if (mDownloadIsComplete)
{
[[self window] performClose:self];
return;
}
@ -644,26 +426,28 @@ static NSString *LeaveOpenToolbarItemIdentifier = @"Leave Open Toggle Toolbar
[mElapsedTimeLabel setStringValue:[self formatTime:(++elapsedSec)]];
// for status field & time left
float maxBytes = ([mProgressBar maxValue]);
float byteSec = aCurrentProgress/elapsedSec;
float byteSec = mCurrentProgress/elapsedSec;
// OK - if downloadTimer is nil, we're done - fix maxBytes value for status report.
if (!downloadTimer)
maxBytes = aCurrentProgress;
maxBytes = mCurrentProgress;
// update status field
NSString *labelString = [[NSBundle mainBundle] localizedStringForKey:@"LabelString"
value:@"%@ of %@ total (at %@/sec)"
table:@"ProgressDialog"];
[mStatusLabel setStringValue: [NSString stringWithFormat:labelString, [self formatBytes:aCurrentProgress], [self formatBytes:maxBytes], [self formatBytes:byteSec]]];
[mStatusLabel setStringValue: [NSString stringWithFormat:labelString, [self formatBytes:mCurrentProgress], [self formatBytes:maxBytes], [self formatBytes:byteSec]]];
// updating estimated time left field
// if maxBytes < 0, can't calc time left.
// if !downloadTimer, download is finished. either way, make sure time left is 0.
if ((maxBytes > 0) && (downloadTimer)) {
int secToGo = (int)ceil((elapsedSec*maxBytes/aCurrentProgress)-elapsedSec);
if ((maxBytes > 0) && (downloadTimer))
{
int secToGo = (int)ceil((elapsedSec*maxBytes/mCurrentProgress) - elapsedSec);
[mTimeLeftLabel setStringValue:[self formatFuzzyTime:secToGo]];
}
else if (!downloadTimer) { // download done. Set remaining time to 0, fix progress bar & cancel button
else if (!downloadTimer)
{ // download done. Set remaining time to 0, fix progress bar & cancel button
mDownloadIsComplete = YES; // all done. we got a STATE_STOP
[mTimeLeftLabel setStringValue:@""];
[self setProgressBar:aCurrentProgress maxProg:aCurrentProgress];
[self setProgressTo:mCurrentProgress ofMax:mCurrentProgress];
if (!mSaveFileDialogShouldStayOpen)
[[self window] performClose:self]; // close window
else
@ -673,4 +457,59 @@ static NSString *LeaveOpenToolbarItemIdentifier = @"Leave Open Toggle Toolbar
[mTimeLeftLabel setStringValue:@"???"];
}
#pragma mark -
// DownloadProgressDisplay protocol methods
- (void)onStartDownload
{
[self showWindow: self];
[self setupDownloadTimer];
}
- (void)onEndDownload
{
[self killDownloadTimer];
[self setDownloadProgress:nil];
}
- (void)setProgressTo:(long)aCurProgress ofMax:(long)aMaxProgress
{
mCurrentProgress = aCurProgress; // fall back for stat calcs
if (![mProgressBar isIndeterminate]) //most likely - just update value
{
if (aCurProgress == aMaxProgress) //handles little bug in FTP download size
[mProgressBar setMaxValue:aMaxProgress];
[mProgressBar setDoubleValue:aCurProgress];
}
else if (aMaxProgress > 0) // ok, we're starting up with good max & cur values
{
[mProgressBar setIndeterminate:NO];
[mProgressBar setMaxValue:aMaxProgress];
[mProgressBar setDoubleValue:aCurProgress];
} // if neither case was true, it's barber pole city.
}
-(void) setDownloadListener: (nsDownloader*)aDownloader
{
if (mDownloader != aDownloader)
NS_IF_RELEASE(mDownloader);
NS_IF_ADDREF(mDownloader = aDownloader);
}
- (void)setSourceURL:(NSString*)aSourceURL
{
[mFromField setStringValue: aSourceURL];
[mFromField display]; // force an immmeditate update
}
- (void)setDestinationPath:(NSString*)aDestPath
{
[mToField setStringValue: [aDestPath stringByAbbreviatingWithTildeInPath]];
[mToField display]; // force an immmeditate update
}
@end

Просмотреть файл

Просмотреть файл

Просмотреть файл

@ -55,7 +55,7 @@ class nsCocoaBrowserService : public nsIWindowCreator,
public nsIPromptService,
public nsIFactory,
public nsIBadCertListener, public nsISecurityWarningDialogs, public nsINSSDialogs,
public nsIHelperAppLauncherDialog, public nsIDownload, public nsIWebProgressListener
public nsIHelperAppLauncherDialog
{
public:
nsCocoaBrowserService();
@ -69,8 +69,6 @@ public:
NS_DECL_NSIBADCERTLISTENER
NS_DECL_NSISECURITYWARNINGDIALOGS
NS_DECL_NSIHELPERAPPLAUNCHERDIALOG
NS_DECL_NSIDOWNLOAD
NS_DECL_NSIWEBPROGRESSLISTENER
static nsresult InitEmbedding();
static void TermEmbedding();

Просмотреть файл

@ -35,14 +35,15 @@
*
* ***** END LICENSE BLOCK ***** */
#include "nsCocoaBrowserService.h"
#import "nsCocoaBrowserService.h"
#import "DownloadFactories.h"
#import "CHBrowserView.h"
#include "nsIWindowWatcher.h"
#include "nsIWebBrowserChrome.h"
#include "nsIEmbeddingSiteWindow.h"
#include "nsIProfile.h"
#include "nsIPrefService.h"
#include "CHBrowserView.h"
#include "nsCRT.h"
#include "nsString.h"
#include "nsIPrompt.h"
@ -74,13 +75,14 @@ nsCocoaBrowserService::~nsCocoaBrowserService()
{
}
NS_IMPL_ISUPPORTS9(nsCocoaBrowserService,
NS_IMPL_ISUPPORTS7(nsCocoaBrowserService,
nsIWindowCreator,
nsIPromptService,
nsIFactory,
nsIBadCertListener, nsISecurityWarningDialogs, nsINSSDialogs,
nsIHelperAppLauncherDialog, nsIDownload, nsIWebProgressListener)
nsIHelperAppLauncherDialog)
/* static */
nsresult
nsCocoaBrowserService::InitEmbedding()
{
@ -103,7 +105,7 @@ nsCocoaBrowserService::InitEmbedding()
#define NS_PROMPTSERVICE_CID \
{0xa2112d6a, 0x0e28, 0x421f, {0xb4, 0x6a, 0x25, 0xc0, 0xb3, 0x8, 0xcb, 0xd0}}
static NS_DEFINE_CID(kPromptServiceCID, NS_PROMPTSERVICE_CID);
nsresult rv = cr->RegisterFactory(kPromptServiceCID, "Prompt Service", "@mozilla.org/embedcomp/prompt-service;1",
nsresult rv = cr->RegisterFactory(kPromptServiceCID, "Prompt Service", "@mozilla.org/embedcomp/prompt-service;1",
sSingleton);
if (NS_FAILED(rv))
return rv;
@ -127,14 +129,18 @@ nsCocoaBrowserService::InitEmbedding()
rv = cr->RegisterFactory(kHelperDlgCID, NS_IHELPERAPPLAUNCHERDLG_CLASSNAME, NS_IHELPERAPPLAUNCHERDLG_CONTRACTID,
sSingleton);
// replace the downloader with our own which does rely on the xpfe downlaod manager
// replace the downloader with our own which does not rely on the xpfe downlaod manager
nsCOMPtr<nsIFactory> downloadFactory;
rv = NewDownloadListenerFactory(getter_AddRefs(downloadFactory));
if (NS_FAILED(rv)) return rv;
static NS_DEFINE_CID(kDownloadCID, NS_DOWNLOAD_CID);
rv = cr->RegisterFactory(kDownloadCID, "Download", NS_DOWNLOAD_CONTRACTID,
sSingleton);
rv = cr->RegisterFactory(kDownloadCID, "Download", NS_DOWNLOAD_CONTRACTID, downloadFactory);
return rv;
}
/* static */
void
nsCocoaBrowserService::BrowserClosed()
{
@ -149,6 +155,7 @@ nsCocoaBrowserService::BrowserClosed()
}
}
/* static */
void
nsCocoaBrowserService::TermEmbedding()
{
@ -195,8 +202,15 @@ nsCocoaBrowserService::CreateInstance(nsISupports *aOuter,
const nsIID & aIID,
void **aResult)
{
NS_ENSURE_ARG_POINTER(aResult);
/*
if (aIID.Equals(NS_GET_IID(nsIHelperAppLauncherDialog)))
{
}
*/
return sSingleton->QueryInterface(aIID, aResult);
}
@ -828,14 +842,12 @@ nsCocoaBrowserService::ConfirmPostToInsecureFromSecure(nsIInterfaceRequestor *ct
NS_IMETHODIMP
nsCocoaBrowserService::Show(nsIHelperAppLauncher* inLauncher, nsISupports* inContext)
{
NSLog(@"Show");
return inLauncher->SaveToDisk(nsnull, PR_FALSE);
}
NS_IMETHODIMP
nsCocoaBrowserService::PromptForSaveToFile(nsISupports *aWindowContext, const PRUnichar *aDefaultFile, const PRUnichar *aSuggestedFileExtension, nsILocalFile **_retval)
{
NSLog(@"PromptForSaveToFile");
NSString* filename = [NSString stringWithCharacters:aDefaultFile length:nsCRT::strlen(aDefaultFile)];
NSSavePanel *thePanel = [NSSavePanel savePanel];
@ -844,7 +856,7 @@ NSLog(@"PromptForSaveToFile");
// use nil for the path given to runModalForDirectory
int runResult = [thePanel runModalForDirectory: nil file:filename];
if (runResult == NSOKButton) {
NSLog([thePanel filename]);
// NSLog(@"Saving to %@", [thePanel filename]);
NSString *theName = [thePanel filename];
return NS_NewNativeLocalFile(nsDependentCString([theName fileSystemRepresentation]), PR_FALSE, _retval);
}
@ -856,140 +868,6 @@ NSLog([thePanel filename]);
NS_IMETHODIMP
nsCocoaBrowserService::ShowProgressDialog(nsIHelperAppLauncher *aLauncher, nsISupports *aContext)
{
return NS_OK;
}
NS_IMETHODIMP
nsCocoaBrowserService::Init(nsIURI* aSource,
nsILocalFile* aTarget,
const PRUnichar* aDisplayName,
const PRUnichar* aOpeningWith,
PRInt64 aStartTime,
nsIWebBrowserPersist* aPersist)
{
NSLog(@"nsIDownload::Init");
return NS_OK;
}
NS_IMETHODIMP
nsCocoaBrowserService::GetDisplayName(PRUnichar** aDisplayName)
{
NS_ERROR("NS_ERROR_NOT_IMPLEMENTED");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsCocoaBrowserService::SetDisplayName(const PRUnichar* aDisplayName)
{
return NS_OK;
}
NS_IMETHODIMP
nsCocoaBrowserService::GetOpeningWith(PRUnichar** aOpeningWith)
{
NS_ERROR("NS_ERROR_NOT_IMPLEMENTED");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsCocoaBrowserService::GetSource(nsIURI** aSource)
{
NS_ERROR("NS_ERROR_NOT_IMPLEMENTED");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsCocoaBrowserService::GetTarget(nsILocalFile** aTarget)
{
NS_ERROR("NS_ERROR_NOT_IMPLEMENTED");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsCocoaBrowserService::GetStartTime(PRInt64* aStartTime)
{
NS_ERROR("NS_ERROR_NOT_IMPLEMENTED");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsCocoaBrowserService::GetPercentComplete(PRInt32* aPercentComplete)
{
NS_ERROR("NS_ERROR_NOT_IMPLEMENTED");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsCocoaBrowserService::GetListener(nsIWebProgressListener** aListener)
{
NS_ERROR("NS_ERROR_NOT_IMPLEMENTED");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsCocoaBrowserService::SetListener(nsIWebProgressListener* aListener)
{
return NS_OK;
}
NS_IMETHODIMP
nsCocoaBrowserService::GetObserver(nsIObserver** aObserver)
{
NS_ERROR("NS_ERROR_NOT_IMPLEMENTED");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsCocoaBrowserService::SetObserver(nsIObserver* aObserver)
{
return NS_OK;
}
NS_IMETHODIMP
nsCocoaBrowserService::GetPersist(nsIWebBrowserPersist** aPersist)
{
NS_ERROR("NS_ERROR_NOT_IMPLEMENTED");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsCocoaBrowserService::OnStateChange(nsIWebProgress* aWebProgress,
nsIRequest* aRequest, PRUint32 aStateFlags,
PRUint32 aStatus)
{
return NS_OK;
}
NS_IMETHODIMP
nsCocoaBrowserService::OnStatusChange(nsIWebProgress *aWebProgress,
nsIRequest *aRequest, nsresult aStatus,
const PRUnichar *aMessage)
{
return NS_OK;
}
NS_IMETHODIMP
nsCocoaBrowserService::OnLocationChange(nsIWebProgress *aWebProgress,
nsIRequest *aRequest, nsIURI *aLocation)
{
return NS_OK;
}
NS_IMETHODIMP
nsCocoaBrowserService::OnProgressChange(nsIWebProgress *aWebProgress,
nsIRequest *aRequest,
PRInt32 aCurSelfProgress,
PRInt32 aMaxSelfProgress,
PRInt32 aCurTotalProgress,
PRInt32 aMaxTotalProgress)
{
return NS_OK;
}
NS_IMETHODIMP
nsCocoaBrowserService::OnSecurityChange(nsIWebProgress *aWebProgress,
nsIRequest *aRequest, PRUint32 aState)
{
NSLog(@"nsCocoaBrowserService::ShowProgressDialog");
return NS_OK;
}

Просмотреть файл

@ -0,0 +1,88 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Netscape 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/NPL/
*
* 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):
* 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 NPL, 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 NPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#import <Foundation/Foundation.h>
#import <Appkit/Appkit.h>
#import "DownloadProgressDisplay.h"
#include "nsString.h"
#include "nsIDownload.h"
#include "nsIWebProgressListener.h"
#include "nsIWebBrowserPersist.h"
#include "nsIURI.h"
#include "nsILocalFile.h"
// maybe this should replace nsHeaderSniffer too?
class nsDownloadListener : public nsDownloader,
public nsIDownload,
public nsIWebProgressListener
{
public:
nsDownloadListener(DownloadControllerFactory* inDownloadControllerFactory);
virtual ~nsDownloadListener();
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSIDOWNLOAD
NS_DECL_NSIWEBPROGRESSLISTENER
public:
//void BeginDownload();
void InitDialog();
virtual void PauseDownload();
virtual void ResumeDownload();
virtual void CancelDownload();
virtual void DownloadDone();
private:
nsCOMPtr<nsIWebBrowserPersist> mWebPersist; // Our web persist object.
nsCOMPtr<nsIURI> mURI; // The URI of our source file. Null if we're saving a complete document.
nsCOMPtr<nsILocalFile> mDestination; // Our destination URL.
PRInt64 mStartTime; // When the download started
PRPackedBool mBypassCache; // Whether we should bypass the cache or not.
PRPackedBool mNetworkTransfer; // true if the first OnStateChange has the NETWORK bit set
PRPackedBool mGotFirstStateChange; // true after we've seen the first OnStateChange
PRPackedBool mUserCanceled; // true if the user canceled the download
};

Просмотреть файл

@ -0,0 +1,308 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Netscape 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/NPL/
*
* 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):
* 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 NPL, 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 NPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsDownloadListener.h"
#include "nsIWebProgress.h"
#include "nsIRequest.h"
#include "nsIURL.h"
#include "netCore.h"
nsDownloadListener::nsDownloadListener(DownloadControllerFactory* inControllerFactory)
: nsDownloader(inControllerFactory)
, mBypassCache(PR_FALSE)
, mNetworkTransfer(PR_FALSE)
, mGotFirstStateChange(PR_FALSE)
, mUserCanceled(PR_FALSE)
{
}
nsDownloadListener::~nsDownloadListener()
{
}
NS_IMPL_ISUPPORTS_INHERITED2(nsDownloadListener, nsDownloader, nsIDownload, nsIWebProgressListener)
#pragma mark -
/* void init (in nsIURI aSource, in nsILocalFile aTarget, in wstring aDisplayName, in wstring openingWith, in long long startTime, in nsIWebBrowserPersist aPersist); */
NS_IMETHODIMP
nsDownloadListener::Init(nsIURI *aSource, nsILocalFile *aTarget, const PRUnichar *aDisplayName,
const PRUnichar *openingWith, PRInt64 startTime, nsIWebBrowserPersist *aPersist)
{
CreateDownloadDisplay(); // call the base class to make the download UI
if (aPersist) // only true for File->Save As.
{
mWebPersist = aPersist;
mWebPersist->SetProgressListener(this); // we form a cycle here, since we're a listener.
// we'll break this cycle in DownloadDone()
}
mDestination = aTarget;
mURI = aSource;
mStartTime = startTime;
InitDialog();
return NS_OK;
}
/* readonly attribute nsIURI source; */
NS_IMETHODIMP
nsDownloadListener::GetSource(nsIURI * *aSource)
{
NS_ENSURE_ARG_POINTER(aSource);
NS_IF_ADDREF(*aSource = mURI);
return NS_OK;
}
/* readonly attribute nsILocalFile target; */
NS_IMETHODIMP
nsDownloadListener::GetTarget(nsILocalFile * *aTarget)
{
NS_ENSURE_ARG_POINTER(aTarget);
NS_IF_ADDREF(*aTarget = mDestination);
return NS_OK;
}
/* readonly attribute nsIWebBrowserPersist persist; */
NS_IMETHODIMP
nsDownloadListener::GetPersist(nsIWebBrowserPersist * *aPersist)
{
NS_ENSURE_ARG_POINTER(aPersist);
NS_IF_ADDREF(*aPersist = mWebPersist);
return NS_OK;
}
/* readonly attribute PRInt32 percentComplete; */
NS_IMETHODIMP
nsDownloadListener::GetPercentComplete(PRInt32 *aPercentComplete)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
/* attribute wstring displayName; */
NS_IMETHODIMP
nsDownloadListener::GetDisplayName(PRUnichar * *aDisplayName)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsDownloadListener::SetDisplayName(const PRUnichar * aDisplayName)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
/* readonly attribute long long startTime; */
NS_IMETHODIMP
nsDownloadListener::GetStartTime(PRInt64 *aStartTime)
{
NS_ENSURE_ARG(aStartTime);
*aStartTime = mStartTime;
return NS_OK;
}
/* readonly attribute wstring openingWith; */
NS_IMETHODIMP
nsDownloadListener::GetOpeningWith(PRUnichar * *aOpeningWith)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
/* attribute nsIWebProgressListener listener; */
NS_IMETHODIMP
nsDownloadListener::GetListener(nsIWebProgressListener * *aListener)
{
NS_ENSURE_ARG_POINTER(aListener);
NS_IF_ADDREF(*aListener = (nsIWebProgressListener *)this);
return NS_OK;
}
NS_IMETHODIMP
nsDownloadListener::SetListener(nsIWebProgressListener * aListener)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
/* attribute nsIObserver observer; */
NS_IMETHODIMP
nsDownloadListener::GetObserver(nsIObserver * *aObserver)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsDownloadListener::SetObserver(nsIObserver * aObserver)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
#pragma mark -
/* void onProgressChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in long aCurSelfProgress, in long aMaxSelfProgress, in long aCurTotalProgress, in long aMaxTotalProgress); */
NS_IMETHODIMP
nsDownloadListener::OnProgressChange(nsIWebProgress *aWebProgress,
nsIRequest *aRequest,
PRInt32 aCurSelfProgress,
PRInt32 aMaxSelfProgress,
PRInt32 aCurTotalProgress,
PRInt32 aMaxTotalProgress)
{
if (mUserCanceled)
{
if (aRequest)
aRequest->Cancel(NS_BINDING_ABORTED);
mUserCanceled = false;
}
[mDownloadDisplay setProgressTo:aCurTotalProgress ofMax:aMaxTotalProgress];
return NS_OK;
}
/* void onLocationChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in nsIURI location); */
NS_IMETHODIMP
nsDownloadListener::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
nsDownloadListener::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
nsDownloadListener::OnSecurityChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, PRUint32 state)
{
return NS_OK;
}
// Implementation of nsIWebProgressListener
/* void onStateChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in unsigned long aStateFlags, in unsigned long aStatus); */
NS_IMETHODIMP
nsDownloadListener::OnStateChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, PRUint32 aStateFlags,
PRUint32 aStatus)
{
// NSLog(@"State changed: state %u, status %u", aStateFlags, aStatus);
if (!mGotFirstStateChange) {
mNetworkTransfer = ((aStateFlags & STATE_IS_NETWORK) != 0);
mGotFirstStateChange = PR_TRUE;
}
// when the entire download finishes, stop the progress timer and clean up
// the window and controller. We will get this even in the event of a cancel,
// so this is the only place in the listener where we should kill the download.
if ((aStateFlags & STATE_STOP) && (!mNetworkTransfer || (aStateFlags & STATE_IS_NETWORK))) {
DownloadDone();
}
return NS_OK;
}
#pragma mark -
void
nsDownloadListener::InitDialog()
{
// dialog has to be shown before the outlets get hooked up
[mDownloadDisplay onStartDownload];
if (mURI)
{
nsCAutoString spec;
mURI->GetSpec(spec);
[mDownloadDisplay setSourceURL: [NSString stringWithUTF8String:spec.get()]];
}
nsAutoString pathStr;
mDestination->GetPath(pathStr);
[mDownloadDisplay setDestinationPath: [NSString stringWithCharacters:pathStr.get() length:pathStr.Length()]];
}
void
nsDownloadListener::PauseDownload()
{
// write me
}
void
nsDownloadListener::ResumeDownload()
{
// write me
}
void
nsDownloadListener::CancelDownload()
{
mUserCanceled = PR_TRUE;
if (mWebPersist)
{
mWebPersist->CancelSave();
mUserCanceled = PR_FALSE;
}
// delete any files we've created...
}
void
nsDownloadListener::DownloadDone()
{
// break the reference cycle by removing ourselves as a listener
if (mWebPersist)
{
mWebPersist->SetProgressListener(nsnull);
mWebPersist = nsnull;
}
[mDownloadDisplay onEndDownload];
}
#pragma mark -

Просмотреть файл

@ -14,6 +14,7 @@
F512F52B02D1287F01072C9F,
F5A3669702CCFAF601DC3354,
F512F52C02D1287F01072C9F,
F50D9DE602ECC32301BB4219,
F512F52D02D1287F01072C9F,
);
isa = PBXGroup;
@ -471,6 +472,10 @@
F59236C202C89ACA0100012B,
F5A3669802CCFAF601DC3354,
F55C4DD402D2864E0130B065,
F50D9DE402ECC2C601BB4219,
F50D9DEF02EE0AB101BB4219,
F50D9DF302EE194001BB4219,
F50D9DF702EE2B9B01BB4219,
);
isa = PBXHeadersBuildPhase;
name = Headers;
@ -585,6 +590,10 @@
F53E012D02AEE93701A967F3,
F632AF8602B9AEBC01000103,
F59236C302C89ACA0100012B,
F50D9DE502ECC2C601BB4219,
F50D9DF002EE0AB101BB4219,
F50D9DF402EE194001BB4219,
F50D9DF802EE2B9B01BB4219,
);
isa = PBXSourcesBuildPhase;
name = Sources;
@ -840,6 +849,145 @@
name = Graphics;
refType = 4;
};
F50D9DE202ECC2C601BB4219 = {
isa = PBXFileReference;
path = nsDownloadListener.h;
refType = 4;
};
F50D9DE302ECC2C601BB4219 = {
isa = PBXFileReference;
path = nsDownloadListener.mm;
refType = 4;
};
F50D9DE402ECC2C601BB4219 = {
fileRef = F50D9DE202ECC2C601BB4219;
isa = PBXBuildFile;
settings = {
};
};
F50D9DE502ECC2C601BB4219 = {
fileRef = F50D9DE302ECC2C601BB4219;
isa = PBXBuildFile;
settings = {
};
};
F50D9DE602ECC32301BB4219 = {
children = (
F50D9DF902EE2C1D01BB4219,
F50D9DFA02EE2C1D01BB4219,
);
isa = PBXGroup;
name = Downloading;
path = "";
refType = 4;
};
F50D9DE702ECC36201BB4219 = {
fileRef = F50D9DE202ECC2C601BB4219;
isa = PBXBuildFile;
settings = {
};
};
F50D9DE802ECC36201BB4219 = {
fileRef = F632AF8302B9AEBB01000103;
isa = PBXBuildFile;
settings = {
};
};
F50D9DE902ECC36201BB4219 = {
fileRef = F50D9DE302ECC2C601BB4219;
isa = PBXBuildFile;
settings = {
};
};
F50D9DED02EE0AB101BB4219 = {
isa = PBXFileReference;
path = DownloadProgressDisplay.h;
refType = 4;
};
F50D9DEE02EE0AB101BB4219 = {
isa = PBXFileReference;
path = DownloadProgressDisplay.mm;
refType = 4;
};
F50D9DEF02EE0AB101BB4219 = {
fileRef = F50D9DED02EE0AB101BB4219;
isa = PBXBuildFile;
settings = {
};
};
F50D9DF002EE0AB101BB4219 = {
fileRef = F50D9DEE02EE0AB101BB4219;
isa = PBXBuildFile;
settings = {
};
};
F50D9DF102EE194001BB4219 = {
isa = PBXFileReference;
path = DownloadFactories.h;
refType = 4;
};
F50D9DF202EE194001BB4219 = {
isa = PBXFileReference;
path = DownloadFactories.mm;
refType = 4;
};
F50D9DF302EE194001BB4219 = {
fileRef = F50D9DF102EE194001BB4219;
isa = PBXBuildFile;
settings = {
};
};
F50D9DF402EE194001BB4219 = {
fileRef = F50D9DF202EE194001BB4219;
isa = PBXBuildFile;
settings = {
};
};
F50D9DF502EE2B9A01BB4219 = {
isa = PBXFileReference;
path = SaveHeaderSniffer.h;
refType = 4;
};
F50D9DF602EE2B9A01BB4219 = {
isa = PBXFileReference;
path = SaveHeaderSniffer.mm;
refType = 4;
};
F50D9DF702EE2B9B01BB4219 = {
fileRef = F50D9DF502EE2B9A01BB4219;
isa = PBXBuildFile;
settings = {
};
};
F50D9DF802EE2B9B01BB4219 = {
fileRef = F50D9DF602EE2B9A01BB4219;
isa = PBXBuildFile;
settings = {
};
};
F50D9DF902EE2C1D01BB4219 = {
children = (
F50D9DF102EE194001BB4219,
F50D9DF202EE194001BB4219,
F50D9DED02EE0AB101BB4219,
F50D9DEE02EE0AB101BB4219,
);
isa = PBXGroup;
name = Generic;
refType = 4;
};
F50D9DFA02EE2C1D01BB4219 = {
children = (
F50D9DF502EE2B9A01BB4219,
F50D9DF602EE2B9A01BB4219,
F517395B020CE3740189DA0C,
F50D9DE302ECC2C601BB4219,
);
isa = PBXGroup;
name = Chimera;
path = "";
refType = 4;
};
F50DCB4302C2856001A967F3 = {
isa = PBXFileReference;
name = libjsj.dylib;
@ -1143,7 +1291,6 @@
F512F52B02D1287F01072C9F = {
children = (
F5DE10E90209DC0601A967DF,
F517395B020CE3740189DA0C,
F528E21A020FD9620168DE43,
);
isa = PBXGroup;
@ -1176,7 +1323,6 @@
};
F512F53302D17A2601072C9F = {
children = (
F55C4DD302D2864D0130B065,
29B97316FDCFA39411CA2CEA,
F59236C002C89AC90100012B,
F5AE04BA0206A4FE01A967DF,
@ -1330,6 +1476,7 @@
F507BA480213AD5F01D93544,
F57074B5026BA85F01A80166,
F57074B9026BFD0101A80166,
2EEC3E61028138714B000102,
F57074BD026D80DF01A80166,
2E293A00027F33604B000102,
F5607CB5023944AD01A967DF,
@ -1344,6 +1491,8 @@
F53E013202AEEA2801A967F3,
F5A3669302CCFAF601DC3354,
F59236C102C89AC90100012B,
F50D9DE202ECC2C601BB4219,
F55C4DD302D2864D0130B065,
);
isa = PBXGroup;
name = Headers;
@ -4375,7 +4524,6 @@
F57074B6026BA85F01A80166,
F57074BA026BFD0101A80166,
F53E012C02AEE93601A967F3,
2EEC3E61028138714B000102,
2EEC3E62028138714B000102,
);
isa = PBXGroup;
@ -4959,6 +5107,8 @@
F53E013402AEEA2901A967F3,
F59236C402C89ACA0100012B,
F5A3669A02CCFB7A01DC3354,
F50D9DE702ECC36201BB4219,
F50D9DE802ECC36201BB4219,
);
isa = PBXHeadersBuildPhase;
name = Headers;
@ -5074,6 +5224,7 @@
F59236C502C89ACA0100012B,
F5A3669B02CCFB7A01DC3354,
F5A3669C02CCFB7A01DC3354,
F50D9DE902ECC36201BB4219,
);
isa = PBXSourcesBuildPhase;
name = Sources;

Просмотреть файл

@ -3,13 +3,13 @@
<plist version="0.9">
<dict>
<key>IBDocumentLocation</key>
<string>73 360 356 240 0 0 1152 848 </string>
<string>61 108 356 240 0 0 1152 746 </string>
<key>IBEditorPositions</key>
<dict>
<key>266</key>
<string>418 452 277 90 0 0 1152 746 </string>
<string>23 342 277 90 0 0 1152 746 </string>
<key>29</key>
<string>8 803 446 44 0 0 1152 848 </string>
<string>8 701 446 44 0 0 1152 746 </string>
</dict>
<key>IBFramework Version</key>
<string>248.0</string>

Двоичные данные
chimera/resources/localized/English.lproj/MainMenu.nib/objects.nib сгенерированный

Двоичный файл не отображается.

Просмотреть файл

@ -5,12 +5,12 @@
CLASS = ProgressDlgController;
LANGUAGE = ObjC;
OUTLETS = {
mElapsedTimeLabel = id;
mFromField = id;
mProgressBar = id;
mStatusLabel = id;
mTimeLeftLabel = id;
mToField = id;
mElapsedTimeLabel = NSTextField;
mFromField = NSTextField;
mProgressBar = NSProgressIndicator;
mStatusLabel = NSTextField;
mTimeLeftLabel = NSTextField;
mToField = NSTextField;
};
SUPERCLASS = NSWindowController;
}

Просмотреть файл

@ -3,7 +3,7 @@
<plist version="0.9">
<dict>
<key>IBDocumentLocation</key>
<string>152 212 356 240 0 0 1024 746 </string>
<string>94 26 404 250 0 0 1152 746 </string>
<key>IBFramework Version</key>
<string>248.0</string>
<key>IBOpenObjects</key>
@ -11,6 +11,6 @@
<integer>5</integer>
</array>
<key>IBSystem Version</key>
<string>5Q125</string>
<string>5S66</string>
</dict>
</plist>

Двоичные данные
chimera/resources/localized/English.lproj/ProgressDialog.nib/objects.nib сгенерированный

Двоичный файл не отображается.

Просмотреть файл

@ -36,6 +36,9 @@
* ***** END LICENSE BLOCK ***** */
#import <AppKit/AppKit.h>
#import "DownloadProgressDisplay.h"
#include "nscore.h"
class nsIWebBrowserPersist;
@ -43,42 +46,37 @@ class nsISupports;
class nsIInputStream;
class nsDownloadListener;
@interface ProgressDlgController : NSWindowController {
IBOutlet id mFromField;
IBOutlet id mToField;
IBOutlet id mStatusLabel;
IBOutlet id mTimeLeftLabel;
IBOutlet id mElapsedTimeLabel;
IBOutlet id mProgressBar;
@interface ChimeraDownloadControllerFactory : DownloadControllerFactory
@end
@interface ProgressDlgController : NSWindowController <DownloadProgressDisplay>
{
IBOutlet NSTextField *mElapsedTimeLabel;
IBOutlet NSTextField *mFromField;
IBOutlet NSTextField *mStatusLabel;
IBOutlet NSTextField *mTimeLeftLabel;
IBOutlet NSTextField *mToField;
IBOutlet NSProgressIndicator *mProgressBar;
NSToolbarItem *pauseResumeToggleToolbarItem;
NSToolbarItem *leaveOpenToggleToolbarItem;
BOOL mDownloadIsPaused;
BOOL mSaveFileDialogShouldStayOpen;
BOOL mDownloadIsComplete;
long int aCurrentProgress; // if progress bar is indeterminate, can still calc stats.
BOOL mDownloadIsPaused;
BOOL mSaveFileDialogShouldStayOpen;
BOOL mDownloadIsComplete;
long mCurrentProgress; // if progress bar is indeterminate, can still calc stats.
nsDownloadListener* mDownloadListener;
NSTimer *mDownloadTimer;
nsDownloader *mDownloader; // we hold a ref to this
NSTimer *mDownloadTimer;
}
-(void) setWebPersist: (nsIWebBrowserPersist*)aPersist
source: (nsISupports*)aSource
destination: (NSString*)aDestination
contentType: (const char*)aContentType
postData: (nsIInputStream*)aInputStream
bypassCache: (BOOL)aBypassCache;
-(void) setProgressBar:(long int)aCurProgress
maxProg:(long int)aMaxProgress;
-(void) setDownloadTimer;
-(void) setupDownloadTimer;
-(void) killDownloadTimer;
-(void) setDownloadProgress:(NSTimer *)aTimer;
-(NSString *) formatTime:(int)aSeconds;
-(NSString *) formatFuzzyTime:(int)aSeconds;
-(NSString *) formatBytes:(float)aBytes;
-(void) setSourceURL: (const PRUnichar*)aSource;
-(void) setDestination: (const PRUnichar*)aDestination;
@end

Просмотреть файл

@ -46,282 +46,58 @@
#include "nsILocalFile.h"
#include "nsIDOMHTMLDocument.h"
#include "nsIWebProgressListener.h"
#include "nsIDownload.h"
#include "nsIComponentManager.h"
#include "nsIPref.h"
class nsDownloadListener : public nsIWebProgressListener
{
public:
nsDownloadListener(ProgressDlgController* aController,
nsIWebBrowserPersist* aPersist,
nsISupports* aSource,
NSString* aDestination,
const char* aContentType,
nsIInputStream* aPostData,
BOOL aBypassCache)
{
NS_INIT_ISUPPORTS();
mController = aController;
mWebPersist = aPersist;
// The source is either a simple URL or a complete document.
mURL = do_QueryInterface(aSource);
if (!mURL)
mDocument = do_QueryInterface(aSource);
PRUint32 dstLen = [aDestination length];
PRUnichar* tmp = new PRUnichar[dstLen + sizeof(PRUnichar)];
tmp[dstLen] = (PRUnichar)'\0';
[aDestination getCharacters:tmp];
nsAutoString dstStr(tmp);
delete tmp;
NS_NewLocalFile(dstStr, PR_FALSE, getter_AddRefs(mDestination));
// XXX check for failure
mContentType = aContentType;
mPostData = aPostData;
mBypassCache = aBypassCache;
mNetworkTransfer = PR_FALSE;
mGotFirstStateChange = PR_FALSE;
};
virtual ~nsDownloadListener() {};
NS_DECL_ISUPPORTS
NS_DECL_NSIWEBPROGRESSLISTENER
public:
void BeginDownload();
void InitDialog();
void CancelDownload();
private: // Member variables
ProgressDlgController* mController; // Controller for our UI.
nsCOMPtr<nsIWebBrowserPersist> mWebPersist; // Our web persist object.
nsCOMPtr<nsIURL> mURL; // The URL of our source file. Null if we're saving a complete document.
nsCOMPtr<nsILocalFile> mDestination; // Our destination URL.
nsCString mContentType; // Our content type string.
nsCOMPtr<nsIDOMHTMLDocument> mDocument; // A DOM document. Null if we're only saving a simple URL.
nsCOMPtr<nsIInputStream> mPostData; // For complete documents, this is our post data from session history.
PRPackedBool mBypassCache; // Whether we should bypass the cache or not.
PRPackedBool mNetworkTransfer; // true if the first OnStateChange has the NETWORK bit set
PRPackedBool mGotFirstStateChange; // true after we've seen the first OnStateChange
};
NS_IMPL_ISUPPORTS1(nsDownloadListener, nsIWebProgressListener)
/* void onProgressChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in long aCurSelfProgress, in long aMaxSelfProgress, in long aCurTotalProgress, in long aMaxTotalProgress); */
NS_IMETHODIMP
nsDownloadListener::OnProgressChange(nsIWebProgress *aWebProgress,
nsIRequest *aRequest,
PRInt32 aCurSelfProgress,
PRInt32 aMaxSelfProgress,
PRInt32 aCurTotalProgress,
PRInt32 aMaxTotalProgress)
{
[mController setProgressBar:aCurTotalProgress maxProg:aMaxTotalProgress];
return NS_OK;
}
/* void onLocationChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in nsIURI location); */
NS_IMETHODIMP
nsDownloadListener::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
nsDownloadListener::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
nsDownloadListener::OnSecurityChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, PRUint32 state)
{
return NS_OK;
}
// Implementation of nsIWebProgressListener
/* void onStateChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in unsigned long aStateFlags, in unsigned long aStatus); */
NS_IMETHODIMP
nsDownloadListener::OnStateChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, PRUint32 aStateFlags,
PRUint32 aStatus)
{
// NSLog(@"State changed: state %u, status %u", aStateFlags, aStatus);
if (!mGotFirstStateChange) {
mNetworkTransfer = ((aStateFlags & STATE_IS_NETWORK) != 0);
mGotFirstStateChange = PR_TRUE;
}
// when the entire download finishes, stop the progress timer and clean up
// the window and controller. We will get this even in the event of a cancel,
// so this is the only place in the listener where we should kill the download.
if ((aStateFlags & STATE_STOP) && (!mNetworkTransfer || (aStateFlags & STATE_IS_NETWORK))) {
[mController killDownloadTimer];
[mController setDownloadProgress:nil];
}
return NS_OK;
}
void
nsDownloadListener::BeginDownload()
{
if (mWebPersist) {
mWebPersist->SetProgressListener(this);
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;
if (mURL)
mWebPersist->SaveURI(mURL, mPostData, mDestination);
else {
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;
mDestination->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)
filesFolder->Create(nsILocalFile::DIRECTORY_TYPE, 0755);
}
else
encodingFlags |= nsIWebBrowserPersist::ENCODE_FLAGS_FORMATTED |
nsIWebBrowserPersist::ENCODE_FLAGS_ABSOLUTE_LINKS |
nsIWebBrowserPersist::ENCODE_FLAGS_NOFRAMES_CONTENT;
mWebPersist->SaveDocument(mDocument, mDestination, filesFolder, mContentType.get(),
encodingFlags, 80);
}
}
InitDialog();
}
void
nsDownloadListener::InitDialog()
{
if (!mURL && !mDocument)
return;
if (mWebPersist) {
if (mURL) {
nsCAutoString spec;
mURL->GetSpec(spec);
nsAutoString spec2; spec2.AssignWithConversion(spec.get());
[mController setSourceURL: spec2.get()];
}
else {
nsAutoString spec;
mDocument->GetURL(spec);
[mController setSourceURL: spec.get()];
}
}
nsAutoString pathStr;
mDestination->GetPath(pathStr);
[mController setDestination: pathStr.get()];
[mController setDownloadTimer];
}
void
nsDownloadListener::CancelDownload()
{
if (mWebPersist)
mWebPersist->CancelSave();
}
static NSString *SaveFileToolbarIdentifier = @"Save File Dialog Toolbar";
static NSString *CancelToolbarItemIdentifier = @"Cancel Toolbar Item";
static NSString *SaveFileToolbarIdentifier = @"Save File Dialog Toolbar";
static NSString *CancelToolbarItemIdentifier = @"Cancel Toolbar Item";
static NSString *PauseResumeToolbarItemIdentifier = @"Pause and Resume Toggle Toolbar Item";
static NSString *ShowFileToolbarItemIdentifier = @"Show File Toolbar Item";
static NSString *OpenFileToolbarItemIdentifier = @"Open File Toolbar Item";
static NSString *LeaveOpenToolbarItemIdentifier = @"Leave Open Toggle Toolbar Item";
@implementation ChimeraDownloadControllerFactory : DownloadControllerFactory
- (NSWindowController<DownloadProgressDisplay> *)createDownloadController
{
NSWindowController* progressController = [[ProgressDlgController alloc] initWithWindowNibName: @"ProgressDialog"];
NSAssert([progressController conformsToProtocol:@protocol(DownloadProgressDisplay)],
@"progressController should conform to DownloadProgressDisplay protocol");
return progressController;
}
@end
#pragma mark -
@interface ProgressDlgController(Private)
-(void)setupToolbar;
@end
@implementation ProgressDlgController
-(void)setWebPersist:(nsIWebBrowserPersist*)aPersist
source:(nsISupports*)aSource
destination:(NSString*)aDestination
contentType:(const char*)aContentType
postData:(nsIInputStream*)aInputStream
bypassCache:(BOOL)aBypassCache
- (void)dealloc
{
mDownloadListener = new nsDownloadListener(self, aPersist, aSource,
aDestination, aContentType,
aInputStream, aBypassCache);
NS_ADDREF(mDownloadListener);
}
-(void) setProgressBar:(long int)curProgress maxProg:(long int)maxProgress
{
aCurrentProgress = curProgress; // fall back for stat calcs
if (![mProgressBar isIndeterminate]) { //most likely - just update value
if (curProgress == maxProgress) //handles little bug in FTP download size
[mProgressBar setMaxValue:maxProgress];
[mProgressBar setDoubleValue:curProgress];
}
else if (maxProgress > 0) { // ok, we're starting up with good max & cur values
[mProgressBar setIndeterminate:NO];
[mProgressBar setMaxValue:maxProgress];
[mProgressBar setDoubleValue:curProgress];
} // if neither case was true, it's barber pole city.
}
-(void) setSourceURL: (const PRUnichar*)aSource
{
[mFromField setStringValue: [NSString stringWithCharacters:aSource length:nsCRT::strlen(aSource)]];
}
-(void) setDestination: (const PRUnichar*)aDestination
{
[mToField setStringValue: [[NSString stringWithCharacters:aDestination length:nsCRT::strlen(aDestination)] stringByAbbreviatingWithTildeInPath]];
NS_IF_RELEASE(mDownloader);
[super dealloc];
}
- (void)windowDidLoad
{
mDownloadIsPaused = NO;
mDownloadIsComplete = NO;
nsCOMPtr<nsIPref> prefs(do_GetService(NS_PREF_CONTRACTID));
PRBool save = PR_FALSE;
prefs->GetBoolPref("browser.download.progressDnldDialog.keepAlive",&save);
prefs->GetBoolPref("browser.download.progressDnldDialog.keepAlive", &save);
mSaveFileDialogShouldStayOpen = save;
[self setupToolbar];
[mProgressBar setUsesThreadedAnimation:YES];
[mProgressBar startAnimation:self];
if (mDownloadListener)
mDownloadListener->BeginDownload();
[mProgressBar startAnimation:self]; // move to onStateChange
}
- (void)setupToolbar
@ -438,7 +214,9 @@ static NSString *LeaveOpenToolbarItemIdentifier = @"Leave Open Toggle Toolbar
-(void)cancel
{
mDownloadListener->CancelDownload();
if (mDownloader) // we should always have one
mDownloader->CancelDownload();
// clean up downloaded file. - do it here on in CancelDownload?
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *thePath = [[mToField stringValue] stringByExpandingTildeInPath];
@ -457,22 +235,29 @@ static NSString *LeaveOpenToolbarItemIdentifier = @"Leave Open Toggle Toolbar
-(void)pauseAndResumeDownload
{
if ( ! mDownloadIsPaused ) {
//Do logic to pause download
if ( !mDownloadIsPaused )
{
mDownloadIsPaused = YES;
[pauseResumeToggleToolbarItem setLabel:@"Resume"];
[pauseResumeToggleToolbarItem setPaletteLabel:@"Resume Download"];
[pauseResumeToggleToolbarItem setToolTip:@"Resume the paused FTP download"];
[pauseResumeToggleToolbarItem setImage:[NSImage imageNamed:@"saveResume"]];
[self killDownloadTimer];
} else {
//Do logic to resume download
if (mDownloader) // we should always have one
mDownloader->PauseDownload();
}
else
{
mDownloadIsPaused = NO;
[pauseResumeToggleToolbarItem setLabel:@"Pause"];
[pauseResumeToggleToolbarItem setPaletteLabel:@"Pause Download"];
[pauseResumeToggleToolbarItem setToolTip:@"Pause this FTP file download"];
[pauseResumeToggleToolbarItem setImage:[NSImage imageNamed:@"savePause"]];
[self setDownloadTimer];
[self setupDownloadTimer];
if (mDownloader) // we should always have one
mDownloader->ResumeDownload();
}
}
@ -531,12 +316,6 @@ static NSString *LeaveOpenToolbarItemIdentifier = @"Leave Open Toggle Toolbar
return YES;
}
- (void)dealloc
{
NS_IF_RELEASE(mDownloadListener);
[super dealloc];
}
- (void)killDownloadTimer
{
if (mDownloadTimer) {
@ -545,7 +324,7 @@ static NSString *LeaveOpenToolbarItemIdentifier = @"Leave Open Toggle Toolbar
mDownloadTimer = nil;
}
}
- (void)setDownloadTimer
- (void)setupDownloadTimer
{
[self killDownloadTimer];
mDownloadTimer = [[NSTimer scheduledTimerWithTimeInterval:1.0
@ -590,7 +369,7 @@ static NSString *LeaveOpenToolbarItemIdentifier = @"Leave Open Toggle Toolbar
return [[[NSString alloc] initWithString:[[NSBundle mainBundle] localizedStringForKey:@"UnderMin" value:@"Under a minute" table:@"ProgressDialog"]] autorelease];
}
// seconds becomes minutes and we keep checking.
seconds=seconds/60;
seconds = seconds/60;
if (seconds < 60) {
if (seconds < 2)
return [[[NSString alloc] initWithString:[[NSBundle mainBundle] localizedStringForKey:@"AboutMin" value:@"About a minute" table:@"ProgressDialog"]] autorelease];
@ -598,7 +377,7 @@ static NSString *LeaveOpenToolbarItemIdentifier = @"Leave Open Toggle Toolbar
return [[[NSString alloc] initWithFormat:[[NSBundle mainBundle] localizedStringForKey:@"AboutMins" value:@"About %d minutes" table:@"ProgressDialog"],seconds] autorelease];
}
//this download will never seemingly never end. now seconds become hours.
seconds=seconds/60;
seconds = seconds/60;
if (seconds < 2)
return [[[NSString alloc] initWithString:[[NSBundle mainBundle] localizedStringForKey:@"AboutHour" value:@"Over an hour" table:@"ProgressDialog"]] autorelease];
return [[[NSString alloc] initWithFormat:[[NSBundle mainBundle] localizedStringForKey:@"AboutHours" value:@"Over %d hours" table:@"ProgressDialog"],seconds] autorelease];
@ -629,8 +408,11 @@ static NSString *LeaveOpenToolbarItemIdentifier = @"Leave Open Toggle Toolbar
// this handles lots of things.
- (void)setDownloadProgress:(NSTimer *)downloadTimer;
{
// XXX this logic needs cleaning up.
// Ack! we're closing the window with the download still running!
if (mDownloadIsComplete) {
if (mDownloadIsComplete)
{
[[self window] performClose:self];
return;
}
@ -644,26 +426,28 @@ static NSString *LeaveOpenToolbarItemIdentifier = @"Leave Open Toggle Toolbar
[mElapsedTimeLabel setStringValue:[self formatTime:(++elapsedSec)]];
// for status field & time left
float maxBytes = ([mProgressBar maxValue]);
float byteSec = aCurrentProgress/elapsedSec;
float byteSec = mCurrentProgress/elapsedSec;
// OK - if downloadTimer is nil, we're done - fix maxBytes value for status report.
if (!downloadTimer)
maxBytes = aCurrentProgress;
maxBytes = mCurrentProgress;
// update status field
NSString *labelString = [[NSBundle mainBundle] localizedStringForKey:@"LabelString"
value:@"%@ of %@ total (at %@/sec)"
table:@"ProgressDialog"];
[mStatusLabel setStringValue: [NSString stringWithFormat:labelString, [self formatBytes:aCurrentProgress], [self formatBytes:maxBytes], [self formatBytes:byteSec]]];
[mStatusLabel setStringValue: [NSString stringWithFormat:labelString, [self formatBytes:mCurrentProgress], [self formatBytes:maxBytes], [self formatBytes:byteSec]]];
// updating estimated time left field
// if maxBytes < 0, can't calc time left.
// if !downloadTimer, download is finished. either way, make sure time left is 0.
if ((maxBytes > 0) && (downloadTimer)) {
int secToGo = (int)ceil((elapsedSec*maxBytes/aCurrentProgress)-elapsedSec);
if ((maxBytes > 0) && (downloadTimer))
{
int secToGo = (int)ceil((elapsedSec*maxBytes/mCurrentProgress) - elapsedSec);
[mTimeLeftLabel setStringValue:[self formatFuzzyTime:secToGo]];
}
else if (!downloadTimer) { // download done. Set remaining time to 0, fix progress bar & cancel button
else if (!downloadTimer)
{ // download done. Set remaining time to 0, fix progress bar & cancel button
mDownloadIsComplete = YES; // all done. we got a STATE_STOP
[mTimeLeftLabel setStringValue:@""];
[self setProgressBar:aCurrentProgress maxProg:aCurrentProgress];
[self setProgressTo:mCurrentProgress ofMax:mCurrentProgress];
if (!mSaveFileDialogShouldStayOpen)
[[self window] performClose:self]; // close window
else
@ -673,4 +457,59 @@ static NSString *LeaveOpenToolbarItemIdentifier = @"Leave Open Toggle Toolbar
[mTimeLeftLabel setStringValue:@"???"];
}
#pragma mark -
// DownloadProgressDisplay protocol methods
- (void)onStartDownload
{
[self showWindow: self];
[self setupDownloadTimer];
}
- (void)onEndDownload
{
[self killDownloadTimer];
[self setDownloadProgress:nil];
}
- (void)setProgressTo:(long)aCurProgress ofMax:(long)aMaxProgress
{
mCurrentProgress = aCurProgress; // fall back for stat calcs
if (![mProgressBar isIndeterminate]) //most likely - just update value
{
if (aCurProgress == aMaxProgress) //handles little bug in FTP download size
[mProgressBar setMaxValue:aMaxProgress];
[mProgressBar setDoubleValue:aCurProgress];
}
else if (aMaxProgress > 0) // ok, we're starting up with good max & cur values
{
[mProgressBar setIndeterminate:NO];
[mProgressBar setMaxValue:aMaxProgress];
[mProgressBar setDoubleValue:aCurProgress];
} // if neither case was true, it's barber pole city.
}
-(void) setDownloadListener: (nsDownloader*)aDownloader
{
if (mDownloader != aDownloader)
NS_IF_RELEASE(mDownloader);
NS_IF_ADDREF(mDownloader = aDownloader);
}
- (void)setSourceURL:(NSString*)aSourceURL
{
[mFromField setStringValue: aSourceURL];
[mFromField display]; // force an immmeditate update
}
- (void)setDestinationPath:(NSString*)aDestPath
{
[mToField setStringValue: [aDestPath stringByAbbreviatingWithTildeInPath]];
[mToField display]; // force an immmeditate update
}
@end

Просмотреть файл

@ -0,0 +1,84 @@
/* ***** 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 ***** */
#import <Foundation/Foundation.h>
#import <Appkit/Appkit.h>
#include "nsString.h"
#include "nsIWebProgressListener.h"
#include "nsIWebBrowserPersist.h"
#include "nsIURI.h"
#include "nsILocalFile.h"
#include "nsIInputStream.h"
#include "nsIDOMDocument.h"
// Implementation of a header sniffer class that is used when saving Web pages and images.
class nsHeaderSniffer : public nsIWebProgressListener
{
public:
nsHeaderSniffer(nsIWebBrowserPersist* aPersist, nsIFile* aFile, nsIURI* aURL,
nsIDOMDocument* aDocument, nsIInputStream* aPostData,
const nsCString& aSuggestedFilename, PRBool aBypassCache,
NSView* aFilterView, NSPopUpButton* aFilterList);
virtual ~nsHeaderSniffer();
NS_DECL_ISUPPORTS
NS_DECL_NSIWEBPROGRESSLISTENER
protected:
nsresult PerformSave(nsIURI* inOriginalURI);
nsresult InitiateDownload(nsISupports* inSourceData, nsString& inFileName, nsIURI* inOriginalURI);
private:
nsIWebBrowserPersist* mPersist; // Weak. It owns us as a listener.
nsCOMPtr<nsIFile> mTmpFile;
nsCOMPtr<nsIURI> mURL;
nsCOMPtr<nsIDOMDocument> mDocument;
nsCOMPtr<nsIInputStream> mPostData;
nsCString mDefaultFilename;
PRBool mBypassCache;
nsCString mContentType;
nsCString mContentDisposition;
NSView* mFilterView;
NSPopUpButton* mFilterList;
};

Просмотреть файл

@ -0,0 +1,386 @@
/* ***** 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 "SaveHeaderSniffer.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"
const char* const persistContractID = "@mozilla.org/embedding/browser/nsWebBrowserPersist;1";
nsHeaderSniffer::nsHeaderSniffer(nsIWebBrowserPersist* aPersist, nsIFile* aFile, nsIURI* aURL,
nsIDOMDocument* aDocument, nsIInputStream* aPostData,
const nsCString& aSuggestedFilename, PRBool aBypassCache,
NSView* aFilterView, NSPopUpButton* aFilterList)
: mPersist(aPersist)
, mTmpFile(aFile)
, mURL(aURL)
, mDocument(aDocument)
, mPostData(aPostData)
, mDefaultFilename(aSuggestedFilename)
, mBypassCache(aBypassCache)
, mFilterView(aFilterView)
, mFilterList(aFilterList)
{
NS_INIT_ISUPPORTS();
}
nsHeaderSniffer::~nsHeaderSniffer()
{
}
NS_IMPL_ISUPPORTS1(nsHeaderSniffer, nsIWebProgressListener)
#pragma mark -
// Implementation of nsIWebProgressListener
/* void onStateChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in long aStateFlags, in unsigned long aStatus); */
NS_IMETHODIMP
nsHeaderSniffer::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 ourslves 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);
if (NS_FAILED(rv))
{
// put up some UI
NSLog(@"Error saving web page");
}
}
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
nsHeaderSniffer::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
nsHeaderSniffer::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
nsHeaderSniffer::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
nsHeaderSniffer::OnSecurityChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, PRUint32 state)
{
return NS_OK;
}
#pragma mark -
nsresult nsHeaderSniffer::PerformSave(nsIURI* inOriginalURI)
{
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 (dirBranch) {
nsresult rv = dirBranch->GetIntPref("save_converter_index", &filterIndex);
if (NS_FAILED(rv))
filterIndex = 0;
}
if (mFilterList)
[mFilterList selectItemAtIndex: filterIndex];
// We need to figure out what file name to use.
nsCAutoString 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 = filename;
}
}
if (defaultFileName.IsEmpty()) {
nsCOMPtr<nsIURL> url(do_QueryInterface(mURL));
if (url)
url->GetFileName(defaultFileName); // (2) For file URLs, use the file name.
}
if (defaultFileName.IsEmpty() && mDocument && isHTML) {
nsCOMPtr<nsIDOMHTMLDocument> htmlDoc(do_QueryInterface(mDocument));
nsAutoString title;
if (htmlDoc)
htmlDoc->GetTitle(title); // (3) Use the title of the document.
defaultFileName.AssignWithConversion(title);
}
if (defaultFileName.IsEmpty()) {
// (4) Use the caller provided name.
defaultFileName = mDefaultFilename;
}
if (defaultFileName.IsEmpty() && mURL)
// (5) Use the host.
mURL->GetHost(defaultFileName);
// One last case to handle about:blank and other fruity untitled pages.
if (defaultFileName.IsEmpty())
defaultFileName = "untitled";
// Validate the file name to ensure legality.
for (PRUint32 i = 0; i < defaultFileName.Length(); i++)
if (defaultFileName[i] == ':' || defaultFileName[i] == '/')
defaultFileName.SetCharAt(i, ' ');
// 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(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 += ".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 += ".";
defaultFileName += extList[0];
}
}
// Now it's time to pose the save dialog.
NSSavePanel* savePanel = [NSSavePanel savePanel];
NSString* file = nil;
if (!defaultFileName.IsEmpty())
file = [[NSString alloc] initWithCString: defaultFileName.get()];
if (isHTML)
[savePanel setAccessoryView: mFilterView];
if ([savePanel runModalForDirectory: nil file: file] == NSFileHandlingPanelCancelButton)
return NS_OK;
// Release the file string.
[file release];
// Update the filter index.
if (isHTML && mFilterList) {
filterIndex = [mFilterList indexOfSelectedItem];
dirBranch->SetIntPref("save_converter_index", filterIndex);
}
// Convert the content type to text/plain if it was selected in the filter.
if (isHTML && filterIndex == 2)
mContentType = "text/plain";
nsCOMPtr<nsISupports> sourceData;
if (isHTML && filterIndex != 1)
sourceData = do_QueryInterface(mDocument);
else
sourceData = do_QueryInterface(mURL);
NSString* destName = [savePanel filename];
PRUint32 dstLen = [destName length];
PRUnichar* tmp = new PRUnichar[dstLen + sizeof(PRUnichar)];
tmp[dstLen] = (PRUnichar)'\0';
[destName getCharacters:tmp];
nsAutoString dstString(tmp);
delete tmp;
return InitiateDownload(sourceData, dstString, 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 nsHeaderSniffer::InitiateDownload(nsISupports* inSourceData, nsString& inFileName, 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);
nsCOMPtr<nsILocalFile> destFile;
rv = NS_NewLocalFile(inFileName, PR_FALSE, getter_AddRefs(destFile));
if (NS_FAILED(rv)) return rv;
PRInt64 timeNow = PR_Now();
nsCOMPtr<nsIDownload> downloader = do_CreateInstance(NS_DOWNLOAD_CONTRACTID);
// dlListener attaches to its progress dialog here, which gains ownership
rv = downloader->Init(inOriginalURI, destFile, inFileName.get(), nsString().get(), 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;
if (sourceURI)
{
rv = webPersist->SaveURI(sourceURI, mPostData, destFile);
}
else
{
nsCOMPtr<nsIDOMHTMLDocument> 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;
destFile->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, destFile, filesFolder, mContentType.get(), encodingFlags, 80);
}
return rv;
}

Просмотреть файл

@ -0,0 +1,88 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Netscape 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/NPL/
*
* 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):
* 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 NPL, 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 NPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#import <Foundation/Foundation.h>
#import <Appkit/Appkit.h>
#import "DownloadProgressDisplay.h"
#include "nsString.h"
#include "nsIDownload.h"
#include "nsIWebProgressListener.h"
#include "nsIWebBrowserPersist.h"
#include "nsIURI.h"
#include "nsILocalFile.h"
// maybe this should replace nsHeaderSniffer too?
class nsDownloadListener : public nsDownloader,
public nsIDownload,
public nsIWebProgressListener
{
public:
nsDownloadListener(DownloadControllerFactory* inDownloadControllerFactory);
virtual ~nsDownloadListener();
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSIDOWNLOAD
NS_DECL_NSIWEBPROGRESSLISTENER
public:
//void BeginDownload();
void InitDialog();
virtual void PauseDownload();
virtual void ResumeDownload();
virtual void CancelDownload();
virtual void DownloadDone();
private:
nsCOMPtr<nsIWebBrowserPersist> mWebPersist; // Our web persist object.
nsCOMPtr<nsIURI> mURI; // The URI of our source file. Null if we're saving a complete document.
nsCOMPtr<nsILocalFile> mDestination; // Our destination URL.
PRInt64 mStartTime; // When the download started
PRPackedBool mBypassCache; // Whether we should bypass the cache or not.
PRPackedBool mNetworkTransfer; // true if the first OnStateChange has the NETWORK bit set
PRPackedBool mGotFirstStateChange; // true after we've seen the first OnStateChange
PRPackedBool mUserCanceled; // true if the user canceled the download
};

Просмотреть файл

@ -0,0 +1,308 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Netscape 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/NPL/
*
* 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):
* 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 NPL, 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 NPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsDownloadListener.h"
#include "nsIWebProgress.h"
#include "nsIRequest.h"
#include "nsIURL.h"
#include "netCore.h"
nsDownloadListener::nsDownloadListener(DownloadControllerFactory* inControllerFactory)
: nsDownloader(inControllerFactory)
, mBypassCache(PR_FALSE)
, mNetworkTransfer(PR_FALSE)
, mGotFirstStateChange(PR_FALSE)
, mUserCanceled(PR_FALSE)
{
}
nsDownloadListener::~nsDownloadListener()
{
}
NS_IMPL_ISUPPORTS_INHERITED2(nsDownloadListener, nsDownloader, nsIDownload, nsIWebProgressListener)
#pragma mark -
/* void init (in nsIURI aSource, in nsILocalFile aTarget, in wstring aDisplayName, in wstring openingWith, in long long startTime, in nsIWebBrowserPersist aPersist); */
NS_IMETHODIMP
nsDownloadListener::Init(nsIURI *aSource, nsILocalFile *aTarget, const PRUnichar *aDisplayName,
const PRUnichar *openingWith, PRInt64 startTime, nsIWebBrowserPersist *aPersist)
{
CreateDownloadDisplay(); // call the base class to make the download UI
if (aPersist) // only true for File->Save As.
{
mWebPersist = aPersist;
mWebPersist->SetProgressListener(this); // we form a cycle here, since we're a listener.
// we'll break this cycle in DownloadDone()
}
mDestination = aTarget;
mURI = aSource;
mStartTime = startTime;
InitDialog();
return NS_OK;
}
/* readonly attribute nsIURI source; */
NS_IMETHODIMP
nsDownloadListener::GetSource(nsIURI * *aSource)
{
NS_ENSURE_ARG_POINTER(aSource);
NS_IF_ADDREF(*aSource = mURI);
return NS_OK;
}
/* readonly attribute nsILocalFile target; */
NS_IMETHODIMP
nsDownloadListener::GetTarget(nsILocalFile * *aTarget)
{
NS_ENSURE_ARG_POINTER(aTarget);
NS_IF_ADDREF(*aTarget = mDestination);
return NS_OK;
}
/* readonly attribute nsIWebBrowserPersist persist; */
NS_IMETHODIMP
nsDownloadListener::GetPersist(nsIWebBrowserPersist * *aPersist)
{
NS_ENSURE_ARG_POINTER(aPersist);
NS_IF_ADDREF(*aPersist = mWebPersist);
return NS_OK;
}
/* readonly attribute PRInt32 percentComplete; */
NS_IMETHODIMP
nsDownloadListener::GetPercentComplete(PRInt32 *aPercentComplete)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
/* attribute wstring displayName; */
NS_IMETHODIMP
nsDownloadListener::GetDisplayName(PRUnichar * *aDisplayName)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsDownloadListener::SetDisplayName(const PRUnichar * aDisplayName)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
/* readonly attribute long long startTime; */
NS_IMETHODIMP
nsDownloadListener::GetStartTime(PRInt64 *aStartTime)
{
NS_ENSURE_ARG(aStartTime);
*aStartTime = mStartTime;
return NS_OK;
}
/* readonly attribute wstring openingWith; */
NS_IMETHODIMP
nsDownloadListener::GetOpeningWith(PRUnichar * *aOpeningWith)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
/* attribute nsIWebProgressListener listener; */
NS_IMETHODIMP
nsDownloadListener::GetListener(nsIWebProgressListener * *aListener)
{
NS_ENSURE_ARG_POINTER(aListener);
NS_IF_ADDREF(*aListener = (nsIWebProgressListener *)this);
return NS_OK;
}
NS_IMETHODIMP
nsDownloadListener::SetListener(nsIWebProgressListener * aListener)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
/* attribute nsIObserver observer; */
NS_IMETHODIMP
nsDownloadListener::GetObserver(nsIObserver * *aObserver)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsDownloadListener::SetObserver(nsIObserver * aObserver)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
#pragma mark -
/* void onProgressChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in long aCurSelfProgress, in long aMaxSelfProgress, in long aCurTotalProgress, in long aMaxTotalProgress); */
NS_IMETHODIMP
nsDownloadListener::OnProgressChange(nsIWebProgress *aWebProgress,
nsIRequest *aRequest,
PRInt32 aCurSelfProgress,
PRInt32 aMaxSelfProgress,
PRInt32 aCurTotalProgress,
PRInt32 aMaxTotalProgress)
{
if (mUserCanceled)
{
if (aRequest)
aRequest->Cancel(NS_BINDING_ABORTED);
mUserCanceled = false;
}
[mDownloadDisplay setProgressTo:aCurTotalProgress ofMax:aMaxTotalProgress];
return NS_OK;
}
/* void onLocationChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in nsIURI location); */
NS_IMETHODIMP
nsDownloadListener::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
nsDownloadListener::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
nsDownloadListener::OnSecurityChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, PRUint32 state)
{
return NS_OK;
}
// Implementation of nsIWebProgressListener
/* void onStateChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in unsigned long aStateFlags, in unsigned long aStatus); */
NS_IMETHODIMP
nsDownloadListener::OnStateChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, PRUint32 aStateFlags,
PRUint32 aStatus)
{
// NSLog(@"State changed: state %u, status %u", aStateFlags, aStatus);
if (!mGotFirstStateChange) {
mNetworkTransfer = ((aStateFlags & STATE_IS_NETWORK) != 0);
mGotFirstStateChange = PR_TRUE;
}
// when the entire download finishes, stop the progress timer and clean up
// the window and controller. We will get this even in the event of a cancel,
// so this is the only place in the listener where we should kill the download.
if ((aStateFlags & STATE_STOP) && (!mNetworkTransfer || (aStateFlags & STATE_IS_NETWORK))) {
DownloadDone();
}
return NS_OK;
}
#pragma mark -
void
nsDownloadListener::InitDialog()
{
// dialog has to be shown before the outlets get hooked up
[mDownloadDisplay onStartDownload];
if (mURI)
{
nsCAutoString spec;
mURI->GetSpec(spec);
[mDownloadDisplay setSourceURL: [NSString stringWithUTF8String:spec.get()]];
}
nsAutoString pathStr;
mDestination->GetPath(pathStr);
[mDownloadDisplay setDestinationPath: [NSString stringWithCharacters:pathStr.get() length:pathStr.Length()]];
}
void
nsDownloadListener::PauseDownload()
{
// write me
}
void
nsDownloadListener::ResumeDownload()
{
// write me
}
void
nsDownloadListener::CancelDownload()
{
mUserCanceled = PR_TRUE;
if (mWebPersist)
{
mWebPersist->CancelSave();
mUserCanceled = PR_FALSE;
}
// delete any files we've created...
}
void
nsDownloadListener::DownloadDone()
{
// break the reference cycle by removing ourselves as a listener
if (mWebPersist)
{
mWebPersist->SetProgressListener(nsnull);
mWebPersist = nsnull;
}
[mDownloadDisplay onEndDownload];
}
#pragma mark -

Просмотреть файл

@ -55,7 +55,7 @@ class nsCocoaBrowserService : public nsIWindowCreator,
public nsIPromptService,
public nsIFactory,
public nsIBadCertListener, public nsISecurityWarningDialogs, public nsINSSDialogs,
public nsIHelperAppLauncherDialog, public nsIDownload, public nsIWebProgressListener
public nsIHelperAppLauncherDialog
{
public:
nsCocoaBrowserService();
@ -69,8 +69,6 @@ public:
NS_DECL_NSIBADCERTLISTENER
NS_DECL_NSISECURITYWARNINGDIALOGS
NS_DECL_NSIHELPERAPPLAUNCHERDIALOG
NS_DECL_NSIDOWNLOAD
NS_DECL_NSIWEBPROGRESSLISTENER
static nsresult InitEmbedding();
static void TermEmbedding();

Просмотреть файл

@ -35,14 +35,15 @@
*
* ***** END LICENSE BLOCK ***** */
#include "nsCocoaBrowserService.h"
#import "nsCocoaBrowserService.h"
#import "DownloadFactories.h"
#import "CHBrowserView.h"
#include "nsIWindowWatcher.h"
#include "nsIWebBrowserChrome.h"
#include "nsIEmbeddingSiteWindow.h"
#include "nsIProfile.h"
#include "nsIPrefService.h"
#include "CHBrowserView.h"
#include "nsCRT.h"
#include "nsString.h"
#include "nsIPrompt.h"
@ -74,13 +75,14 @@ nsCocoaBrowserService::~nsCocoaBrowserService()
{
}
NS_IMPL_ISUPPORTS9(nsCocoaBrowserService,
NS_IMPL_ISUPPORTS7(nsCocoaBrowserService,
nsIWindowCreator,
nsIPromptService,
nsIFactory,
nsIBadCertListener, nsISecurityWarningDialogs, nsINSSDialogs,
nsIHelperAppLauncherDialog, nsIDownload, nsIWebProgressListener)
nsIHelperAppLauncherDialog)
/* static */
nsresult
nsCocoaBrowserService::InitEmbedding()
{
@ -103,7 +105,7 @@ nsCocoaBrowserService::InitEmbedding()
#define NS_PROMPTSERVICE_CID \
{0xa2112d6a, 0x0e28, 0x421f, {0xb4, 0x6a, 0x25, 0xc0, 0xb3, 0x8, 0xcb, 0xd0}}
static NS_DEFINE_CID(kPromptServiceCID, NS_PROMPTSERVICE_CID);
nsresult rv = cr->RegisterFactory(kPromptServiceCID, "Prompt Service", "@mozilla.org/embedcomp/prompt-service;1",
nsresult rv = cr->RegisterFactory(kPromptServiceCID, "Prompt Service", "@mozilla.org/embedcomp/prompt-service;1",
sSingleton);
if (NS_FAILED(rv))
return rv;
@ -127,14 +129,18 @@ nsCocoaBrowserService::InitEmbedding()
rv = cr->RegisterFactory(kHelperDlgCID, NS_IHELPERAPPLAUNCHERDLG_CLASSNAME, NS_IHELPERAPPLAUNCHERDLG_CONTRACTID,
sSingleton);
// replace the downloader with our own which does rely on the xpfe downlaod manager
// replace the downloader with our own which does not rely on the xpfe downlaod manager
nsCOMPtr<nsIFactory> downloadFactory;
rv = NewDownloadListenerFactory(getter_AddRefs(downloadFactory));
if (NS_FAILED(rv)) return rv;
static NS_DEFINE_CID(kDownloadCID, NS_DOWNLOAD_CID);
rv = cr->RegisterFactory(kDownloadCID, "Download", NS_DOWNLOAD_CONTRACTID,
sSingleton);
rv = cr->RegisterFactory(kDownloadCID, "Download", NS_DOWNLOAD_CONTRACTID, downloadFactory);
return rv;
}
/* static */
void
nsCocoaBrowserService::BrowserClosed()
{
@ -149,6 +155,7 @@ nsCocoaBrowserService::BrowserClosed()
}
}
/* static */
void
nsCocoaBrowserService::TermEmbedding()
{
@ -195,8 +202,15 @@ nsCocoaBrowserService::CreateInstance(nsISupports *aOuter,
const nsIID & aIID,
void **aResult)
{
NS_ENSURE_ARG_POINTER(aResult);
/*
if (aIID.Equals(NS_GET_IID(nsIHelperAppLauncherDialog)))
{
}
*/
return sSingleton->QueryInterface(aIID, aResult);
}
@ -828,14 +842,12 @@ nsCocoaBrowserService::ConfirmPostToInsecureFromSecure(nsIInterfaceRequestor *ct
NS_IMETHODIMP
nsCocoaBrowserService::Show(nsIHelperAppLauncher* inLauncher, nsISupports* inContext)
{
NSLog(@"Show");
return inLauncher->SaveToDisk(nsnull, PR_FALSE);
}
NS_IMETHODIMP
nsCocoaBrowserService::PromptForSaveToFile(nsISupports *aWindowContext, const PRUnichar *aDefaultFile, const PRUnichar *aSuggestedFileExtension, nsILocalFile **_retval)
{
NSLog(@"PromptForSaveToFile");
NSString* filename = [NSString stringWithCharacters:aDefaultFile length:nsCRT::strlen(aDefaultFile)];
NSSavePanel *thePanel = [NSSavePanel savePanel];
@ -844,7 +856,7 @@ NSLog(@"PromptForSaveToFile");
// use nil for the path given to runModalForDirectory
int runResult = [thePanel runModalForDirectory: nil file:filename];
if (runResult == NSOKButton) {
NSLog([thePanel filename]);
// NSLog(@"Saving to %@", [thePanel filename]);
NSString *theName = [thePanel filename];
return NS_NewNativeLocalFile(nsDependentCString([theName fileSystemRepresentation]), PR_FALSE, _retval);
}
@ -856,140 +868,6 @@ NSLog([thePanel filename]);
NS_IMETHODIMP
nsCocoaBrowserService::ShowProgressDialog(nsIHelperAppLauncher *aLauncher, nsISupports *aContext)
{
return NS_OK;
}
NS_IMETHODIMP
nsCocoaBrowserService::Init(nsIURI* aSource,
nsILocalFile* aTarget,
const PRUnichar* aDisplayName,
const PRUnichar* aOpeningWith,
PRInt64 aStartTime,
nsIWebBrowserPersist* aPersist)
{
NSLog(@"nsIDownload::Init");
return NS_OK;
}
NS_IMETHODIMP
nsCocoaBrowserService::GetDisplayName(PRUnichar** aDisplayName)
{
NS_ERROR("NS_ERROR_NOT_IMPLEMENTED");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsCocoaBrowserService::SetDisplayName(const PRUnichar* aDisplayName)
{
return NS_OK;
}
NS_IMETHODIMP
nsCocoaBrowserService::GetOpeningWith(PRUnichar** aOpeningWith)
{
NS_ERROR("NS_ERROR_NOT_IMPLEMENTED");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsCocoaBrowserService::GetSource(nsIURI** aSource)
{
NS_ERROR("NS_ERROR_NOT_IMPLEMENTED");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsCocoaBrowserService::GetTarget(nsILocalFile** aTarget)
{
NS_ERROR("NS_ERROR_NOT_IMPLEMENTED");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsCocoaBrowserService::GetStartTime(PRInt64* aStartTime)
{
NS_ERROR("NS_ERROR_NOT_IMPLEMENTED");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsCocoaBrowserService::GetPercentComplete(PRInt32* aPercentComplete)
{
NS_ERROR("NS_ERROR_NOT_IMPLEMENTED");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsCocoaBrowserService::GetListener(nsIWebProgressListener** aListener)
{
NS_ERROR("NS_ERROR_NOT_IMPLEMENTED");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsCocoaBrowserService::SetListener(nsIWebProgressListener* aListener)
{
return NS_OK;
}
NS_IMETHODIMP
nsCocoaBrowserService::GetObserver(nsIObserver** aObserver)
{
NS_ERROR("NS_ERROR_NOT_IMPLEMENTED");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsCocoaBrowserService::SetObserver(nsIObserver* aObserver)
{
return NS_OK;
}
NS_IMETHODIMP
nsCocoaBrowserService::GetPersist(nsIWebBrowserPersist** aPersist)
{
NS_ERROR("NS_ERROR_NOT_IMPLEMENTED");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsCocoaBrowserService::OnStateChange(nsIWebProgress* aWebProgress,
nsIRequest* aRequest, PRUint32 aStateFlags,
PRUint32 aStatus)
{
return NS_OK;
}
NS_IMETHODIMP
nsCocoaBrowserService::OnStatusChange(nsIWebProgress *aWebProgress,
nsIRequest *aRequest, nsresult aStatus,
const PRUnichar *aMessage)
{
return NS_OK;
}
NS_IMETHODIMP
nsCocoaBrowserService::OnLocationChange(nsIWebProgress *aWebProgress,
nsIRequest *aRequest, nsIURI *aLocation)
{
return NS_OK;
}
NS_IMETHODIMP
nsCocoaBrowserService::OnProgressChange(nsIWebProgress *aWebProgress,
nsIRequest *aRequest,
PRInt32 aCurSelfProgress,
PRInt32 aMaxSelfProgress,
PRInt32 aCurTotalProgress,
PRInt32 aMaxTotalProgress)
{
return NS_OK;
}
NS_IMETHODIMP
nsCocoaBrowserService::OnSecurityChange(nsIWebProgress *aWebProgress,
nsIRequest *aRequest, PRUint32 aState)
{
NSLog(@"nsCocoaBrowserService::ShowProgressDialog");
return NS_OK;
}

Просмотреть файл

@ -36,7 +36,6 @@
* ***** END LICENSE BLOCK ***** */
#import "CHBrowserView.h"
#import "ProgressDlgController.h"
#import "FindDlgController.h"
#import "nsCocoaBrowserService.h"
#import "mozView.h"
@ -65,18 +64,12 @@
// Saving of links/images/docs
#include "nsIWebBrowserFocus.h"
#include "nsIDOMHTMLDocument.h"
#include "nsIDOMNSDocument.h"
#include "nsIDOMLocation.h"
#include "nsIURL.h"
#include "nsIWebBrowserPersist.h"
#include "nsIProperties.h"
#include "nsIRequest.h"
#include "nsIChannel.h"
#include "nsIHttpChannel.h"
#include "nsIPref.h"
#include "nsIMIMEService.h"
#include "nsIMIMEInfo.h"
#include "nsIPrefService.h"
#include "nsISHistory.h"
#include "nsIHistoryEntry.h"
#include "nsISHEntry.h"
@ -84,6 +77,7 @@
#include "nsIContextMenuListener.h"
#include "nsITooltipListener.h"
#include "nsIEmbeddingSiteWindow2.h"
#include "SaveHeaderSniffer.h"
typedef unsigned int DragReference;
#include "nsIDragHelperService.h"
@ -677,265 +671,7 @@ nsCocoaBrowserListener::SetContainer(id <NSBrowserContainer> aContainer)
[mContainer retain];
}
// Implementation of a header sniffer class that is used when saving Web pages and images.
class nsHeaderSniffer : public nsIWebProgressListener
{
public:
nsHeaderSniffer(nsIWebBrowserPersist* aPersist, nsIFile* aFile, nsIURI* aURL,
nsIDOMDocument* aDocument, nsIInputStream* aPostData,
const nsCString& aSuggestedFilename, PRBool aBypassCache,
NSView* aFilterView, NSPopUpButton* aFilterList)
{
NS_INIT_REFCNT();
mPersist = aPersist;
mTmpFile = aFile;
mURL = aURL;
mDocument = aDocument;
mPostData = aPostData;
mDefaultFilename = aSuggestedFilename;
mBypassCache = aBypassCache;
mFilterView = aFilterView;
mFilterList = aFilterList;
}
virtual ~nsHeaderSniffer()
{
};
NS_DECL_ISUPPORTS
NS_DECL_NSIWEBPROGRESSLISTENER
protected:
void PerformSave();
private:
nsIWebBrowserPersist* mPersist; // Weak. It owns us as a listener.
nsCOMPtr<nsIFile> mTmpFile;
nsCOMPtr<nsIURI> mURL;
nsCOMPtr<nsIDOMDocument> mDocument;
nsCOMPtr<nsIInputStream> mPostData;
nsCString mDefaultFilename;
PRBool mBypassCache;
nsCString mContentType;
nsCString mContentDisposition;
NSView* mFilterView;
NSPopUpButton* mFilterList;
};
NS_IMPL_ISUPPORTS1(nsHeaderSniffer, nsIWebProgressListener)
// Implementation of nsIWebProgressListener
/* void onStateChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in long aStateFlags, in unsigned long aStatus); */
NS_IMETHODIMP
nsHeaderSniffer::OnStateChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, PRUint32 aStateFlags,
PRUint32 aStatus)
{
if (aStateFlags & nsIWebProgressListener::STATE_START) {
nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest));
channel->GetContentType(mContentType);
// 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);
PerformSave();
}
return NS_OK;
}
void nsHeaderSniffer::PerformSave()
{
// 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"));
if (!prefs)
return;
nsCOMPtr<nsIPrefBranch> dirBranch;
prefs->GetBranch("browser.download.", getter_AddRefs(dirBranch));
PRInt32 filterIndex = 0;
if (dirBranch) {
nsresult rv = dirBranch->GetIntPref("save_converter_index", &filterIndex);
if (NS_FAILED(rv))
filterIndex = 0;
}
if (mFilterList)
[mFilterList selectItemAtIndex: filterIndex];
// We need to figure out what file name to use.
nsCAutoString 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 = filename;
}
}
if (defaultFileName.IsEmpty()) {
nsCOMPtr<nsIURL> url(do_QueryInterface(mURL));
if (url)
url->GetFileName(defaultFileName); // (2) For file URLs, use the file name.
}
if (defaultFileName.IsEmpty() && mDocument && isHTML) {
nsCOMPtr<nsIDOMHTMLDocument> htmlDoc(do_QueryInterface(mDocument));
nsAutoString title;
if (htmlDoc)
htmlDoc->GetTitle(title); // (3) Use the title of the document.
defaultFileName.AssignWithConversion(title);
}
if (defaultFileName.IsEmpty()) {
// (4) Use the caller provided name.
defaultFileName = mDefaultFilename;
}
if (defaultFileName.IsEmpty() && mURL)
// (5) Use the host.
mURL->GetHost(defaultFileName);
// One last case to handle about:blank and other fruity untitled pages.
if (defaultFileName.IsEmpty())
defaultFileName = "untitled";
// Validate the file name to ensure legality.
for (PRUint32 i = 0; i < defaultFileName.Length(); i++)
if (defaultFileName[i] == ':' || defaultFileName[i] == '/')
defaultFileName.SetCharAt(i, ' ');
// 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));
if (!fileURL)
return;
fileURL->SetFilePath(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 += ".html";
setExtension = PR_TRUE;
}
}
if (!setExtension && fileExtension.IsEmpty()) {
nsCOMPtr<nsIMIMEService> mimeService(do_GetService("@mozilla.org/mime;1"));
if (!mimeService)
return;
nsCOMPtr<nsIMIMEInfo> mimeInfo;
mimeService->GetFromMIMEType(mContentType.get(), getter_AddRefs(mimeInfo));
if (!mimeInfo)
return;
PRUint32 extCount = 0;
char** extList = nsnull;
mimeInfo->GetFileExtensions(&extCount, &extList);
if (extCount > 0 && extList) {
defaultFileName += ".";
defaultFileName += extList[0];
}
}
// Now it's time to pose the save dialog.
NSSavePanel* savePanel = [NSSavePanel savePanel];
NSString* file = nil;
if (!defaultFileName.IsEmpty())
file = [[NSString alloc] initWithCString: defaultFileName.get()];
if (isHTML)
[savePanel setAccessoryView: mFilterView];
if ([savePanel runModalForDirectory: nil file: file] == NSFileHandlingPanelCancelButton)
return;
// Release the file string.
[file release];
// Update the filter index.
if (isHTML && mFilterList) {
filterIndex = [mFilterList indexOfSelectedItem];
dirBranch->SetIntPref("save_converter_index", filterIndex);
}
// Convert the content type to text/plain if it was selected in the filter.
if (isHTML && filterIndex == 2)
mContentType = "text/plain";
nsCOMPtr<nsISupports> sourceData;
if (isHTML && filterIndex != 1)
sourceData = do_QueryInterface(mDocument);
else
sourceData = do_QueryInterface(mURL);
nsCOMPtr<nsIWebBrowserPersist> webPersist(do_CreateInstance(persistContractID));
ProgressDlgController* progressDialog = [[ProgressDlgController alloc] initWithWindowNibName: @"ProgressDialog"];
[progressDialog setWebPersist: webPersist
source: sourceData.get()
destination: [savePanel filename]
contentType: mContentType.get()
postData: mPostData
bypassCache: mBypassCache];
[progressDialog showWindow: progressDialog];
}
/* void onProgressChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in long aCurSelfProgress, in long aMaxSelfProgress, in long aCurTotalProgress, in long aMaxTotalProgress); */
NS_IMETHODIMP
nsHeaderSniffer::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
nsHeaderSniffer::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
nsHeaderSniffer::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
nsHeaderSniffer::OnSecurityChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, PRUint32 state)
{
return NS_OK;
}
#pragma mark -
@implementation CHBrowserView
@ -1244,13 +980,17 @@ nsHeaderSniffer::OnSecurityChange(nsIWebProgress *aWebProgress, nsIRequest *aReq
shEntry->GetPostData(getter_AddRefs(postData));
}
// when saving, we first fire off a save with a nsHeaderSniffer as a progress
// listener. This allows us to look for the content-disposition header, which
// can supply a filename, and maybe has something to do with CGI-generated
// content (?)
nsCAutoString fileName(aFilename);
nsHeaderSniffer* sniffer = new nsHeaderSniffer(webPersist, tmpFile, aURI,
aDocument, postData, fileName, aBypassCache,
aFilterView, aFilterList);
if (!sniffer)
return;
webPersist->SetProgressListener(sniffer);
webPersist->SetProgressListener(sniffer); // owned
webPersist->SaveURI(aURI, nsnull, tmpFile);
}

Просмотреть файл

Просмотреть файл

@ -0,0 +1,120 @@
/* ***** 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):
* 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 ***** */
// This file contains implementations of factories for various
// downloading-related interfaces.
#import "DownloadProgressDisplay.h"
#import "ProgressDlgController.h"
#include "nsCOMPtr.h"
#include "nsIFactory.h"
#include "nsDownloadListener.h"
#include "DownloadFactories.h"
// factory for nsIDownload objects
// XXX replace with generic factory stuff
class DownloadListenerFactory : public nsIFactory
{
public:
DownloadListenerFactory();
virtual ~DownloadListenerFactory();
NS_DECL_ISUPPORTS
NS_DECL_NSIFACTORY
protected:
DownloadControllerFactory* mControllerFactory; // factory which creates the Cocoa window controller
};
DownloadListenerFactory::DownloadListenerFactory()
: mControllerFactory(nil)
{
NS_INIT_ISUPPORTS();
mControllerFactory = [[[ChimeraDownloadControllerFactory alloc] init] retain];
}
DownloadListenerFactory::~DownloadListenerFactory()
{
[mControllerFactory release];
}
NS_IMPL_ISUPPORTS1(DownloadListenerFactory, nsIFactory);
/* void createInstance (in nsISupports aOuter, in nsIIDRef iid, [iid_is (iid), retval] out nsQIResult result); */
NS_IMETHODIMP
DownloadListenerFactory::CreateInstance(nsISupports *aOuter, const nsIID& aIID, void* *aResult)
{
nsresult rv;
if (aIID.Equals(NS_GET_IID(nsIDownload)))
{
nsDownloadListener* downloadListener = new nsDownloadListener(mControllerFactory);
if (!downloadListener) return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(downloadListener);
rv = downloadListener->QueryInterface(aIID, aResult);
NS_RELEASE(downloadListener);
return rv;
}
return NS_ERROR_NO_INTERFACE;
}
/* void lockFactory (in PRBool lock); */
NS_IMETHODIMP
DownloadListenerFactory::LockFactory(PRBool lock)
{
return NS_OK;
}
#pragma mark -
nsresult NewDownloadListenerFactory(nsIFactory* *outFactory)
{
DownloadListenerFactory* newFactory = new DownloadListenerFactory();
if (!newFactory) return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(newFactory);
nsresult rv = newFactory->QueryInterface(NS_GET_IID(nsIFactory), (void **)outFactory);
NS_RELEASE(newFactory);
return rv;
}

Просмотреть файл

@ -0,0 +1,161 @@
/* ***** 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):
* 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 ***** */
/*
The classes and protocol in this file allow Cocoa applications to easily
reuse the underlying download implementation, which deals with the complexity
of Gecko's downloading callbacks.
There are three things here:
1. The DownloadProgressDisplay protocol.
This is a formal protocol that needs to be implemented by
a window controller for your progress window. Its methods
will be called by the underlying C++ downloading classes.
2. The Obj-C DownloadControllerFactory class.
This class should be subclassed by an embedder, with an
implementation of 'createDownloadController' that hands back
a new instance of an NSWindowController that implements the
<DownloadProgressDisplay> protocol.
The underlying C++ classes use this factory to create the
progress window controller.
3. The nsDownloader C++ class
This base class exists to hide the complextity of the download
listener classes (which deal with Gecko callbacks) from the
window controller. Embedders don't need to do anything with it.
How these classes fit together:
There are 2 ways in which a download is initiated:
(i) File->Save.
Chimera does a complex dance here in order to get certain
information about the data being downloaded (it needs to
start the download before it can read some optional MIME headers).
CBrowserView creates an nsIWebBrowserPersist (WBP), and then a
nsHeaderSniffer, which implements nsIWebProgressListener and is set to
observer the WBP. When nsHeaderSniffer hears about the start of the
download, it decides on a file name, and what format to save the data
in. It then cancels the current WPB, makes another one, and does
a CreateInstance of an nsIDownload (making one of our nsDownloadListener
-- aka nsDownloder -- objects), and sets that as the nsIWebProgressListener.
The full download procedes from there.
(ii) Click to download (e.g. FTP link)
This is simpler. The backend (necko) does the CreateInstance of the
nsIDownload, and the download progresses.
In both cases, creating the nsDownloadListener and calling its Init() method
calls nsDownloder::CreateDownloadDisplay(). The nsDownloder has as a member
variable a DownloadControllerFactory (see above), which got passed to it
via our XPCOM factory for nsIDownload objects. It then uses that DownloadControllerFactory
to get an instance of the download progress window controller, which then
shows the download progress window.
Simple, eh?
*/
#import <AppKit/AppKit.h>
#include "nsISupports.h"
class nsDownloader;
// a formal protocol for something that implements progress display
// Embedders can make a window controller that conforms to this
// protocol, and reuse nsDownloadListener to get download UI.
@protocol DownloadProgressDisplay
- (void)onStartDownload;
- (void)onEndDownload;
- (void)setProgressTo:(long)aCurProgress ofMax:(long)aMaxProgress;
- (void)setDownloadListener:(nsDownloader*)aDownloader;
- (void)setSourceURL:(NSString*)aSourceURL;
- (void)setDestinationPath:(NSString*)aDestPath;
@end
// subclass this, and have your subclass instantiate and return your window
// controller in createDownloadController
@interface DownloadControllerFactory : NSObject
{
}
- (NSWindowController<DownloadProgressDisplay> *)createDownloadController;
@end
// Pure virtual base class for a generic downloader, that the progress UI can talk to.
// It implements nsISupports so that it can be refcounted. This class insulates the
// UI code from having to know too much about the nsIDownloadListener.
// It is responsible for creating the download UI, via the DownloadControllerFactory
// that it owns.
class nsDownloader : public nsISupports
{
public:
nsDownloader(DownloadControllerFactory* inControllerFactory);
virtual ~nsDownloader();
NS_DECL_ISUPPORTS
virtual void PauseDownload() = 0;
virtual void ResumeDownload() = 0;
virtual void CancelDownload() = 0;
virtual void DownloadDone() = 0;
virtual void CreateDownloadDisplay();
protected:
DownloadControllerFactory* mControllerFactory;
id <DownloadProgressDisplay> mDownloadDisplay; // something that implements the DownloadProgressDisplay protocol
};

Просмотреть файл

@ -0,0 +1,75 @@
/* ***** 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):
* 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 ***** */
#import "DownloadProgressDisplay.h"
@implementation DownloadControllerFactory
- (NSWindowController<DownloadProgressDisplay> *)createDownloadController
{
// a dummy implementation. You should provide a subclass that
// returns an instance of your progress dialog controller.
return nil;
}
@end
#pragma mark -
// see the header file for comments
nsDownloader::nsDownloader(DownloadControllerFactory* inControllerFactory)
: mControllerFactory(inControllerFactory)
, mDownloadDisplay(nil)
{
NS_INIT_ISUPPORTS();
[mControllerFactory retain];
}
nsDownloader::~nsDownloader()
{
[mControllerFactory release];
}
NS_IMPL_ISUPPORTS1(nsDownloader, nsISupports);
void
nsDownloader::CreateDownloadDisplay()
{
mDownloadDisplay = [mControllerFactory createDownloadController];
[mDownloadDisplay setDownloadListener:this];
}

Просмотреть файл

@ -89,8 +89,11 @@ app_getModuleInfo(nsStaticModuleInfo **info, PRUint32 *count);
nsresult rv;
ICStop (mInternetConfig);
nsCOMPtr<nsIPrefService> pref(do_GetService(NS_PREF_CONTRACTID, &rv));
if (!NS_FAILED(rv))
if (NS_SUCCEEDED(rv)) {
//NSLog(@"Saving prefs file");
pref->SavePrefFile(nsnull);
}
[super dealloc];
}