Bug 854299 - Part 1. Split nsExternalAppHandler::SaveToDisk in two parts to make second part async. r=bz sr=roc

This commit is contained in:
Felipe Gomes 2013-04-01 03:07:13 -03:00
Родитель d71be8c99e
Коммит 91d91d3c58
5 изменённых файлов: 121 добавлений и 26 удалений

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

@ -189,6 +189,10 @@ nsUnknownContentTypeDialog.prototype = {
// Note - this function is called without a dialog, so it cannot access any part
// of the dialog XUL as other functions on this object do.
promptForSaveToFile: function(aLauncher, aContext, aDefaultFile, aSuggestedFileExtension, aForcePrompt) {
throw new Components.Exception("Async version must be used", Components.results.NS_ERROR_NOT_AVAILABLE);
},
promptForSaveToFileAsync: function(aLauncher, aContext, aDefaultFile, aSuggestedFileExtension, aForcePrompt) {
var result = null;
this.mLauncher = aLauncher;
@ -226,13 +230,16 @@ nsUnknownContentTypeDialog.prototype = {
bundle.GetStringFromName("badPermissions.title"),
bundle.GetStringFromName("badPermissions"));
aLauncher.saveDestinationAvailable(null);
return;
}
}
// Check to make sure we have a valid directory, otherwise, prompt
if (result)
return result;
if (result) {
aLauncher.saveDestinationAvailable(result);
return;
}
}
}
@ -283,7 +290,8 @@ nsUnknownContentTypeDialog.prototype = {
if (picker.show() == nsIFilePicker.returnCancel) {
// null result means user cancelled.
return null;
aLauncher.saveDestinationAvailable(null);
return;
}
// Be sure to save the directory the user chose through the Save As...
@ -307,7 +315,8 @@ nsUnknownContentTypeDialog.prototype = {
result = this.validateLeafName(newDir, result.leafName, null);
}
return result;
aLauncher.saveDestinationAvailable(result);
return;
},
/**

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

@ -1994,7 +1994,17 @@ nsresult nsExternalAppHandler::CreateProgressListener()
return rv;
}
nsresult nsExternalAppHandler::PromptForSaveToFile(nsIFile ** aNewFile, const nsAFlatString &aDefaultFile, const nsAFlatString &aFileExtension)
nsresult nsExternalAppHandler::SaveDestinationAvailable(nsIFile * aFile)
{
if (aFile)
ContinueSave(aFile);
else
Cancel(NS_BINDING_ABORTED);
return NS_OK;
}
void nsExternalAppHandler::RequestSaveDestination(const nsAFlatString &aDefaultFile, const nsAFlatString &aFileExtension)
{
// invoke the dialog!!!!! use mWindowContext as the window context parameter for the dialog request
// Convert to use file picker? No, then embeddors could not do any sort of
@ -2004,7 +2014,10 @@ nsresult nsExternalAppHandler::PromptForSaveToFile(nsIFile ** aNewFile, const ns
{
// Get helper app launcher dialog.
mDialog = do_CreateInstance( NS_HELPERAPPLAUNCHERDLG_CONTRACTID, &rv );
NS_ENSURE_SUCCESS(rv, rv);
if (rv != NS_OK) {
Cancel(NS_BINDING_ABORTED);
return;
}
}
// we want to explicitly unescape aDefaultFile b4 passing into the dialog. we can't unescape
@ -2015,14 +2028,25 @@ nsresult nsExternalAppHandler::PromptForSaveToFile(nsIFile ** aNewFile, const ns
// picker is up would cause Cancel() to be called, and the dialog would be
// released, which would release this object too, which would crash.
// See Bug 249143
nsIFile* fileToUse;
nsRefPtr<nsExternalAppHandler> kungFuDeathGrip(this);
nsCOMPtr<nsIHelperAppLauncherDialog> dlg(mDialog);
rv = mDialog->PromptForSaveToFile(this,
rv = mDialog->PromptForSaveToFile(this,
mWindowContext,
aDefaultFile.get(),
aFileExtension.get(),
mForceSave, aNewFile);
return rv;
mForceSave, &fileToUse);
if (rv == NS_ERROR_NOT_AVAILABLE) {
// we need to use the async version -> nsIHelperAppLauncherDialog.promptForSaveToFileAsync.
rv = mDialog->PromptForSaveToFileAsync(this,
mWindowContext,
aDefaultFile.get(),
aFileExtension.get(),
mForceSave);
} else {
SaveDestinationAvailable(rv == NS_OK ? fileToUse : nullptr);
}
}
nsresult nsExternalAppHandler::MoveFile(nsIFile * aNewFileLocation)
@ -2089,7 +2113,6 @@ nsresult nsExternalAppHandler::MoveFile(nsIFile * aNewFileLocation)
NS_IMETHODIMP nsExternalAppHandler::SaveToDisk(nsIFile * aNewFileLocation, bool aRememberThisPreference)
{
nsresult rv = NS_OK;
if (mCanceled)
return NS_OK;
@ -2098,11 +2121,9 @@ NS_IMETHODIMP nsExternalAppHandler::SaveToDisk(nsIFile * aNewFileLocation, bool
// The helper app dialog has told us what to do.
mReceivedDispositionInfo = true;
nsCOMPtr<nsIFile> fileToUse = do_QueryInterface(aNewFileLocation);
if (!fileToUse)
{
if (!aNewFileLocation) {
if (mSuggestedFileName.IsEmpty())
rv = PromptForSaveToFile(getter_AddRefs(fileToUse), mTempLeafName, mTempFileExtension);
RequestSaveDestination(mTempLeafName, mTempFileExtension);
else
{
nsAutoString fileExt;
@ -2112,15 +2133,20 @@ NS_IMETHODIMP nsExternalAppHandler::SaveToDisk(nsIFile * aNewFileLocation, bool
if (fileExt.IsEmpty())
fileExt = mTempFileExtension;
rv = PromptForSaveToFile(getter_AddRefs(fileToUse), mSuggestedFileName, fileExt);
}
if (NS_FAILED(rv) || !fileToUse) {
Cancel(NS_BINDING_ABORTED);
return NS_ERROR_FAILURE;
RequestSaveDestination(mSuggestedFileName, fileExt);
}
} else {
ContinueSave(aNewFileLocation);
}
return NS_OK;
}
nsresult nsExternalAppHandler::ContinueSave(nsIFile * aNewFileLocation)
{
NS_PRECONDITION(aNewFileLocation, "Must be called with a non-null file");
nsresult rv = NS_OK;
nsCOMPtr<nsIFile> fileToUse = do_QueryInterface(aNewFileLocation);
mFinalFileDestination = do_QueryInterface(fileToUse);
// Move what we have in the final directory, but append .part

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

@ -342,9 +342,34 @@ protected:
* what's going on...
*/
nsresult CreateProgressListener();
nsresult PromptForSaveToFile(nsIFile ** aNewFile,
const nsAFlatString &aDefaultFile,
const nsAFlatString &aDefaultFileExt);
/*
* The following two functions are part of the split of SaveToDisk
* to make it async, and works as following:
*
* SaveToDisk -------> RequestSaveDestination
* .
* .
* v
* ContinueSave <------- SaveDestinationAvailable
*/
/**
* This is called by SaveToDisk to decide what's the final
* file destination chosen by the user or by auto-download settings.
*/
void RequestSaveDestination(const nsAFlatString &aDefaultFile,
const nsAFlatString &aDefaultFileExt);
/**
* When SaveToDisk is called, it possibly delegates to RequestSaveDestination
* to decide the file destination. ContinueSave must then be called when
* the final destination is finally known.
* @param aFile The file that was chosen as the final destination.
* Must not be null.
*/
nsresult ContinueSave(nsIFile* aFile);
/**
* After we're done prompting the user for any information, if the original

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

@ -76,7 +76,7 @@ interface nsPIExternalAppLauncher : nsISupports
* Note that cancelling the load via the nsICancelable interface will release
* the reference to the launcher dialog.
*/
[scriptable, uuid(d9a19faf-497b-408c-b995-777d956b72c0)]
[scriptable, uuid(acf2a516-7d7f-4771-8b22-6c4a559c088e)]
interface nsIHelperAppLauncher : nsICancelable
{
/**
@ -110,6 +110,13 @@ interface nsIHelperAppLauncher : nsICancelable
*/
void launchWithApplication(in nsIFile aApplication, in boolean aRememberThisPreference);
/**
* Callback invoked by nsIHelperAppLauncherDialog::promptForSaveToFileAsync
* after the user has chosen a file through the File Picker (or dismissed it).
* @param aFile The file that was chosen by the user (or null if dialog was dismissed).
*/
void saveDestinationAvailable(in nsIFile aFile);
/**
* The following methods are used by the progress dialog to get or set
* information on the current helper app launcher download.

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

@ -21,7 +21,7 @@ interface nsIFile;
* will access methods of the nsIHelperAppLauncher passed in to show()
* in order to cause a "save to disk" or "open using" action.
*/
[scriptable, uuid(f3704fdc-8ae6-4eba-a3c3-f02958ac0649)]
[scriptable, uuid(3ae4dca8-ac91-4891-adcf-3fbebed6170e)]
interface nsIHelperAppLauncherDialog : nsISupports {
/**
* This request is passed to the helper app dialog because Gecko can not
@ -73,12 +73,40 @@ interface nsIHelperAppLauncherDialog : nsISupports {
* Set to true to force prompting the user for thet file
* name/location, otherwise perferences may control if the user is
* prompted.
*
* @throws NS_ERROR_NOT_AVAILABLE if the async version of this function
* should be used.
*/
nsIFile promptForSaveToFile(in nsIHelperAppLauncher aLauncher,
in nsISupports aWindowContext,
in wstring aDefaultFileName,
in wstring aSuggestedFileExtension,
in boolean aForcePrompt);
/**
* Async invoke a save-to-file dialog instead of the full fledged helper app
* dialog. When the file is chosen (or the dialog is closed), the callback
* in aLauncher (aLauncher.saveDestinationAvailable) is called with the
* selected file.
*
* @param aLauncher
* A nsIHelperAppLauncher to be invoked when a file is selected.
* @param aWindowContext
* Window associated with action.
* @param aDefaultFileName
* Default file name to provide (can be null)
* @param aSuggestedFileExtension
* Sugested file extension
* @param aForcePrompt
* Set to true to force prompting the user for thet file
* name/location, otherwise perferences may control if the user is
* prompted.
*/
void promptForSaveToFileAsync(in nsIHelperAppLauncher aLauncher,
in nsISupports aWindowContext,
in wstring aDefaultFileName,
in wstring aSuggestedFileExtension,
in boolean aForcePrompt);
};