Fixes for #10737 (ftp download), overhauled to work better with Necko; r=valeski

This commit is contained in:
law%netscape.com 1999-11-13 05:37:00 +00:00
parent 1ea38abf06
commit 88626d4e62
12 changed files with 583 additions and 344 deletions

View File

@ -25,66 +25,48 @@
// may think they are. Welcome to reality.
#include "nsIFileSpec.idl"
%{C++
#include "nscore.h" // for NS_WIDGET
#include "nsIComponentManager.h"
%}
native StandardFilterMask(nsIFileSpecWithUI::StandardFilterMask);
#include "nsIComponentManager.idl"
[scriptable, uuid(8ddf7681-139a-11d3-915f-dc1f8c138b7c)]
interface nsIFileSpecWithUI : nsIFileSpec
{
%{C++
//
// The "choose" functions present the file picker UI in order to set the
// value of the file spec.
%}
// Filter mask flags. These may be or'd together.
const unsigned long eAllReadable = 1<<0;
const unsigned long eHTMLFiles = 1<<1;
const unsigned long eXMLFiles = 1<<2;
const unsigned long eImageFiles = 1<<3;
const unsigned long eMailFiles = 1<<4;
const unsigned long eTextFiles = 1<<5;
const unsigned long eAllFiles = 1<<6;
%{C++
// The mask for standard filters is given as follows:
enum StandardFilterMask
{
eAllReadable = (1<<0)
, eHTMLFiles = (1<<1)
, eXMLFiles = (1<<2)
, eImageFiles = (1<<3)
, eMailFiles = (1<<4)
, eTextFiles = (1<<5)
, eAllFiles = (1<<6)
const unsigned long eAllStandardFilters = eAllReadable |
eHTMLFiles |
eXMLFiles |
eImageFiles |
eMailFiles |
eTextFiles |
eAllFiles;
const unsigned long eAllMailOutputFilters = eHTMLFiles |
eMailFiles |
eTextFiles;
// Mask containing all the above default filters
, eAllStandardFilters = (
eAllReadable
| eHTMLFiles
| eXMLFiles
| eImageFiles
| eMailFiles
| eTextFiles
| eAllFiles)
, eAllMailOutputFilters = (
eHTMLFiles
| eMailFiles
| eTextFiles)
// The "extra filter" bit should be set if the "extra filter"
// is passed in to chooseInputFile.
, eExtraFilter = (1<<31)
};
enum { kNumStandardFilters = 7, kNumMailFilters = 3 };
%}
[noscript] void chooseInputFile(
in string title
, in StandardFilterMask standardFilterMask
, in string extraFilterTitle
, in string extraFilter
);
const unsigned long eExtraFilter = 1<<31;
[noscript] void chooseOutputFile(in string windowTitle,
in string suggestedLeafName,
in StandardFilterMask standardFilterMask);
const unsigned long kNumStandardFilters = 7;
const unsigned long kNumMailFilters = 3;
void chooseInputFile( in string title,
in unsigned long filterMask,
in string extraFilterTitle,
in string extraFilter );
void chooseOutputFile( in string windowTitle,
in string suggestedLeafName,
in unsigned long filterMask );
string chooseFile(in string title);
string chooseFile(in string title);
string chooseDirectory(in string title);
};

View File

@ -83,7 +83,7 @@ nsFileSpecWithUIImpl::~nsFileSpecWithUIImpl()
NS_IMETHODIMP nsFileSpecWithUIImpl::ChooseOutputFile(
const char *windowTitle,
const char *suggestedLeafName,
nsIFileSpecWithUI::StandardFilterMask outMask)
PRUint32 outMask)
//----------------------------------------------------------------------------------------
{
if (!mBaseFileSpec)
@ -101,10 +101,10 @@ NS_IMETHODIMP nsFileSpecWithUIImpl::ChooseOutputFile(
SetFileWidgetFilterList(fileWidget, outMask, nsnull, nsnull);
nsFileSpec spec;
// If there is a filespec specified, then start there.
if (GetFileSpec(&spec) != NS_ERROR_NOT_INITIALIZED)
fileWidget->SetDisplayDirectory(spec);
SetFileWidgetStartDir(fileWidget);
nsFileSpec spec;
nsString winTitle(windowTitle);
@ -129,7 +129,7 @@ NS_IMETHODIMP nsFileSpecWithUIImpl::ChooseFile(const char *title, char **_retval
// ---------------------------------------------------------------------------
void nsFileSpecWithUIImpl::SetFileWidgetFilterList(
nsIFileWidget* fileWidget, nsIFileSpecWithUI::StandardFilterMask mask,
nsIFileWidget* fileWidget, PRUint32 mask,
const char *inExtraFilterTitle, const char *inExtraFilter)
{
if (!fileWidget) return;
@ -199,10 +199,24 @@ Clean:
delete [] filters;
}
//----------------------------------------------------------------------------------------
void nsFileSpecWithUIImpl::SetFileWidgetStartDir( nsIFileWidget *fileWidget ) {
// We set the file widget's starting directory to the one specified by this nsIFileSpec.
if ( mBaseFileSpec && fileWidget ) {
nsFileSpec spec;
nsresult rv = mBaseFileSpec->GetFileSpec( &spec );
if ( NS_SUCCEEDED( rv ) && spec.Valid() ) {
// Set as starting directory in file widget.
fileWidget->SetDisplayDirectory( spec );
}
}
}
//----------------------------------------------------------------------------------------
NS_IMETHODIMP nsFileSpecWithUIImpl::ChooseInputFile(
const char *inTitle,
nsIFileSpecWithUI::StandardFilterMask inMask,
PRUint32 inMask,
const char *inExtraFilterTitle, const char *inExtraFilter)
//----------------------------------------------------------------------------------------
{
@ -220,6 +234,7 @@ NS_IMETHODIMP nsFileSpecWithUIImpl::ChooseInputFile(
SetFileWidgetFilterList(fileWidget, inMask,
inExtraFilterTitle, inExtraFilter);
SetFileWidgetStartDir(fileWidget);
nsString winTitle(inTitle);
if (fileWidget->GetFile(nsnull, winTitle, spec) != nsFileDlgResults_OK)
rv = NS_FILE_FAILURE;
@ -243,6 +258,7 @@ NS_IMETHODIMP nsFileSpecWithUIImpl::ChooseDirectory(const char *title, char **_r
(void**)getter_AddRefs(fileWidget));
if (NS_FAILED(rv))
return rv;
SetFileWidgetStartDir(fileWidget);
nsFileSpec spec;
if (fileWidget->GetFolder(nsnull, title, spec) != nsFileDlgResults_OK)
rv = NS_FILE_FAILURE;

View File

@ -103,7 +103,8 @@ class nsFileSpecWithUIImpl
{ return mBaseFileSpec ? mBaseFileSpec->GetParent(aParent) : NS_ERROR_NOT_INITIALIZED; }
/* boolean equals(in nsIFileSpec spec); */
NS_IMETHOD Equals(nsIFileSpec *spec, PRBool *result) { return mBaseFileSpec ? mBaseFileSpec->Equals(spec, result) : NS_ERROR_NOT_INITIALIZED; }
NS_IMETHOD Equals(nsIFileSpec *spec, PRBool *result)
{ return mBaseFileSpec ? mBaseFileSpec->Equals(spec, result) : NS_ERROR_NOT_INITIALIZED; }
/* nsIFileSpec makeUnique (); */
NS_IMETHOD MakeUnique()
@ -252,11 +253,13 @@ class nsFileSpecWithUIImpl
// Data
protected:
// helper
void SetFileWidgetFilterList(nsIFileWidget* fileWidget,
nsIFileSpecWithUI::StandardFilterMask mask,
const char *inExtraFilterTitle,
const char *inExtraFilter);
// helpers
void SetFileWidgetFilterList(nsIFileWidget* fileWidget,
PRUint32 mask,
const char *inExtraFilterTitle,
const char *inExtraFilter);
void SetFileWidgetStartDir(nsIFileWidget* fileWidget);
nsCOMPtr<nsIFileSpec> mBaseFileSpec;

View File

@ -22,14 +22,7 @@
#include "nsIAppShellComponent.idl"
#include "domstubs.idl"
interface nsIURI;
interface nsIChannel;
%{C++
class nsIDOMWindow; // Seems domstubs.idl should do this, though.
%}
#include "nsIChannel.idl"
/*----------------------- nsIUnknownContentTypeHandler -------------------------
| This file describes the interface for Mozilla's "unknown content-type |
@ -38,7 +31,7 @@ class nsIDOMWindow; // Seems domstubs.idl should do this, though.
| |
| This component provides one component-specific member function: |
| HandleUnknownContentType. This method's areguments include: |
| o the URL at which the content resides |
| o the nsIChannel that encountered the content |
| o the content-type |
| o the window that encountered the unknown content. |
| |

View File

@ -26,15 +26,17 @@ var dialog;
function initData() {
// Create data object and initialize.
data = new Object;
data.location = window.arguments[0];
data.contentType = window.arguments[1];
data.channel = window.arguments[0];
data.contentType = window.arguments[1];
// Get location from channel.
data.location = data.channel.URI.spec;
}
function initDialog() {
// Create dialog object and initialize.
dialog = new Object;
dialog.contentType = document.getElementById("dialog.contentType");
dump("dialog.contentType="+dialog.contentType+"\n");
dialog.more = document.getElementById("dialog.more");
dialog.pick = document.getElementById("dialog.pick");
dialog.save = document.getElementById("dialog.save");
@ -58,7 +60,6 @@ function onLoad() {
}
function onUnload() {
// Nothing for now.
}
function more() {
@ -84,7 +85,7 @@ function save() {
xfer.SelectFileAndTransferLocationSpec( data.location, window.opener );
} catch( exception ) {
// Failed (or cancelled), give them another chance.
dump( "SelectFileAndTransferLocationSpec failed, rv=" + exception + "\n" );
alert( "Save failed, rv=" + exception + "\n" );
return;
}
// Save underway, close this dialog.
@ -92,6 +93,6 @@ function save() {
}
function cancel() {
// Close the window.
// Close this dialog.
window.close();
}

View File

@ -24,11 +24,10 @@
#include "nsIAppShellComponentImpl.h"
#include "nsString.h"
#include "nsIURL.h"
#include "nsIDOMWindow.h"
#include "nsIScriptGlobalObject.h"
#include "nsIChannel.h"
#include "nsIURI.h"
// {42770B50-03E9-11d3-8068-00600811A9C3}
#define NS_UNKNOWNCONTENTTYPEHANDLER_CID \
@ -64,79 +63,78 @@ NS_IMETHODIMP
nsUnknownContentTypeHandler::HandleUnknownContentType( nsIChannel *aChannel,
const char *aContentType,
nsIDOMWindow *aWindow ) {
if ( !aWindow ) {
return NS_ERROR_NULL_POINTER;
}
nsresult rv = NS_OK;
// Open "Unknown content type" dialog.
// We pass in the url and the content type.
// Note that the "parent" browser window will be window.opener within the
// new dialog.
nsCOMPtr<nsISupports> channel;
// Extract URI from channel.
nsCOMPtr<nsIURI> channelUri = nsnull;
rv = aChannel->GetURI(getter_AddRefs(channelUri));
if ( NS_FAILED( rv ) ) {
DEBUG_PRINTF( PR_STDOUT, "%s %d: GetURI failed, rv=0x%08X\n",
(char*)__FILE__, (int)__LINE__, (int)rv );
return rv;
if ( aChannel ) {
// Need root nsISupports for later JS_PushArguments call.
channel = do_QueryInterface( aChannel );
// Cancel input channel now.
rv = aChannel->Cancel();
if ( NS_FAILED( rv ) ) {
DEBUG_PRINTF( PR_STDOUT, "%s %d: Cancel failed, rv=0x%08X\n",
(char*)__FILE__, (int)__LINE__, (int)rv );
}
}
// url string non-const in this case.
char *urlStr = 0;
// Get url string from channel.
channelUri->GetSpec( &urlStr );
// Get JS context from parent window.
nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface( aWindow, &rv );
if ( NS_SUCCEEDED( rv ) && sgo ) {
nsCOMPtr<nsIScriptContext> context;
sgo->GetContext( getter_AddRefs( context ) );
if ( context ) {
JSContext *jsContext = (JSContext*)context->GetNativeContext();
if ( jsContext ) {
void *stackPtr;
jsval *argv = JS_PushArguments( jsContext,
&stackPtr,
"sssss",
"chrome://global/content/unknownContent.xul",
"_blank",
"chrome",
urlStr,
aContentType );
// Free url string.
nsCRT::free(urlStr);
if ( argv ) {
nsIDOMWindow *newWindow;
rv = aWindow->OpenDialog( jsContext, argv, 5, &newWindow );
if ( NS_SUCCEEDED( rv ) ) {
newWindow->Release();
if ( NS_SUCCEEDED( rv ) && channel && aContentType && aWindow ) {
// Open "Unknown content type" dialog.
// We pass in the channel and the content type.
// Note that the "parent" browser window will be window.opener within the
// new dialog.
// Get JS context from parent window.
nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface( aWindow, &rv );
if ( NS_SUCCEEDED( rv ) && sgo ) {
nsCOMPtr<nsIScriptContext> context;
sgo->GetContext( getter_AddRefs( context ) );
if ( context ) {
JSContext *jsContext = (JSContext*)context->GetNativeContext();
if ( jsContext ) {
void *stackPtr;
jsval *argv = JS_PushArguments( jsContext,
&stackPtr,
"sss%ips",
"chrome://global/content/unknownContent.xul",
"_blank",
"chrome",
(const nsIID*)(&nsIChannel::GetIID()),
(nsISupports*)channel.get(),
aContentType );
if ( argv ) {
nsCOMPtr<nsIDOMWindow> newWindow;
rv = aWindow->OpenDialog( jsContext, argv, 5, getter_AddRefs( newWindow ) );
if ( NS_FAILED( rv ) ) {
DEBUG_PRINTF( PR_STDOUT, "%s %d: OpenDialog failed, rv=0x%08X\n",
(char*)__FILE__, (int)__LINE__, (int)rv );
}
JS_PopArguments( jsContext, stackPtr );
} else {
DEBUG_PRINTF( PR_STDOUT, "%s %d: OpenDialog failed, rv=0x%08X\n",
(char*)__FILE__, (int)__LINE__, (int)rv );
DEBUG_PRINTF( PR_STDOUT, "%s %d: JS_PushArguments failed\n",
(char*)__FILE__, (int)__LINE__ );
rv = NS_ERROR_FAILURE;
}
JS_PopArguments( jsContext, stackPtr );
} else {
DEBUG_PRINTF( PR_STDOUT, "%s %d: JS_PushArguments failed\n",
DEBUG_PRINTF( PR_STDOUT, "%s %d: GetNativeContext failed\n",
(char*)__FILE__, (int)__LINE__ );
rv = NS_ERROR_FAILURE;
}
} else {
DEBUG_PRINTF( PR_STDOUT, "%s %d: GetNativeContext failed\n",
DEBUG_PRINTF( PR_STDOUT, "%s %d: GetContext failed\n",
(char*)__FILE__, (int)__LINE__ );
rv = NS_ERROR_FAILURE;
}
} else {
DEBUG_PRINTF( PR_STDOUT, "%s %d: GetContext failed\n",
(char*)__FILE__, (int)__LINE__ );
rv = NS_ERROR_FAILURE;
DEBUG_PRINTF( PR_STDOUT, "%s %d: QueryInterface (for nsIScriptGlobalObject) failed, rv=0x%08X\n",
(char*)__FILE__, (int)__LINE__, (int)rv );
}
} else {
DEBUG_PRINTF( PR_STDOUT, "%s %d: QueryInterface (for nsIScriptGlobalObject) failed, rv=0x%08X\n",
(char*)__FILE__, (int)__LINE__, (int)rv );
// If no error recorded so far, set one now.
if ( NS_SUCCEEDED( rv ) ) {
rv = NS_ERROR_NULL_POINTER;
}
}
return rv;

View File

@ -22,13 +22,7 @@
#include "nsIAppShellComponent.idl"
#include "domstubs.idl"
[ptr] native nsIURI( nsIURI );
%{C++
class nsIURI;
class nsIDOMWindow;
%}
#include "nsIChannel.idl"
/*----------------------------- nsIStreamTransfer ------------------------------
| This file describes Mozilla's general-purpose "stream transfer" component. |
@ -51,11 +45,18 @@ class nsIDOMWindow;
interface nsIStreamTransfer : nsIAppShellComponent {
/*-------------------- SelectFileAndTransferLocation -----------------------
| Prompt the user for a destination file and then transfer the data using |
| the argument URL as source to that file, while showing a progress |
| Prompt the user for a destination file and then transfer the data, using |
| the argument channel as source, to that file, while showing a progress |
| dialog. |
--------------------------------------------------------------------------*/
[noscript] void SelectFileAndTransferLocation( in nsIChannel aChannel,
in nsIDOMWindow parent );
/*------------------ SelectFileAndTransferLocationSpec ---------------------
| Prompt the user for a destination file and then transfer the data, using |
| the argument URL as source, to that file, while showing a progress |
| dialog. |
--------------------------------------------------------------------------*/
[noscript] void SelectFileAndTransferLocation( in nsIURI aURL, in nsIDOMWindow parent );
void SelectFileAndTransferLocationSpec( in string aURL, in nsIDOMWindow parent );
};

View File

@ -21,6 +21,8 @@
*/
#include "nsISupports.idl"
#include "nsIChannel.idl"
#include "nsIFileSpec.idl"
interface nsIObserver;
@ -34,11 +36,22 @@ interface nsIObserver;
------------------------------------------------------------------------------*/
[scriptable, uuid(E2200F90-3E23-11d3-806A-00600811A9C3)]
interface nsIStreamTransferOperation : nsISupports {
readonly attribute string source;
readonly attribute string target;
readonly attribute nsIChannel source;
readonly attribute nsIFileSpec target;
attribute nsIObserver observer;
void Start();
void Stop();
// Operation codes (for error notifications):
const unsigned long kOpAsyncRead = 1;
const unsigned long kOpWrite = 2;
const unsigned long kOpOpenOutputStream = 3;
const unsigned long kOpCreateTransport = 4;
const unsigned long kOpGetService = 5;
const unsigned long kOpInputCancel = 6;
const unsigned long kOpOutputClose = 8;
const unsigned long kOpOutputCancel = 9;
const unsigned long kOpRead = 10;
};

View File

@ -1,9 +1,32 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (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 Communicator client code,
* released March 31, 1998.
*
* The Initial Developer of the Original Code is Netscape Communications
* Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*
* Contributors:
* William A. ("PowerGUI") Law <law@netscape.com>
*/
var data; // nsIStreamTransferOperation object
var dialog;
function loadDialog() {
dialog.location.setAttribute( "value", data.source );
dialog.fileName.setAttribute( "value", data.target );
dialog.location.setAttribute( "value", data.source.URI.spec );
dialog.fileName.setAttribute( "value", data.target.nativePath );
}
var progId = "component://netscape/appshell/component/xfer";
@ -21,7 +44,7 @@ var observer = {
onCompletion( data );
break;
default:
dump( "Unknown topic: " + topic + "\n" );
alert( "Unknown topic: " + topic + "\nData: " + data );
break;
}
return;
@ -59,8 +82,11 @@ function onUnload() {
// Unhook observer.
data.observer = null;
// Terminate transfer.
data.Stop();
// See if we completed normally (i.e., are closing ourself).
if ( !completed ) {
// Terminate transfer.
data.Stop();
}
}
var started = false;
@ -84,14 +110,16 @@ function onProgress( bytes, max ) {
// Initialize download start time.
started = true;
startTime = ( new Date() ).getTime();
// Let the user stop, now.
dialog.cancel.removeAttribute( "disabled" );
}
// Get current time.
var now = ( new Date() ).getTime();
// If interval hasn't elapsed, ignore it.
if ( now - lastUpdate < interval && eval(bytes) < eval(max) ) {
if ( now - lastUpdate < interval
&&
max != "-1"
&&
eval(bytes) < eval(max) ) {
return;
}
@ -108,19 +136,31 @@ function onProgress( bytes, max ) {
}
// Calculate percentage.
var percent = Math.round( (bytes*100)/max );
var percent;
if ( max != "-1" ) {
percent = Math.round( (bytes*100)/max );
// Advance progress meter.
dialog.progress.setAttribute( "value", percent );
} else {
percent = "??";
// Progress meter should be barber-pole in this case.
dialog.progress.setAttribute( "mode", "undetermined" );
}
// Advance progress meter.
dialog.progress.setAttribute( "value", percent );
// Check if download complete.
if ( !completed ) {
// Update status (nnn of mmm)
var status = "( ";
status += Math.round( bytes/1024 );
status += "K of ";
status += Math.round( max/1024 );
status += "K bytes ";
if ( max != "-1" ) {
status += Math.round( max/1024 );
status += "K bytes ";
} else {
status += "??.?K bytes ";
}
if ( rate ) {
status += "at ";
status += Math.round( (rate*10)/1024 ) / 10;
@ -137,9 +177,11 @@ function onProgress( bytes, max ) {
if ( !completed ) {
// Update time remaining.
if ( rate ) {
if ( rate && max != "-1" ) {
var rem = Math.round( ( max - bytes ) / rate ); // In seconds.
dialog.timeLeft.childNodes[0].nodeValue = formatSeconds( rem );
} else {
dialog.timeLeft.childNodes[0].nodeValue = "??:??:??";
}
} else {
// Clear time remaining field.
@ -150,12 +192,12 @@ function onProgress( bytes, max ) {
function formatSeconds( nSecs ) {
status = "";
if ( nSecs >= 3600 ) {
status += Math.round( nSecs/3600 ) + " hours, ";
status += Math.round( nSecs/3600 ) + ":";
nSecs = nSecs % 3600;
}
status += Math.round( nSecs/60 ) + " minutes and ";
status += Math.round( nSecs/60 ) + ":";
nSecs = nSecs % 60;
status += nSecs + " seconds";
status += nSecs;
return status;
}
@ -164,8 +206,22 @@ function onCompletion( status ) {
completed = true;
// Indicate completion in status area.
onStatus( "Download completed in " + formatSeconds( elapsed/1000 ) );
// Close the window in 2 seconds (to ensure user sees we're done).
window.setTimeout( "window.close();", 2000 );
// Put progress meter at 100%.
dialog.progress.setAttribute( "value", 100 );
dialog.progress.setAttribute( "mode", "normal" );
try {
// Close the window in 2 seconds (to ensure user sees we're done).
window.setTimeout( "window.close();", 2000 );
} catch ( exception ) {
dump( "Error setting close timeout\n" );
for ( prop in exception ) {
dump( "exception." + prop + "=" + exception[ prop ] + "\n" );
}
// Bug prevents that from working, just close the window.
window.close();
// If that's not working either, change button text to give user a clue.
dialog.cancel.childNodes[0].nodeValue = "Close";
}
}
function onStatus( status ) {

View File

@ -23,18 +23,15 @@
#include "nsIAppShellComponentImpl.h"
#include "nsStreamXferOp.h"
#include "nsIFileWidget.h"
#include "nsWidgetsCID.h"
#include "nsIURL.h"
#include "nsIFileSpecWithUI.h"
#include "nsNeckoUtil.h"
#include "nsIPref.h"
#include "nsIURL.h"
// {BEBA91C0-070F-11d3-8068-00600811A9C3}
#define NS_STREAMTRANSFER_CID \
{ 0xbeba91c0, 0x70f, 0x11d3, { 0x80, 0x68, 0x0, 0x60, 0x8, 0x11, 0xa9, 0xc3 } }
static NS_DEFINE_IID( kCFileWidgetCID, NS_FILEWIDGET_CID );
static NS_DEFINE_IID( kIFileWidgetIID, NS_IFILEWIDGET_IID );
// Implementation of the stream transfer component interface.
class nsStreamTransfer : public nsIStreamTransfer,
public nsAppShellComponentImpl {
@ -59,31 +56,36 @@ public:
private:
// Put up file picker dialog.
NS_IMETHOD SelectFile( nsFileSpec &result );
NS_IMETHOD SelectFile( nsIFileSpec **result, const nsCString &suggested );
nsCString SuggestNameFor( nsIChannel *aChannel );
// Objects of this class are counted to manage library unloading...
nsInstanceCounter instanceCounter;
}; // nsStreamTransfer
NS_IMETHODIMP
nsStreamTransfer::SelectFileAndTransferLocation( nsIURI *aURL, nsIDOMWindow *parent ) {
nsStreamTransfer::SelectFileAndTransferLocation( nsIChannel *aChannel, nsIDOMWindow *parent ) {
// Prompt the user for the destination file.
nsFileSpec outputFileName;
nsresult rv = SelectFile( outputFileName );
nsCOMPtr<nsIFileSpec> outputFile;
PRBool isValid = PR_FALSE;
nsresult rv = SelectFile( getter_AddRefs( outputFile ),
SuggestNameFor( aChannel ).GetBuffer() );
if ( NS_SUCCEEDED( rv ) ) {
// Open a downloadProgress dialog.
char *source = 0;
aURL->GetSpec( &source );
if ( NS_SUCCEEDED( rv )
&&
outputFile
&&
NS_SUCCEEDED( outputFile->IsValid( &isValid ) )
&&
isValid ) {
// Construct stream transfer operation to be given to dialog.
nsStreamXferOp *p= new nsStreamXferOp( aChannel, outputFile );
nsStreamXferOp *p= new nsStreamXferOp( source, (const char*)outputFileName );
nsCOMPtr<nsIStreamTransferOperation> op = dont_QueryInterface( (nsIStreamTransferOperation*)p );
nsCRT::free( source );
if ( op ) {
if ( p ) {
// Open download progress dialog.
NS_ADDREF(p);
rv = p->OpenDialog( parent );
NS_RELEASE(p);
if ( NS_FAILED( rv ) ) {
DEBUG_PRINTF( PR_STDOUT, "%s %d : Error opening dialog, rv=0x%08X\n",
(char *)__FILE__, (int)__LINE__, (int)rv );
@ -94,7 +96,11 @@ nsStreamTransfer::SelectFileAndTransferLocation( nsIURI *aURL, nsIDOMWindow *par
rv = NS_ERROR_OUT_OF_MEMORY;
}
} else {
DEBUG_PRINTF( PR_STDOUT, "Failed to select file, rv=0x%X\n", (int)rv );
if ( NS_FAILED( rv ) ) {
DEBUG_PRINTF( PR_STDOUT, "Failed to select file, rv=0x%X\n", (int)rv );
} else {
// User cancelled.
}
}
return rv;
@ -105,45 +111,107 @@ nsStreamTransfer::SelectFileAndTransferLocationSpec( char const *aURL, nsIDOMWin
nsresult rv = NS_OK;
// Construct URI from spec.
nsIURI *uri;
rv = NS_NewURI( &uri, aURL );
nsCOMPtr<nsIURI> uri;
rv = NS_NewURI( getter_AddRefs( uri ), aURL );
if ( NS_SUCCEEDED( rv ) && uri ) {
rv = this->SelectFileAndTransferLocation( uri,parent );
NS_RELEASE( uri );
// Construct channel from URI.
nsCOMPtr<nsIChannel> channel;
rv = NS_OpenURI( getter_AddRefs( channel ), uri, nsnull );
if ( NS_SUCCEEDED( rv ) && channel ) {
// Transfer channel to output file chosen by user.
rv = this->SelectFileAndTransferLocation( channel, parent );
} else {
DEBUG_PRINTF( PR_STDOUT, "Failed to open URI, rv=0x%X\n", (int)rv );
}
} else {
DEBUG_PRINTF( PR_STDOUT, "Failed to create URI, rv=0x%X\n", (int)rv );
}
return rv;
}
NS_IMETHODIMP
nsStreamTransfer::SelectFile( nsFileSpec &aResult ) {
nsStreamTransfer::SelectFile( nsIFileSpec **aResult, const nsCString &suggested ) {
nsresult rv = NS_OK;
// Prompt user for file name.
nsIFileWidget* fileWidget;
nsString title("Save File");
if ( aResult ) {
*aResult = 0;
rv = nsComponentManager::CreateInstance( kCFileWidgetCID,
nsnull,
kIFileWidgetIID,
(void**)&fileWidget );
if ( NS_SUCCEEDED( rv ) && fileWidget ) {
nsFileDlgResults result = fileWidget->PutFile( nsnull, title, aResult );
if ( result == nsFileDlgResults_OK || result == nsFileDlgResults_Replace ) {
// Prompt user for file name.
nsCOMPtr<nsIFileSpecWithUI> result;
result = getter_AddRefs( NS_CreateFileSpecWithUI() );
if ( result ) {
// Prompt for file name.
nsCOMPtr<nsIFileSpec> startDir;
// Pull in the user's preferences and get the default download directory.
NS_WITH_SERVICE( nsIPref, prefs, NS_PREF_PROGID, &rv );
if ( NS_SUCCEEDED( rv ) && prefs ) {
prefs->GetFilePref( "browser.download.dir", getter_AddRefs( startDir ) );
if ( startDir ) {
PRBool isValid = PR_FALSE;
startDir->IsValid( &isValid );
if ( isValid ) {
// Set result so startDir is used.
result->FromFileSpec( startDir );
}
}
}
//XXX l10n
nsAutoCString title("Save File");
rv = result->ChooseOutputFile( title,
suggested.IsEmpty() ? 0 : suggested.GetBuffer(),
nsIFileSpecWithUI::eAllFiles );
if ( NS_SUCCEEDED( rv ) ) {
// Give result to caller.
rv = result->QueryInterface( nsIFileSpec::GetIID(), (void**)aResult );
if ( NS_SUCCEEDED( rv ) && prefs ) {
// Save selected directory for next time.
rv = result->GetParent( getter_AddRefs( startDir ) );
if ( NS_SUCCEEDED( rv ) && startDir ) {
prefs->SetFilePref( "browser.download.dir", startDir, PR_FALSE );
}
}
}
} else {
rv = NS_ERROR_ABORT;
DEBUG_PRINTF( PR_STDOUT, "%s %d: Error creating file widget, rv=0x%X\n",
__FILE__, (int)__LINE__, (int)rv );
}
NS_RELEASE( fileWidget );
} else {
DEBUG_PRINTF( PR_STDOUT, "%s %d: Error creating file widget, rv=0x%X\n",
__FILE__, (int)__LINE__, (int)rv );
rv = NS_ERROR_NULL_POINTER;
}
return rv;
}
nsCString nsStreamTransfer::SuggestNameFor( nsIChannel *aChannel ) {
nsCString result;
if ( aChannel ) {
// Get URI from channel and spec from URI.
nsCOMPtr<nsIURI> uri;
nsresult rv = aChannel->GetURI( getter_AddRefs( uri ) );
if ( NS_SUCCEEDED( rv ) && uri ) {
// Try to get URL from URI.
nsCOMPtr<nsIURL> url( do_QueryInterface( uri, &rv ) );
if ( NS_SUCCEEDED( rv ) && url ) {
char *nameFromURL = 0;
rv = url->GetFileName( &nameFromURL );
if ( NS_SUCCEEDED( rv ) && nameFromURL ) {
result = nameFromURL;
nsCRT::free( nameFromURL );
}
}
}
}
return result;
}
// Generate base nsIAppShellComponent implementation.
NS_IMPL_IAPPSHELLCOMPONENT( nsStreamTransfer,
nsIStreamTransfer,

View File

@ -20,39 +20,40 @@
* Contributor(s):
*/
#include "nsStreamXferOp.h"
#include "nsIStreamTransfer.h"
#include "nsString.h"
#include "nsCOMPtr.h"
#include "nsFileStream.h"
#include "nsFileSpec.h"
// Basic dependencies.
#include "nsIServiceManager.h"
// For notifying observer.
#include "nsIObserver.h"
// For opening dialog.
#include "nsIDOMWindow.h"
#include "nsIScriptGlobalObject.h"
#include "nsNeckoUtil.h"
#include "nsIURL.h"
#include "nsIChannel.h"
#include "nsIEventQueueService.h"
#include "nsIBufferInputStream.h"
static NS_DEFINE_IID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID);
#include "jsapi.h"
#include "prprf.h"
// For opening input/output streams.
#include "nsIFileTransportService.h"
#include "nsIOutputStream.h"
#include "nsNeckoUtil.h"
#ifdef NS_DEBUG
#include "prprf.h"
#define DEBUG_PRINTF PR_fprintf
#else
#define DEBUG_PRINTF (void)
#endif
// ctor - save arguments in data members.
nsStreamXferOp::nsStreamXferOp( const nsString &source, const nsString &target )
: mSource( source ),
mTarget( target ),
nsStreamXferOp::nsStreamXferOp( nsIChannel *source, nsIFileSpec *target )
: mInputChannel( source ),
mOutputChannel( 0 ),
mOutputStream( 0 ),
mOutputSpec( target ),
mObserver( 0 ),
mBufLen( 8192 ),
mBuffer( new char[ mBufLen ] ),
mStopped( PR_FALSE ),
mOutput( 0 ) {
mContentLength( 0 ),
mBytesProcessed( 0 ) {
// Properly initialize refcnt.
NS_INIT_REFCNT();
}
@ -60,9 +61,9 @@ nsStreamXferOp::nsStreamXferOp( const nsString &source, const nsString &target )
// dtor
nsStreamXferOp::~nsStreamXferOp() {
// Delete dynamically allocated members (file and buffer).
#ifdef DEBUG_law
DEBUG_PRINTF( PR_STDOUT, "nsStreamXferOp destructor called\n" );
delete mOutput;
delete [] mBuffer;
#endif
}
// Invoke nsIDOMWindow::OpenDialog, passing this object as argument.
@ -87,11 +88,9 @@ nsStreamXferOp::OpenDialog( nsIDOMWindow *parent ) {
(const nsIID*)(&nsCOMTypeInfo<nsIStreamTransferOperation>::GetIID()),
(nsISupports*)(nsIStreamTransferOperation*)this );
if ( argv ) {
nsIDOMWindow *newWindow;
rv = parent->OpenDialog( jsContext, argv, 4, &newWindow );
if ( NS_SUCCEEDED( rv ) ) {
newWindow->Release();
} else {
nsCOMPtr<nsIDOMWindow> newWindow;
rv = parent->OpenDialog( jsContext, argv, 4, getter_AddRefs( newWindow ) );
if ( NS_FAILED( rv ) ) {
DEBUG_PRINTF( PR_STDOUT, "%s %d: nsIDOMWindow::OpenDialog failed, rv=0x%08X\n",
(char*)__FILE__, (int)__LINE__, (int)rv );
}
@ -118,64 +117,118 @@ nsStreamXferOp::OpenDialog( nsIDOMWindow *parent ) {
return rv;
}
// Start the download by opening the output file and then loading the source location.
// Notify observer of error.
NS_IMETHODIMP
nsStreamXferOp::OnError( int operation, nsresult errorCode ) {
nsresult rv = NS_OK;
#ifdef DEBUG_law
DEBUG_PRINTF( PR_STDOUT, "nsStreamXferOp::OnError; op=%d, rv=0x%08X\n",
operation, (int)errorCode );
#endif
if ( mObserver ) {
char buf[32];
PR_snprintf( buf, sizeof( buf ), "%d %X", operation, (int)errorCode );
rv = mObserver->Observe( (nsIStreamTransferOperation*)this,
nsAutoString( NS_ISTREAMTRANSFER_PROGID ";onError" ).GetUnicode(),
nsAutoString( buf ).GetUnicode() );
if ( NS_FAILED( rv ) ) {
DEBUG_PRINTF( PR_STDOUT, "%s %d: Observe failed, rv=0x%08X\n",
(char*)__FILE__, (int)__LINE__, (int)rv );
}
}
return rv;
};
// Start the download by opening the output file and then reading the input channel.
NS_IMETHODIMP
nsStreamXferOp::Start( void ) {
nsresult rv = NS_OK;
if ( !mOutput ) {
// Open the output file stream.
mOutput = new nsOutputFileStream( nsFileSpec( mTarget.GetBuffer() ) );
if ( mOutput ) {
if ( !mOutput->failed() ) {
nsIURI *url = 0;
rv = NS_NewURI( &url, mSource.GetBuffer() );
if ( NS_SUCCEEDED( rv ) && url ) {
// XXX: Should there be a LoadGroup?
nsresult rv = NS_OpenURI( this, nsnull, url, nsnull
);
NS_RELEASE(url);
if ( mInputChannel ) {
if ( !mOutputChannel ) {
// First, get file transport service.
NS_DEFINE_IID(kFileTransportServiceCID, NS_FILETRANSPORTSERVICE_CID);
NS_WITH_SERVICE( nsIFileTransportService, fts, kFileTransportServiceCID, &rv );
if ( NS_SUCCEEDED( rv ) ) {
// Next, create output file channel.
nsFileSpec target;
mOutputSpec->GetFileSpec( &target );
rv = fts->CreateTransport( target,
"load",
0,
getter_AddRefs( mOutputChannel ) );
if ( NS_SUCCEEDED( rv ) ) {
// Read the input channel (with ourself as the listener).
rv = mInputChannel->AsyncRead( 0, -1, 0, this );
if ( NS_FAILED( rv ) ) {
DEBUG_PRINTF( PR_STDOUT, "%s %d: NS_OpenURI failed, rv=0x%08X\n",
(char*)__FILE__, (int)__LINE__, (int)rv );
this->OnError( kOpAsyncRead, rv );
}
} else {
DEBUG_PRINTF( PR_STDOUT, "%s %d: NS_NewURI failed, rv=0x%X\n",
__FILE__, (int)__LINE__, (int)rv );
this->OnError( kOpCreateTransport, rv );
rv = NS_ERROR_OUT_OF_MEMORY;
}
} else {
DEBUG_PRINTF( PR_STDOUT, "%s %d: error opening output file, rv=0x%08X\n",
(char*)__FILE__, (int)__LINE__, (int)mOutput->error() );
delete mOutput;
mOutput = 0;
this->OnError( kOpGetService, rv );
}
} else {
rv = NS_ERROR_OUT_OF_MEMORY;
rv = NS_ERROR_ALREADY_INITIALIZED;
this->OnError( 0, rv );
}
} else {
DEBUG_PRINTF( PR_STDOUT, "%s %d: nsStreamXferOp already started\n",
(char*)__FILE__, (int)__LINE__ );
rv = NS_ERROR_ALREADY_INITIALIZED;
rv = NS_ERROR_NOT_INITIALIZED;
this->OnError( 0, rv );
}
// If an error occurred, shut down.
if ( NS_FAILED( rv ) ) {
this->Stop();
}
return rv;
}
// Terminate the download by setting flag (checked in OnDataAvailable).
// Terminate the download by cancelling/closing input and output channels.
NS_IMETHODIMP
nsStreamXferOp::Stop( void ) {
nsresult rv = NS_OK;
// Set flag indicating netlib xfer should cease.
mStopped = PR_TRUE;
// Cancel input.
if ( mInputChannel ) {
// Unhook it first.
nsCOMPtr<nsIChannel> channel = mInputChannel;
mInputChannel = 0;
// Now cancel it.
rv = channel->Cancel();
if ( NS_FAILED( rv ) ) {
this->OnError( kOpInputCancel, rv );
}
}
// Close output stream.
if ( mOutputStream ) {
// Unhook it first.
nsCOMPtr<nsIOutputStream> stream = mOutputStream;
mOutputStream = 0;
// Now close it.
rv = stream->Close();
if ( NS_FAILED( rv ) ) {
this->OnError( kOpOutputClose, rv );
}
}
// Cancel output channel.
mOutputChannel = 0;
return rv;
}
// Process the data by reading it and then writing it to the output file.
// Process the data by writing it to the output channel.
NS_IMETHODIMP
nsStreamXferOp::OnDataAvailable( nsIChannel *channel,
nsISupports *aContext,
@ -184,67 +237,102 @@ nsStreamXferOp::OnDataAvailable( nsIChannel *channel,
PRUint32 aLength ) {
nsresult rv = NS_OK;
// Check for download cancelled by user.
if ( mStopped ) {
// Close the output file.
if ( mOutput ) {
mOutput->close();
}
// Close the input stream.
aIStream->Close();
} else {
// Allocate buffer space.
if ( aLength > mBufLen ) {
char *oldBuffer = mBuffer;
mBuffer = new char[ aLength ];
if ( mBuffer ) {
// Use new (bigger) buffer.
mBufLen = aLength;
// Delete old (smaller) buffer.
delete [] oldBuffer;
} else {
// Keep the one we've got.
mBuffer = oldBuffer;
}
}
// Read the data.
PRUint32 bytesRead;
rv = aIStream->Read( mBuffer, ( mBufLen > aLength ) ? aLength : mBufLen, &bytesRead );
if ( NS_SUCCEEDED(rv) && bytesRead > 0 ) {
// Write the data just read to the output stream.
if ( mOutput ) {
mOutput->write( mBuffer, bytesRead );
if ( mOutput->failed() ) {
DEBUG_PRINTF( PR_STDOUT, "%s %d: Error writing file, rv=0x%08X\n",
(char*)__FILE__, (int)__LINE__, (int)mOutput->error() );
#ifdef DEBUG_law
DEBUG_PRINTF( PR_STDOUT, "nsStreamXferOp::OnDataAvailable, offset=%d length=%d\n",
(int)offset, (int)aLength );
#endif
if ( mOutputStream ) {
// Write the data to the output stream.
// Read a buffer full till aLength bytes have been processed.
char buffer[ 8192 ];
unsigned long bytesRemaining = aLength;
while ( bytesRemaining ) {
unsigned int bytesRead;
// Read a buffer full or the number remaining (whichever is smaller).
rv = aIStream->Read( buffer,
PR_MIN( sizeof( buffer ),
bytesRemaining ),
&bytesRead );
if ( NS_SUCCEEDED( rv ) ) {
// Write the bytes just read to the output stream.
unsigned int bytesWritten;
rv = mOutputStream->Write( buffer, bytesRead, &bytesWritten );
if ( NS_SUCCEEDED( rv ) && bytesWritten == bytesRead ) {
// All bytes written OK.
bytesRemaining -= bytesWritten;
} else {
// Something is wrong.
if ( NS_SUCCEEDED( rv ) ) {
// Not all bytes were written for some strange reason.
rv = NS_ERROR_FAILURE;
}
this->OnError( kOpWrite, rv );
}
} else {
this->OnError( kOpRead, rv );
}
} else {
DEBUG_PRINTF( PR_STDOUT, "%s %d: Error reading stream, rv=0x%08X\n",
(char*)__FILE__, (int)__LINE__, (int)rv );
}
} else {
rv = NS_ERROR_NOT_INITIALIZED;
this->OnError( 0, rv );
}
if ( NS_FAILED( rv ) ) {
// Oh dear. close up shop.
this->Stop();
} else {
// Fake OnProgress.
mBytesProcessed += aLength;
if ( mContentLength == 0 && channel ) {
// Get content length from input channel.
channel->GetContentLength( &mContentLength );
}
this->OnProgress( mOutputChannel, 0, mBytesProcessed, mContentLength );
}
return rv;
}
// We aren't interested in this notification; simply return NS_OK.
// This is called when the input channel is successfully opened.
//
// We also open the output stream at this point.
NS_IMETHODIMP
nsStreamXferOp::OnStartRequest(nsIChannel* channel, nsISupports* aContext) {
nsresult rv = NS_OK;
#ifdef DEBUG_law
DEBUG_PRINTF( PR_STDOUT, "nsStreamXferOp::OnStartRequest; channel=0x%08X, context=0x%08X\n",
(int)(void*)channel, (int)(void*)aContext );
#endif
// Open output stream.
rv = mOutputChannel->OpenOutputStream( 0, getter_AddRefs( mOutputStream ) );
if ( NS_FAILED( rv ) ) {
// Give up all hope.
this->OnError( kOpOpenOutputStream, rv );
this->Stop();
}
return rv;
}
// As an event sink getter, we get ourself.
NS_IMETHODIMP
nsStreamXferOp::GetEventSink( const char *cmd, const nsIID &anIID, nsISupports **aResult ) {
return this->QueryInterface( anIID, (void**)aResult );
}
// Pass notification to our observer (if we have one). This object is the
// "subject", the topic is the component progid (plus ";onProgress"), and
// the data is the progress numbers (in the form "%lu %lu" where the first
// value is the number of bytes processed, the second the total number
// expected.
//
//XXX This function is not called at the moment because this object is not
// provided as the event sink by any event sink getter!
NS_IMETHODIMP
nsStreamXferOp::OnProgress(nsIChannel* channel, nsISupports* aContext,
PRUint32 aProgress, PRUint32 aProgressMax) {
@ -252,7 +340,7 @@ nsStreamXferOp::OnProgress(nsIChannel* channel, nsISupports* aContext,
if ( mObserver ) {
char buf[32];
PR_snprintf( buf, sizeof buf, "%lu %lu", (unsigned long)aProgress, (unsigned long)aProgressMax );
PR_snprintf( buf, sizeof buf, "%lu %ld", (unsigned long)aProgress, (long)aProgressMax );
rv = mObserver->Observe( (nsIStreamTransferOperation*)this,
nsString( NS_ISTREAMTRANSFER_PROGID ";onProgress" ).GetUnicode(),
nsString( buf ).GetUnicode() );
@ -288,8 +376,7 @@ nsStreamXferOp::OnStatus( nsIChannel *channel,
return rv;
}
// Close the output stream. In addition, notify our observer
// (if we have one).
// This is called when the end of input is reached on the input channel.
NS_IMETHODIMP
nsStreamXferOp::OnStopRequest( nsIChannel *channel,
nsISupports *aContext,
@ -297,12 +384,24 @@ nsStreamXferOp::OnStopRequest( nsIChannel *channel,
const PRUnichar *aMsg ) {
nsresult rv = NS_OK;
// Close the output file.
if ( mOutput ) {
mOutput->close();
#ifdef DEBUG_law
DEBUG_PRINTF( PR_STDOUT, "nsStreamXferOp::OnStopRequest notified of input completion, status=0x%08X\n",
(int)aStatus );
#endif
// Close the output stream.
if ( mOutputStream ) {
rv = mOutputStream->Close();
if ( NS_FAILED( rv ) ) {
this->OnError( kOpOutputClose, rv );
}
}
// Notify observer.
// Unhook input/output channels (don't need to cancel 'em).
mInputChannel = 0;
mOutputChannel = 0;
// Notify observer that the download is complete.
if ( mObserver ) {
nsString msg = aMsg;
rv = mObserver->Observe( (nsIStreamTransferOperation*)this,
@ -320,14 +419,12 @@ nsStreamXferOp::OnStopRequest( nsIChannel *channel,
// Attribute getters/setters...
NS_IMETHODIMP
nsStreamXferOp::GetSource( char**result ) {
nsStreamXferOp::GetSource( nsIChannel**result ) {
nsresult rv = NS_OK;
if ( result ) {
*result = mSource.ToNewCString();
if ( !*result ) {
rv = NS_ERROR_OUT_OF_MEMORY;
}
*result = mInputChannel;
NS_IF_ADDREF( *result );
} else {
rv = NS_ERROR_NULL_POINTER;
}
@ -336,14 +433,12 @@ nsStreamXferOp::GetSource( char**result ) {
}
NS_IMETHODIMP
nsStreamXferOp::GetTarget( char**result ) {
nsStreamXferOp::GetTarget( nsIFileSpec**result ) {
nsresult rv = NS_OK;
if ( result ) {
*result = mTarget.ToNewCString();
if ( !*result ) {
rv = NS_ERROR_OUT_OF_MEMORY;
}
*result = mOutputSpec;
NS_IF_ADDREF( *result );
} else {
rv = NS_ERROR_NULL_POINTER;
}
@ -390,11 +485,6 @@ nsStreamXferOp::QueryInterface( REFNSIID aIID, void** aInstancePtr ) {
// Always NULL result, in case of failure
*aInstancePtr = NULL;
if (aIID.Equals(nsCOMTypeInfo<nsIProgressEventSink>::GetIID())) {
*aInstancePtr = (void*) ((nsIProgressEventSink*)this);
NS_ADDREF_THIS();
return NS_OK;
}
if (aIID.Equals(nsCOMTypeInfo<nsISupports>::GetIID())) {
*aInstancePtr = (void*) ((nsIStreamObserver*)this);
NS_ADDREF_THIS();
@ -415,6 +505,16 @@ nsStreamXferOp::QueryInterface( REFNSIID aIID, void** aInstancePtr ) {
NS_ADDREF_THIS();
return NS_OK;
}
if (aIID.Equals(nsCOMTypeInfo<nsIProgressEventSink>::GetIID())) {
*aInstancePtr = (void*) ((nsIProgressEventSink*)this);
NS_ADDREF_THIS();
return NS_OK;
}
if (aIID.Equals(nsCOMTypeInfo<nsIEventSinkGetter>::GetIID())) {
*aInstancePtr = (void*) ((nsIEventSinkGetter*)this);
NS_ADDREF_THIS();
return NS_OK;
}
return NS_ERROR_NO_INTERFACE;
}

View File

@ -22,13 +22,16 @@
#ifndef __nsStreamXferOp_h
#define __nsStreamXferOp_h
#include "nsString.h"
#include "nsIStreamTransferOperation.h"
#include "nsIStreamListener.h"
#include "nsIEventSinkGetter.h"
#include "nsIProgressEventSink.h"
#include "nsIStreamListener.h"
#include "nsCOMPtr.h"
class nsIDOMWindow;
class nsOutputFileStream;
class nsIChannel;
class nsIFileSpec;
// Implementation of the stream transfer operation interface.
//
@ -37,21 +40,27 @@ class nsOutputFileStream;
// passed to a newly-created downloadProgress.xul dialog. That dialog "owns"
// the object (and the creator releases it immediately). The object's dtor
// should get called when the dialog closes.
//
class nsStreamXferOp : public nsIStreamTransferOperation,
public nsIEventSinkGetter,
public nsIProgressEventSink,
public nsIStreamListener {
public:
// ctor/dtor
nsStreamXferOp( const nsString &source, const nsString &target );
nsStreamXferOp( nsIChannel *source, nsIFileSpec *target );
virtual ~nsStreamXferOp();
// Implementation.
NS_IMETHOD OpenDialog( nsIDOMWindow *parent );
NS_IMETHOD OnError( int operation, nsresult rv );
// Declare inherited interfaces.
NS_DECL_ISUPPORTS
NS_DECL_NSISTREAMTRANSFEROPERATION
// nsIEventSinkGetter methods:
NS_DECL_NSIEVENTSINKGETTER
// nsIProgressEventSink methods:
NS_DECL_NSIPROGRESSEVENTSINK
@ -62,15 +71,14 @@ public:
NS_DECL_NSISTREAMLISTENER
private:
nsCString mSource;
nsCString mTarget;
nsIObserver *mObserver; // Not owned; owner should call SetObserver(0) prior
// to this object getting destroyed.
PRUint32 mBufLen;
char *mBuffer; // Owned; deleted in dtor.
PRBool mStopped;
nsOutputFileStream *mOutput; // Owned; deleted in dtor.
nsCOMPtr<nsIChannel> mInputChannel;
nsCOMPtr<nsIChannel> mOutputChannel;
nsCOMPtr<nsIOutputStream> mOutputStream;
nsCOMPtr<nsIFileSpec> mOutputSpec;
nsIObserver *mObserver; // Not owned; owner should call SetObserver(0) prior
// to this object getting destroyed.
int mContentLength;
unsigned long mBytesProcessed;
}; // nsStreamXferOp
#endif