Checking in Boris Zbarsky's <bzbarsky@mit.edu> fix for bug 117269. Making mozilla not invent silly file extensions when saving files. r=law@netscape.com, rs=jaggernaut@netscape.com, jst@netscape.com
This commit is contained in:
Родитель
5d4df6629c
Коммит
8fd2822bf1
|
@ -126,6 +126,15 @@ nsHelperAppDialog.prototype = {
|
|||
.getInterface( Components.interfaces.nsIDOMWindowInternal );
|
||||
picker.init( parent, windowTitle, nsIFilePicker.modeSave );
|
||||
picker.defaultString = aDefaultFile;
|
||||
if (aSuggestedFileExtension) {
|
||||
// aSuggestedFileExtension includes the period, so strip it
|
||||
picker.defaultExtension = aSuggestedFileExtension.substring(1);
|
||||
} else {
|
||||
try {
|
||||
picker.defaultExtension = this.mLauncher.MIMEInfo.primaryExtension;
|
||||
} catch (ex) {
|
||||
}
|
||||
}
|
||||
|
||||
var wildCardExtension = "*";
|
||||
if ( aSuggestedFileExtension ) {
|
||||
|
|
|
@ -93,7 +93,7 @@ static PRBool PR_CALLBACK DeleteEntry(nsHashKey *aKey, void *aData, void* closur
|
|||
static nsDefaultMimeTypeEntry defaultMimeEntries [] =
|
||||
{
|
||||
{ TEXT_PLAIN, "txt,text", "Text File", 'TEXT', 'ttxt' },
|
||||
{ TEXT_HTML, "htm,html,shtml,ehtml", "HyperText Markup Language", 'TEXT', 'MOSS' },
|
||||
{ TEXT_HTML, "html,htm,shtml,ehtml", "HyperText Markup Language", 'TEXT', 'MOSS' },
|
||||
{ TEXT_RDF, "rdf", "Resource Description Framework", 'TEXT','ttxt' },
|
||||
{ TEXT_XUL, "xul", "XML-Based User Interface Language", 'TEXT', 'ttxt' },
|
||||
{ TEXT_XML, "xml,xsl,xbl", "Extensible Markup Language", 'TEXT', 'ttxt' },
|
||||
|
|
|
@ -73,9 +73,20 @@ interface nsIFilePicker : nsISupports
|
|||
void appendFilter(in wstring title,
|
||||
in wstring filter);
|
||||
|
||||
/* what is this? */
|
||||
/**
|
||||
* The filename that should be suggested to the user as a default.
|
||||
*
|
||||
* @throws NS_ERROR_FAILURE on attempts to get
|
||||
*/
|
||||
attribute wstring defaultString;
|
||||
|
||||
/**
|
||||
* The extension that should be associated with files of the type we
|
||||
* want to work with. On some platforms, this extension will be
|
||||
* automatically appended to filenames the user enters, if needed.
|
||||
*/
|
||||
attribute wstring defaultExtension;
|
||||
|
||||
/**
|
||||
* The filter which is currently selected in the File Picker dialog
|
||||
*
|
||||
|
|
|
@ -257,6 +257,22 @@ NS_IMETHODIMP nsFilePicker::GetDefaultString(PRUnichar **aString)
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
//
|
||||
// The default extension to use for files
|
||||
//
|
||||
//-------------------------------------------------------------------------
|
||||
NS_IMETHODIMP nsFilePicker::GetDefaultExtension(PRUnichar **aExtension)
|
||||
{
|
||||
*aExtension = nsnull;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsFilePicker::SetDefaultExtension(const PRUnichar *aExtension)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
//
|
||||
// Set the display directory
|
||||
|
|
|
@ -50,6 +50,8 @@ public:
|
|||
// nsIFilePicker (less what's in nsBaseFilePicker)
|
||||
NS_IMETHOD GetDefaultString(PRUnichar * *aDefaultString);
|
||||
NS_IMETHOD SetDefaultString(const PRUnichar * aDefaultString);
|
||||
NS_IMETHOD GetDefaultExtension(PRUnichar * *aDefaultExtension);
|
||||
NS_IMETHOD SetDefaultExtension(const PRUnichar * aDefaultExtension);
|
||||
NS_IMETHOD GetDisplayDirectory(nsILocalFile * *aDisplayDirectory);
|
||||
NS_IMETHOD SetDisplayDirectory(nsILocalFile * aDisplayDirectory);
|
||||
NS_IMETHOD GetFile(nsILocalFile * *aFile);
|
||||
|
|
|
@ -699,6 +699,22 @@ NS_IMETHODIMP nsFilePicker::GetDefaultString(PRUnichar **aString)
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
//
|
||||
// The default extension to use for files
|
||||
//
|
||||
//-------------------------------------------------------------------------
|
||||
NS_IMETHODIMP nsFilePicker::GetDefaultExtension(PRUnichar **aExtension)
|
||||
{
|
||||
*aExtension = nsnull;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsFilePicker::SetDefaultExtension(const PRUnichar *aExtension)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
//
|
||||
// Set the display directory
|
||||
|
|
|
@ -48,6 +48,8 @@ public:
|
|||
// nsIFilePicker (less what's in nsBaseFilePicker)
|
||||
NS_IMETHOD GetDefaultString(PRUnichar * *aDefaultString);
|
||||
NS_IMETHOD SetDefaultString(const PRUnichar * aDefaultString);
|
||||
NS_IMETHOD GetDefaultExtension(PRUnichar * *aDefaultExtension);
|
||||
NS_IMETHOD SetDefaultExtension(const PRUnichar * aDefaultExtension);
|
||||
NS_IMETHOD GetDisplayDirectory(nsILocalFile * *aDisplayDirectory);
|
||||
NS_IMETHOD SetDisplayDirectory(nsILocalFile * aDisplayDirectory);
|
||||
NS_IMETHOD GetFile(nsILocalFile * *aFile);
|
||||
|
|
|
@ -932,6 +932,22 @@ NS_IMETHODIMP nsFilePicker::GetDefaultString(PRUnichar **aString)
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
//
|
||||
// The default extension to use for files
|
||||
//
|
||||
//-------------------------------------------------------------------------
|
||||
NS_IMETHODIMP nsFilePicker::GetDefaultExtension(PRUnichar **aExtension)
|
||||
{
|
||||
*aExtension = nsnull;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsFilePicker::SetDefaultExtension(const PRUnichar *aExtension)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
//
|
||||
// Set the display directory
|
||||
|
|
|
@ -48,6 +48,8 @@ public:
|
|||
// nsIFilePicker (less what's in nsBaseFilePicker)
|
||||
NS_IMETHOD GetDefaultString(PRUnichar * *aDefaultString);
|
||||
NS_IMETHOD SetDefaultString(const PRUnichar * aDefaultString);
|
||||
NS_IMETHOD GetDefaultExtension(PRUnichar * *aDefaultExtension);
|
||||
NS_IMETHOD SetDefaultExtension(const PRUnichar * aDefaultExtension);
|
||||
NS_IMETHOD GetDisplayDirectory(nsILocalFile * *aDisplayDirectory);
|
||||
NS_IMETHOD SetDisplayDirectory(nsILocalFile * aDisplayDirectory);
|
||||
NS_IMETHOD GetFile(nsILocalFile * *aFile);
|
||||
|
|
|
@ -325,6 +325,22 @@ NS_IMETHODIMP nsFilePicker::GetDefaultString(PRUnichar **aString)
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
//
|
||||
// The default extension to use for files
|
||||
//
|
||||
//-------------------------------------------------------------------------
|
||||
NS_IMETHODIMP nsFilePicker::GetDefaultExtension(PRUnichar **aExtension)
|
||||
{
|
||||
*aExtension = nsnull;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsFilePicker::SetDefaultExtension(const PRUnichar *aExtension)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
//
|
||||
// Set the display directory
|
||||
|
|
|
@ -47,6 +47,8 @@ public:
|
|||
// nsIFilePicker (less what's in nsBaseFilePicker)
|
||||
NS_IMETHOD GetDefaultString(PRUnichar * *aDefaultString);
|
||||
NS_IMETHOD SetDefaultString(const PRUnichar * aDefaultString);
|
||||
NS_IMETHOD GetDefaultExtension(PRUnichar * *aDefaultExtension);
|
||||
NS_IMETHOD SetDefaultExtension(const PRUnichar * aDefaultExtension);
|
||||
NS_IMETHOD GetDisplayDirectory(nsILocalFile * *aDisplayDirectory);
|
||||
NS_IMETHOD SetDisplayDirectory(nsILocalFile * aDisplayDirectory);
|
||||
NS_IMETHOD GetFile(nsILocalFile * *aFile);
|
||||
|
|
|
@ -44,6 +44,8 @@ NS_IMPL_ISUPPORTS1(nsFilePicker, nsIFilePicker)
|
|||
|
||||
char nsFilePicker::mLastUsedDirectory[MAX_PATH+1] = { 0 };
|
||||
|
||||
#define MAX_EXTENSION_LENGTH 10
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
//
|
||||
// nsFilePicker constructor
|
||||
|
@ -147,6 +149,8 @@ NS_IMETHODIMP nsFilePicker::Show(PRInt16 *retval)
|
|||
|
||||
ofn.lStructSize = sizeof(ofn);
|
||||
|
||||
char extensionBuffer[MAX_EXTENSION_LENGTH+1] = "";
|
||||
|
||||
PRInt32 l = (mFilterList.Length()+2)*2;
|
||||
char *filterBuffer = (char*) nsMemory::Alloc(l);
|
||||
int len = WideCharToMultiByte(CP_ACP, 0,
|
||||
|
@ -160,7 +164,7 @@ NS_IMETHODIMP nsFilePicker::Show(PRInt16 *retval)
|
|||
if (initialDir && *initialDir) {
|
||||
ofn.lpstrInitialDir = initialDir;
|
||||
}
|
||||
|
||||
|
||||
ofn.lpstrTitle = title;
|
||||
ofn.lpstrFilter = filterBuffer;
|
||||
ofn.nFilterIndex = mSelectedType;
|
||||
|
@ -170,24 +174,38 @@ NS_IMETHODIMP nsFilePicker::Show(PRInt16 *retval)
|
|||
|
||||
ofn.Flags = OFN_NOCHANGEDIR | OFN_SHAREAWARE | OFN_LONGNAMES | OFN_OVERWRITEPROMPT | OFN_HIDEREADONLY;
|
||||
|
||||
// Get file extension from suggested filename
|
||||
// to detect if we are saving an html file
|
||||
//XXX: nsIFile SHOULD HAVE A GetExtension() METHOD!
|
||||
PRInt32 extIndex = mDefault.RFind(".");
|
||||
if ( extIndex >= 0) {
|
||||
nsAutoString ext;
|
||||
mDefault.Right(ext, mDefault.Length() - extIndex);
|
||||
// Should we test for ".cgi", ".asp", ".jsp" and other
|
||||
// "generated" html pages?
|
||||
if (!mDefaultExtension.IsEmpty()) {
|
||||
// Someone was cool and told us what to do
|
||||
char *convertedExt = ConvertToFileSystemCharset(mDefaultExtension.get());
|
||||
if (!convertedExt) {
|
||||
mDefaultExtension.ToCString(extensionBuffer, MAX_EXTENSION_LENGTH);
|
||||
}
|
||||
else {
|
||||
PL_strncpyz(extensionBuffer, convertedExt, MAX_EXTENSION_LENGTH+1);
|
||||
nsMemory::Free( convertedExt );
|
||||
}
|
||||
ofn.lpstrDefExt = extensionBuffer;
|
||||
}
|
||||
else {
|
||||
// Get file extension from suggested filename
|
||||
// to detect if we are saving an html file
|
||||
//XXX: nsIFile SHOULD HAVE A GetExtension() METHOD!
|
||||
PRInt32 extIndex = mDefault.RFind(".");
|
||||
if ( extIndex >= 0) {
|
||||
nsAutoString ext;
|
||||
mDefault.Right(ext, mDefault.Length() - extIndex);
|
||||
// Should we test for ".cgi", ".asp", ".jsp" and other
|
||||
// "generated" html pages?
|
||||
|
||||
if ( ext.EqualsIgnoreCase(".htm") ||
|
||||
ext.EqualsIgnoreCase(".html") ||
|
||||
ext.EqualsIgnoreCase(".shtml") ) {
|
||||
// This is supposed to append ".htm" if user doesn't supply an extension
|
||||
//XXX Actually, behavior is sort of weird:
|
||||
// often appends ".html" even if you have an extension
|
||||
// It obeys your extension if you put quotes around name
|
||||
ofn.lpstrDefExt = htmExt;
|
||||
if ( ext.EqualsIgnoreCase(".htm") ||
|
||||
ext.EqualsIgnoreCase(".html") ||
|
||||
ext.EqualsIgnoreCase(".shtml") ) {
|
||||
// This is supposed to append ".htm" if user doesn't supply an extension
|
||||
//XXX Actually, behavior is sort of weird:
|
||||
// often appends ".html" even if you have an extension
|
||||
// It obeys your extension if you put quotes around name
|
||||
ofn.lpstrDefExt = htmExt;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -355,6 +373,25 @@ NS_IMETHODIMP nsFilePicker::GetDefaultString(PRUnichar **aString)
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
//
|
||||
// The default extension to use for files
|
||||
//
|
||||
//-------------------------------------------------------------------------
|
||||
NS_IMETHODIMP nsFilePicker::GetDefaultExtension(PRUnichar **aExtension)
|
||||
{
|
||||
*aExtension = ToNewUnicode(mDefaultExtension);
|
||||
if (!*aExtension)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsFilePicker::SetDefaultExtension(const PRUnichar *aExtension)
|
||||
{
|
||||
mDefaultExtension = aExtension;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
//
|
||||
// Set the filter index
|
||||
|
|
|
@ -47,6 +47,8 @@ public:
|
|||
// nsIFilePicker (less what's in nsBaseFilePicker)
|
||||
NS_IMETHOD GetDefaultString(PRUnichar * *aDefaultString);
|
||||
NS_IMETHOD SetDefaultString(const PRUnichar * aDefaultString);
|
||||
NS_IMETHOD GetDefaultExtension(PRUnichar * *aDefaultExtension);
|
||||
NS_IMETHOD SetDefaultExtension(const PRUnichar * aDefaultExtension);
|
||||
NS_IMETHOD GetDisplayDirectory(nsILocalFile * *aDisplayDirectory);
|
||||
NS_IMETHOD SetDisplayDirectory(nsILocalFile * aDisplayDirectory);
|
||||
NS_IMETHOD GetFilterIndex(PRInt32 *aFilterIndex);
|
||||
|
@ -73,6 +75,7 @@ protected:
|
|||
PRInt16 mMode;
|
||||
nsCString mFile;
|
||||
nsString mDefault;
|
||||
nsString mDefaultExtension;
|
||||
nsString mFilterList;
|
||||
nsIUnicodeEncoder* mUnicodeEncoder;
|
||||
nsIUnicodeDecoder* mUnicodeDecoder;
|
||||
|
|
|
@ -232,7 +232,9 @@ function foundHeaderInfo(aSniffer, aData)
|
|||
var defaultFileName = getDefaultFileName(aData.fileName,
|
||||
aSniffer.suggestedFileName,
|
||||
aSniffer.uri);
|
||||
fp.defaultString = getNormalizedLeafName(defaultFileName, contentType);
|
||||
var defaultExtension = getDefaultExtension(defaultFileName, aSniffer.uri, contentType);
|
||||
fp.defaultExtension = defaultExtension;
|
||||
fp.defaultString = getNormalizedLeafName(defaultFileName, defaultExtension);
|
||||
|
||||
if (fp.show() == Components.interfaces.nsIFilePicker.returnCancel || !fp.file)
|
||||
return;
|
||||
|
@ -243,7 +245,6 @@ function foundHeaderInfo(aSniffer, aData)
|
|||
prefs.setComplexValue("dir", nsILocalFile, directory);
|
||||
|
||||
fp.file.leafName = validateFileName(fp.file.leafName);
|
||||
fp.file.leafName = getNormalizedLeafName(fp.file.leafName, contentType);
|
||||
|
||||
// If we're saving a document, and are saving either in complete mode or
|
||||
// as converted text, pass the document to the web browser persist component.
|
||||
|
@ -510,36 +511,64 @@ function validateFileName(aFileName)
|
|||
return aFileName.replace(re, "_");
|
||||
}
|
||||
|
||||
function getNormalizedLeafName(aFile, aContentType)
|
||||
function getNormalizedLeafName(aFile, aDefaultExtension)
|
||||
{
|
||||
// Fix up the file name we're saving to so that if the user enters
|
||||
// no extension, an appropriate one is appended.
|
||||
var leafName = aFile;
|
||||
|
||||
var mimeInfo = getMIMEInfoForType(aContentType);
|
||||
if (mimeInfo) {
|
||||
var extCount = { };
|
||||
var extList = { };
|
||||
mimeInfo.GetFileExtensions(extCount, extList);
|
||||
|
||||
const stdURLContractID = "@mozilla.org/network/standard-url;1";
|
||||
const stdURLIID = Components.interfaces.nsIURI;
|
||||
var uri = Components.classes[stdURLContractID].createInstance(stdURLIID);
|
||||
var url = uri.QueryInterface(Components.interfaces.nsIURL);
|
||||
url.filePath = aFile;
|
||||
|
||||
if (aContentType == "text/html") {
|
||||
if ((url.fileExtension &&
|
||||
url.fileExtension != "htm" && url.fileExtension != "html") ||
|
||||
(!url.fileExtension))
|
||||
return leafName + ".html";
|
||||
}
|
||||
|
||||
if (!url.fileExtension)
|
||||
return leafName + "." + extList.value[0];
|
||||
if (!aDefaultExtension)
|
||||
return aFile;
|
||||
|
||||
// Fix up the file name we're saving to to include the default extension
|
||||
const stdURLContractID = "@mozilla.org/network/standard-url;1";
|
||||
const stdURLIID = Components.interfaces.nsIURL;
|
||||
var url = Components.classes[stdURLContractID].createInstance(stdURLIID);
|
||||
url.filePath = aFile;
|
||||
|
||||
if (url.fileExtension != aDefaultExtension) {
|
||||
return aFile + "." + aDefaultExtension;
|
||||
}
|
||||
|
||||
return aFile;
|
||||
}
|
||||
|
||||
function getDefaultExtension(aFilename, aURI, aContentType)
|
||||
{
|
||||
// This mirrors some code in nsExternalHelperAppService::DoContent
|
||||
// Use the filename first and then the URI if that fails
|
||||
|
||||
var mimeInfo = getMIMEInfoForType(aContentType);
|
||||
|
||||
// First try the extension from the filename
|
||||
const stdURLContractID = "@mozilla.org/network/standard-url;1";
|
||||
const stdURLIID = Components.interfaces.nsIURL;
|
||||
var url = Components.classes[stdURLContractID].createInstance(stdURLIID);
|
||||
url.filePath = aFilename;
|
||||
|
||||
var ext = url.fileExtension;
|
||||
|
||||
if (ext && mimeInfo.ExtensionExists(ext)) {
|
||||
return ext;
|
||||
}
|
||||
|
||||
// Well, that failed. Now try the extension from the URI
|
||||
var urlext;
|
||||
try {
|
||||
url = aURI.QueryInterface(Components.interfaces.nsIURL);
|
||||
urlext = url.fileExtension;
|
||||
} catch (e) {
|
||||
}
|
||||
|
||||
if (urlext && mimeInfo.ExtensionExists(urlext)) {
|
||||
return urlext;
|
||||
}
|
||||
else {
|
||||
try {
|
||||
return mimeInfo.primaryExtension;
|
||||
}
|
||||
catch (e) {
|
||||
// Fall back on the extensions in the filename and URI for lack
|
||||
// of anything better.
|
||||
return ext || urlext;
|
||||
}
|
||||
}
|
||||
|
||||
return leafName;
|
||||
}
|
||||
|
||||
function isDocumentType(aContentType)
|
||||
|
|
|
@ -100,6 +100,10 @@ nsFilePicker.prototype = {
|
|||
set defaultString(a) { this.mDefaultString = a; },
|
||||
get defaultString() { return this.mDefaultString; },
|
||||
|
||||
/* attribute wstring defaultExtension */
|
||||
set defaultExtension(ext) { },
|
||||
get defaultExtension() { return ""; },
|
||||
|
||||
/* attribute long filterIndex; */
|
||||
set filterIndex(a) { this.mFilterIndex = a; },
|
||||
get filterIndex() { return this.mFilterIndex; },
|
||||
|
|
|
@ -100,6 +100,10 @@ nsFilePicker.prototype = {
|
|||
set defaultString(a) { this.mDefaultString = a; },
|
||||
get defaultString() { return this.mDefaultString; },
|
||||
|
||||
/* attribute wstring defaultExtension */
|
||||
set defaultExtension(ext) { },
|
||||
get defaultExtension() { return ""; },
|
||||
|
||||
/* attribute long filterIndex; */
|
||||
set filterIndex(a) { this.mFilterIndex = a; },
|
||||
get filterIndex() { return this.mFilterIndex; },
|
||||
|
|
Загрузка…
Ссылка в новой задаче