Bug #51018, 44176, 47203 implement load group retargeting and stand alone progress window

after we show the helper app dialog. So progress and load information is
now retargeted to a stand alone window instead of re-using the underlying
 browser / mail window...In order to do this, the external app handler needed to implement nsIURIContentListener.
sr=r=rpotts
This commit is contained in:
mscott%netscape.com 2000-10-04 06:54:47 +00:00
parent 7cb10d986d
commit c054dd3653
5 changed files with 251 additions and 13 deletions

View File

@ -109,16 +109,16 @@ NS_IMETHODIMP nsOSHelperAppService::DoContent(const char *aMimeContentType, nsIU
// first, try to see if we can find the content based on just the specified content type...
nsCOMPtr<nsIMIMEInfo> mimeInfo;
rv = GetFromMIMEType(aMimeContentType, getter_AddRefs(mimeInfo));
if (NS_FAILED(rv) || !mimeInfo)
// if we didn't find a match OR if the extesnion is a .bin, then use internet config...
if (NS_FAILED(rv) || !mimeInfo || strcmp(aMimeContentType, APPLICATION_OCTET_STREAM) == 0)
{
// if the content based search failed, then try looking up based on the file extension....
if (url)
{
nsXPIDLCString extension;
url->GetFileExtension(getter_Copies(extension));
const char * ext = (const char *) extension;
if (ext && *ext)
rv = GetFromExtension(ext, getter_AddRefs(mimeInfo));
if (extension)
rv = GetFromExtension(extension, getter_AddRefs(mimeInfo));
}
}

View File

@ -31,6 +31,10 @@
#include "nsMemory.h"
#include "nsIStreamListener.h"
#include "nsIMIMEService.h"
#include "nsILoadGroup.h"
#include "nsCURILoader.h"
#include "nsIWebProgress.h"
#include "nsIWebProgressListener.h"
// used to manage our in memory data source of helper applications
#include "nsRDFCID.h"
@ -68,6 +72,8 @@ static nsDefaultMimeTypeEntry defaultMimeEntries [] =
{ TEXT_PLAIN, "txt,text", "Text File", 'TEXT', 'ttxt' },
#if defined(VMS)
{ APPLICATION_OCTET_STREAM, "exe,bin,sav,bck,pcsi,dcx_axpexe,dcx_vaxexe,sfx_axpexe,sfx_vaxexe", "Binary Executable", PRUint32(0x3F3F3F3F), PRUint32(0x3F3F3F3F) },
#elif defined(XP_MAC) // don't define .bin on the mac...use internet config to look that up...
{ APPLICATION_OCTET_STREAM, "exe", "Binary Executable", PRUint32(0x3F3F3F3F), PRUint32(0x3F3F3F3F) },
#else
{ APPLICATION_OCTET_STREAM, "exe,bin", "Binary Executable", PRUint32(0x3F3F3F3F), PRUint32(0x3F3F3F3F) },
#endif
@ -462,6 +468,8 @@ NS_INTERFACE_MAP_BEGIN(nsExternalAppHandler)
NS_INTERFACE_MAP_ENTRY(nsIStreamListener)
NS_INTERFACE_MAP_ENTRY(nsIStreamObserver)
NS_INTERFACE_MAP_ENTRY(nsIHelperAppLauncher)
NS_INTERFACE_MAP_ENTRY(nsIURIContentListener)
NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
NS_INTERFACE_MAP_END_THREADSAFE
nsExternalAppHandler::nsExternalAppHandler()
@ -479,6 +487,64 @@ nsExternalAppHandler::~nsExternalAppHandler()
nsMemory::Free(mDataBuffer);
}
NS_IMETHODIMP nsExternalAppHandler::GetInterface(const nsIID & aIID, void * *aInstancePtr)
{
NS_ENSURE_ARG_POINTER(aInstancePtr);
return QueryInterface(aIID, aInstancePtr);
}
NS_IMETHODIMP nsExternalAppHandler::SetWebProgressListener(nsIWebProgressListener * aWebProgressListener)
{
if (mLoadCookie)
{
nsCOMPtr<nsIWebProgress> webProgress(do_QueryInterface(mLoadCookie));
if (webProgress)
{
mWebProgressListener = aWebProgressListener;
webProgress->AddProgressListener(mWebProgressListener);
}
}
return NS_OK;
}
NS_IMETHODIMP nsExternalAppHandler::GetDownloadInfo(nsIURI ** aSourceUrl, nsIFile ** aTarget)
{
if (mFinalFileDestination)
{
*aTarget = mFinalFileDestination;
}
else
*aTarget = mTempFile;
NS_IF_ADDREF(*aTarget);
*aSourceUrl = mSourceUrl;
NS_IF_ADDREF(*aSourceUrl);
return NS_OK;
}
NS_IMETHODIMP nsExternalAppHandler::CloseProgressWindow()
{
// make our docloader release the progress listener from the progress window...
if (mLoadCookie && mWebProgressListener)
{
nsCOMPtr<nsIWebProgress> webProgress(do_QueryInterface(mLoadCookie));
if (webProgress)
{
webProgress->RemoveProgressListener(mWebProgressListener);
}
}
// release extra state...
mWebProgressListener = nsnull;
mLoadCookie = nsnull;
return NS_OK;
}
void nsExternalAppHandler::ExtractSuggestedFileNameFromChannel(nsIChannel * aChannel)
{
// if the channel is an http channel and we have a content disposition header set,
@ -512,7 +578,7 @@ void nsExternalAppHandler::ExtractSuggestedFileNameFromChannel(nsIChannel * aCha
dispFileName.Truncate(pos);
// ONLY if we got here, will we remember the suggested file name...
mHTTPSuggestedFileName.AssignWithConversion(dispFileName);
mSuggestedFileName.AssignWithConversion(dispFileName);
}
} // if we found a file name in the header disposition field
} // we had a disp header
@ -520,6 +586,31 @@ void nsExternalAppHandler::ExtractSuggestedFileNameFromChannel(nsIChannel * aCha
} // if we had an http channel
}
nsresult nsExternalAppHandler::RetargetLoadNotifications(nsIChannel * aChannel)
{
// we are going to run the downloading of the helper app in our own little docloader / load group context.
// so go ahead and force the creation of a load group and doc loader for us to use...
nsresult rv = NS_OK;
nsCOMPtr<nsIURILoader> uriLoader(do_GetService(NS_URI_LOADER_CONTRACTID));
NS_ENSURE_TRUE(uriLoader, NS_ERROR_FAILURE);
nsCOMPtr<nsILoadGroup> newLoadGroup;
nsCOMPtr<nsILoadGroup> oldLoadGroup;
uriLoader->GetLoadGroupForContext(NS_STATIC_CAST(nsIURIContentListener*, this), getter_AddRefs(newLoadGroup));
aChannel->GetLoadGroup(getter_AddRefs(oldLoadGroup));
if(oldLoadGroup)
oldLoadGroup->RemoveChannel(aChannel, nsnull, NS_OK, nsnull);
aChannel->SetLoadGroup(newLoadGroup);
nsCOMPtr<nsIInterfaceRequestor> req (do_QueryInterface(mLoadCookie));
aChannel->SetNotificationCallbacks(req);
rv = newLoadGroup->AddChannel(aChannel, nsnull);
return rv;
}
nsresult nsExternalAppHandler::SetUpTempFile(nsIChannel * aChannel)
{
nsresult rv = NS_OK;
@ -547,8 +638,8 @@ nsresult nsExternalAppHandler::SetUpTempFile(nsIChannel * aChannel)
#endif
nsCOMPtr<nsIURI> uri;
aChannel->GetURI(getter_AddRefs(uri));
nsCOMPtr<nsIURL> url = do_QueryInterface(uri);
aChannel->GetURI(getter_AddRefs(mSourceUrl));
nsCOMPtr<nsIURL> url = do_QueryInterface(mSourceUrl);
nsCAutoString tempLeafName;
@ -561,6 +652,12 @@ nsresult nsExternalAppHandler::SetUpTempFile(nsIChannel * aChannel)
if (leafName)
{
tempLeafName = leafName;
// store the file name in the url so we can present it as a "suggested" file name when
// we prompt the user...
if (!tempLeafName.IsEmpty())
mSuggestedFileName.AssignWithConversion(tempLeafName);
// strip off whatever extension this file may have and force our own extension.
PRInt32 pos = tempLeafName.RFindCharInSet(".");
if (pos > 0)
@ -598,6 +695,9 @@ NS_IMETHODIMP nsExternalAppHandler::OnStartRequest(nsIChannel * aChannel, nsISup
return aChannel->Cancel(NS_BINDING_ABORTED);
nsresult rv = SetUpTempFile(aChannel);
// retarget all load notifcations to our docloader instead of the original window's docloader...
RetargetLoadNotifications(aChannel);
// ignore failure...
ExtractSuggestedFileNameFromChannel(aChannel);
// now that the temp file is set up, find out if we need to invoke a dialog asking the user what
@ -698,6 +798,7 @@ nsresult nsExternalAppHandler::Init(nsIMIMEInfo * aMIMEInfo, const char * aTempF
if (aTempFileExtension && *aTempFileExtension != '.')
mTempFileExtension = ".";
mTempFileExtension.Append(aTempFileExtension);
return NS_OK;
}
@ -708,6 +809,18 @@ NS_IMETHODIMP nsExternalAppHandler::GetMIMEInfo(nsIMIMEInfo ** aMIMEInfo)
return NS_OK;
}
nsresult nsExternalAppHandler::ShowProgressDialog()
{
// we are back from the helper app dialog (where the user chooses to save or open), but we aren't
// done processing the load. in this case, throw up a progress dialog so the user can see what's going on...
nsresult rv = NS_OK;
nsCOMPtr<nsIHelperAppLauncherDialog> dlgService( do_GetService(NS_IHELPERAPPLAUNCHERDLG_CONTRACTID, &rv));
if ( dlgService )
dlgService->ShowProgressDialog(this, mWindowContext);
return rv;
}
nsresult nsExternalAppHandler::PromptForSaveToFile(nsILocalFile ** aNewFile, const PRUnichar * aDefaultFile)
{
// invoke the dialog!!!!! use mWindowContext as the window context parameter for the dialog service
@ -715,7 +828,7 @@ nsresult nsExternalAppHandler::PromptForSaveToFile(nsILocalFile ** aNewFile, con
nsresult rv = NS_OK;
if ( dlgService )
rv = dlgService->PromptForSaveToFile(mWindowContext, aDefaultFile, NS_ConvertASCIItoUCS2(mTempFileExtension).get(), aNewFile);
return rv;
}
@ -730,10 +843,10 @@ NS_IMETHODIMP nsExternalAppHandler::SaveToDisk(nsIFile * aNewFileLocation, PRBoo
{
nsXPIDLString leafName;
mTempFile->GetUnicodeLeafName(getter_Copies(leafName));
if (mHTTPSuggestedFileName.IsEmpty())
if (mSuggestedFileName.IsEmpty())
rv = PromptForSaveToFile(getter_AddRefs(fileToUse), leafName);
else
rv = PromptForSaveToFile(getter_AddRefs(fileToUse), mHTTPSuggestedFileName.GetUnicode());
rv = PromptForSaveToFile(getter_AddRefs(fileToUse), mSuggestedFileName.GetUnicode());
if (NS_FAILED(rv))
return Cancel();
@ -743,6 +856,7 @@ NS_IMETHODIMP nsExternalAppHandler::SaveToDisk(nsIFile * aNewFileLocation, PRBoo
fileToUse = do_QueryInterface(aNewFileLocation);
mReceivedDispostionInfo = PR_TRUE;
// if the on stop request was actually issued then it's now time to actually perform the file move....
if (mStopRequestIssued && fileToUse)
{
@ -756,6 +870,10 @@ NS_IMETHODIMP nsExternalAppHandler::SaveToDisk(nsIFile * aNewFileLocation, PRBoo
rv = mTempFile->MoveTo(directoryLocation, fileName);
}
}
else
{
ShowProgressDialog();
}
return rv;
}
@ -779,6 +897,10 @@ NS_IMETHODIMP nsExternalAppHandler::LaunchWithApplication(nsIFile * aApplication
rv = helperAppService->LaunchAppWithTempFile(mMimeInfo, mTempFile);
}
}
else
{
ShowProgressDialog();
}
return NS_OK;
}
@ -799,6 +921,69 @@ NS_IMETHODIMP nsExternalAppHandler::Cancel()
mTempFile->Delete(PR_TRUE);
mTempFile = nsnull;
}
return NS_OK;
}
// nsIURIContentListener implementation
NS_IMETHODIMP nsExternalAppHandler::OnStartURIOpen(nsIURI* aURI, const char* aWindowTarget, PRBool* aAbortOpen)
{
return NS_OK;
}
NS_IMETHODIMP nsExternalAppHandler::GetProtocolHandler(nsIURI *aURI, nsIProtocolHandler **aProtocolHandler)
{
*aProtocolHandler = nsnull;
return NS_OK;
}
NS_IMETHODIMP nsExternalAppHandler::IsPreferred(const char * aContentType, nsURILoadCommand aCommand, const char * aWindowTarget,
char ** aDesiredContentType, PRBool * aCanHandleContent)
{
NS_NOTREACHED("IsPreferred");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP nsExternalAppHandler::CanHandleContent(const char * aContentType, nsURILoadCommand aCommand,
const char * aWindowTarget, char ** aDesiredContentType,
PRBool * aCanHandleContent)
{
NS_NOTREACHED("CanHandleContent");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP nsExternalAppHandler::DoContent(const char * aContentType, nsURILoadCommand aCommand, const char * aWindowTarget,
nsIChannel * aOpenedChannel,
nsIStreamListener ** aContentHandler,PRBool * aAbortProcess)
{
NS_NOTREACHED("DoContent");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP nsExternalAppHandler::GetParentContentListener(nsIURIContentListener** aParent)
{
*aParent = nsnull;
return NS_OK;
}
NS_IMETHODIMP nsExternalAppHandler::SetParentContentListener(nsIURIContentListener* aParent)
{
return NS_OK;
}
NS_IMETHODIMP nsExternalAppHandler::GetLoadCookie(nsISupports ** aLoadCookie)
{
*aLoadCookie = mLoadCookie;
NS_IF_ADDREF(*aLoadCookie);
return NS_OK;
}
NS_IMETHODIMP nsExternalAppHandler::SetLoadCookie(nsISupports * aLoadCookie)
{
mLoadCookie = aLoadCookie;
return NS_OK;
}

View File

@ -25,6 +25,8 @@
#include "nsIExternalHelperAppService.h"
#include "nsIExternalProtocolService.h"
#include "nsIURIContentListener.h"
#include "nsIWebProgressListener.h"
#include "nsIMIMEInfo.h"
#include "nsIMIMEService.h"
@ -129,13 +131,16 @@ struct nsDefaultMimeTypeEntry {
// to write the data into the output stream representing the temp file...
#define DATA_BUFFER_SIZE (4096*2)
class nsExternalAppHandler : public nsIStreamListener, public nsIHelperAppLauncher
class nsExternalAppHandler : public nsIStreamListener, public nsIHelperAppLauncher, public nsIURIContentListener,
public nsIInterfaceRequestor
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSISTREAMLISTENER
NS_DECL_NSISTREAMOBSERVER
NS_DECL_NSIHELPERAPPLAUNCHER
NS_DECL_NSIURICONTENTLISTENER
NS_DECL_NSIINTERFACEREQUESTOR
nsExternalAppHandler();
virtual ~nsExternalAppHandler();
@ -144,13 +149,14 @@ public:
protected:
nsCOMPtr<nsIFile> mTempFile;
nsCOMPtr<nsIURI> mSourceUrl;
nsCString mTempFileExtension;
nsCOMPtr<nsIMIMEInfo> mMimeInfo;
nsCOMPtr<nsIOutputStream> mOutStream; // output stream to the temp file...
nsCOMPtr<nsISupports> mWindowContext;
// the following field is set if we were processing an http channel that had a content disposition header
// which specified the SUGGESTED file name we should present to the user in the save to disk dialog.
nsString mHTTPSuggestedFileName;
nsString mSuggestedFileName;
// the canceled flag is set if the user canceled the launching of this application before we finished
// saving the data to a temp file...
@ -168,10 +174,20 @@ protected:
char * mDataBuffer;
nsresult SetUpTempFile(nsIChannel * aChannel);
// when we download a helper app, we are going to retarget all load notifications into our own docloader
// and load group instead of using the window which initiated the load....RetargetLoadNotifications contains
// that information...
nsresult RetargetLoadNotifications(nsIChannel * aChannel);
// if the user tells us how they want to dispose of the content and we still haven't finished downloading while
// they were deciding, then throw a progress dialog so they know what's going on...
nsresult ShowProgressDialog();
nsresult PromptForSaveToFile(nsILocalFile ** aNewFile, const PRUnichar * aDefaultFile);
// if the passed in channel is an nsIHTTPChannel, we'll attempt to extrace a suggested file name
// if the passed in channel is an nsIHTTPChannel, we'll attempt to extract a suggested file name
// from the content disposition header...
void ExtractSuggestedFileNameFromChannel(nsIChannel * aChannel);
nsCOMPtr<nsISupports> mLoadCookie; // load cookie used by the uri loader when we fetch the url
nsCOMPtr<nsIWebProgressListener> mWebProgressListener;
};
#endif // nsExternalHelperAppService_h__

View File

@ -30,6 +30,7 @@ interface nsIURI;
interface nsIStreamListener;
interface nsIFile;
interface nsIMIMEInfo;
interface nsIWebProgressListener;
[scriptable, uuid(663CC0AA-42EA-11d4-98D0-001083010E9B)]
@ -86,4 +87,15 @@ interface nsIHelperAppLauncher : nsISupports
// called if the user decides to cancel the handling of this content type
void Cancel();
// the following methods are used by the progress dialog to get or set information
// on the current helper app launcher download
void setWebProgressListener(in nsIWebProgressListener aWebProgressListener);
// when the stand along progress window actually closes, it calls this method
// so we can release any local state...
void closeProgressWindow();
// aSourceUrl--> the url we are downloading....and the file we are saving too
nsIFile getDownloadInfo(out nsIURI aSourceUrl);
};

View File

@ -65,7 +65,32 @@ NS_IMETHODIMP nsOSHelperAppService::DoContent(const char *aMimeContentType, nsIU
if (NS_SUCCEEDED(rv)) return NS_OK;
// there is no registry on linux (like there is on win32)
// so we can only make up a dummy mime type for this content....
nsCOMPtr<nsIMIMEInfo> mimeInfo (do_CreateInstance(NS_MIMEINFO_CONTRACTID));
nsCAutoString fileExtension;
*aStreamListener = nsnull;
if (aURI)
{
nsCOMPtr<nsIURL> url = do_QueryInterface(aURI);
nsXPIDLCString extenion;
url->GetFileExtension(getter_Copies(extenion));
fileExtension = ".";
fileExtension.Append(extenion);
}
if (mimeInfo)
{
if (!fileExtension.IsEmpty())
mimeInfo->SetFileExtensions(fileExtension);
mimeInfo->SetMIMEType(aMimeContentType);
// this code is incomplete and just here to get things started..
nsExternalAppHandler * handler = CreateNewExternalHandler(mimeInfo, fileExtension, aWindowContext);
handler->QueryInterface(NS_GET_IID(nsIStreamListener), (void **) aStreamListener);
}
return NS_OK;
}