fix for #121122 (nsIFilePicker should allow picking multiple files) and #43015 (Cannot add multiple attachment in Attach File dialog).

right now, only supported on windows.  bugs logged for mac, beos, cocoa, os/2, qnx
and the xpfilepicker (linux).

r=bz, sr=bienvenu, a=asa
This commit is contained in:
sspitzer%netscape.com 2002-09-07 05:23:45 +00:00
Родитель ccb57e7a19
Коммит d73ec61a67
12 изменённых файлов: 167 добавлений и 27 удалений

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

@ -178,8 +178,8 @@ function enableEditableFields()
var gComposeRecyclingListener = {
onClose: function() {
//Reset recipients and attachments
awResetAllRows();
RemoveAllAttachments();
awResetAllRows();
RemoveAllAttachments();
//We need to clear the identity popup menu in case the user will change them. It will be rebuilded later in ComposeStartup
ClearIdentityListPopup(document.getElementById("msgIdentityPopup"));
@ -2191,12 +2191,12 @@ function SetLastAttachDirectory(attachedLocalFile)
function AttachFile()
{
var currentAttachment = "";
var attachments;
//Get file using nsIFilePicker and convert to URL
try {
var fp = Components.classes["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker);
fp.init(window, sComposeMsgsBundle.getString("chooseFileToAttach"), nsIFilePicker.modeOpen);
fp.init(window, sComposeMsgsBundle.getString("chooseFileToAttach"), nsIFilePicker.modeOpenMultiple);
var lastDirectory = GetLastAttachDirectory();
if (lastDirectory)
@ -2204,28 +2204,36 @@ function AttachFile()
fp.appendFilters(nsIFilePicker.filterAll);
if (fp.show() == nsIFilePicker.returnOK) {
currentAttachment = fp.fileURL.spec;
SetLastAttachDirectory(fp.file)
attachments = fp.files;
}
}
catch (ex) {
dump("failed to get the local file to attach\n");
dump("failed to get attachments: " + ex + "\n");
}
if (currentAttachment == "")
if (!attachments || !attachments.hasMoreElements())
return;
if (DuplicateFileCheck(currentAttachment))
{
dump("Error, attaching the same item twice\n");
}
else
{
var attachment = Components.classes["@mozilla.org/messengercompose/attachment;1"]
.createInstance(Components.interfaces.nsIMsgAttachment);
attachment.url = currentAttachment;
AddAttachment(attachment);
gContentChanged = true;
var haveSetAttachDirectory = false;
while (attachments.hasMoreElements()) {
var currentFile = attachments.getNext().QueryInterface(Components.interfaces.nsILocalFile);
if (!haveSetAttachDirectory) {
SetLastAttachDirectory(currentFile);
haveSetAttachDirectory = true;
}
var ioService = Components.classes["@mozilla.org/network/io-service;1"]
ioService = ioService.getService(Components.interfaces.nsIIOService);
var currentAttachment = ioService.getURLSpecFromFile(currentFile);
if (!DuplicateFileCheck(currentAttachment)) {
var attachment = Components.classes["@mozilla.org/messengercompose/attachment;1"].createInstance(Components.interfaces.nsIMsgAttachment);
attachment.url = currentAttachment;
AddAttachment(attachment);
gContentChanged = true;
}
}
}

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

@ -26,6 +26,7 @@
interface nsILocalFile;
interface nsIFileURL;
interface nsIDOMWindowInternal;
interface nsISimpleEnumerator;
[scriptable, uuid(c47de916-1dd1-11b2-8141-82507fa02b21)]
interface nsIFilePicker : nsISupports
@ -33,6 +34,7 @@ interface nsIFilePicker : nsISupports
const short modeOpen = 0; // Load a file or directory
const short modeSave = 1; // Save a file or directory
const short modeGetFolder = 2; // Select a folder/directory
const short modeOpenMultiple= 3; // Load multiple files
const short returnOK = 0; // User hit Ok, process selection
const short returnCancel = 1; // User hit cancel, ignore selection
@ -118,6 +120,14 @@ interface nsIFilePicker : nsISupports
*/
readonly attribute nsIFileURL fileURL;
/**
* Get the enumerator for the selected files
* only works in the modeOpenMultiple mode
*
* @return Returns the files currently selected
*/
readonly attribute nsISimpleEnumerator files;
/**
* Show File Dialog. The dialog is displayed modally.
*

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

@ -80,7 +80,7 @@ NS_IMETHODIMP nsFilePicker::Show(PRInt16 *retval)
node_flavors = B_DIRECTORY_NODE;
panel_mode = B_OPEN_PANEL;
}
else if (mMode == modeOpen) {
else if (mMode == modeOpen || mMode == modeOpenMultiple) {
node_flavors = B_FILE_NODE;
panel_mode = B_OPEN_PANEL;
}
@ -136,7 +136,7 @@ NS_IMETHODIMP nsFilePicker::Show(PRInt16 *retval)
result = PR_FALSE;
}
if (mMode == modeOpen && ppanel->IsOpenSelected()) {
if ((mMode == modeOpen || mMode == modeOpenMultiple) && ppanel->IsOpenSelected()) {
BList *list = ppanel->OpenRefs();
if ((list) && list->CountItems() >= 1) {
entry_ref *ref = (entry_ref *)list->ItemAt(0);

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

@ -208,7 +208,7 @@ NS_IMETHODIMP nsFilePicker::Show(PRInt16 *retval)
// XXX Ignore the filter list for now....
if (mMode == modeOpen)
if (mMode == modeOpen || mMode == modeOpenMultiple)
userClicksOK = GetLocalFile(title, &theFile);
else if (mMode == modeSave)
userClicksOK = PutLocalFile(title, defaultName, &theFile);

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

@ -160,7 +160,7 @@ NS_IMETHODIMP nsFilePicker::Show(PRInt16 *retval)
// XXX Ignore the filter list for now....
if (mMode == modeOpen)
if (mMode == modeOpen || mMode == modeOpenMultiple)
userClicksOK = GetLocalFile(mTitle, &theFile);
else if (mMode == modeSave)
userClicksOK = PutLocalFile(mTitle, mDefault, &theFile);

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

@ -19,6 +19,7 @@
*
* Contributor(s):
* Stuart Parmenter <pavlov@netscape.com>
* Seth Spitzer <sspitzer@netscape.com>
*/
// Define so header files for openfilename are included
@ -36,6 +37,7 @@
#include "nsIURL.h"
#include "nsIFileURL.h"
#include "nsIStringBundle.h"
#include "nsEnumeratorUtils.h"
#include "nsCRT.h"
#include <windows.h>
#include <SHLOBJ.H>
@ -404,6 +406,10 @@ NS_IMETHODIMP nsFilePicker::Show(PRInt16 *aReturnVal)
ofn.Flags |= OFN_FILEMUSTEXIST;
result = ::GetOpenFileName(&ofn);
}
else if (mMode == modeOpenMultiple) {
ofn.Flags |= OFN_FILEMUSTEXIST | OFN_ALLOWMULTISELECT | OFN_EXPLORER;
result = ::GetOpenFileName(&ofn);
}
else if (mMode == modeSave) {
ofn.Flags |= OFN_NOREADONLYRETURN;
result = ::GetSaveFileName(&ofn);
@ -433,9 +439,53 @@ NS_IMETHODIMP nsFilePicker::Show(PRInt16 *aReturnVal)
if (result == PR_TRUE) {
// I think it also needs a conversion here (to unicode since appending to nsString)
// but doing that generates garbage file name, weird.
if (mMode == modeOpenMultiple) {
nsresult rv = NS_NewISupportsArray(getter_AddRefs(mFiles));
NS_ENSURE_SUCCESS(rv,rv);
// from msdn.microsoft.com, "Open and Save As Dialog Boxes" section:
// If you specify OFN_EXPLORER,
// The directory and file name strings are NULL separated,
// with an extra NULL character after the last file name.
// This format enables the Explorer-style dialog boxes
// to return long file names that include spaces.
char *current = fileBuffer;
const char *dirName = current;
while (current && *current && *(current + strlen(current) + 1)) {
current = current + strlen(current) + 1;
nsCOMPtr<nsILocalFile> file = do_CreateInstance("@mozilla.org/file/local;1", &rv);
NS_ENSURE_SUCCESS(rv,rv);
// dirName contains a trailing slash
rv = file->InitWithNativePath(nsDependentCString(dirName) + nsDependentCString(current));
NS_ENSURE_SUCCESS(rv,rv);
rv = mFiles->AppendElement(file);
NS_ENSURE_SUCCESS(rv,rv);
}
// handle the case where the user selected just one
// file. according to msdn.microsoft.com:
// If you specify OFN_ALLOWMULTISELECT and the user selects
// only one file, the lpstrFile string does not have
// a separator between the path and file name.
if (current && *current && (current == fileBuffer)) {
nsCOMPtr<nsILocalFile> file = do_CreateInstance("@mozilla.org/file/local;1", &rv);
NS_ENSURE_SUCCESS(rv,rv);
rv = file->InitWithNativePath(nsDependentCString(current));
NS_ENSURE_SUCCESS(rv,rv);
rv = mFiles->AppendElement(file);
NS_ENSURE_SUCCESS(rv,rv);
}
}
else {
mFile.Append(fileBuffer);
}
}
}
if (title)
@ -528,6 +578,12 @@ NS_IMETHODIMP nsFilePicker::GetFileURL(nsIFileURL **aFileURL)
return NS_OK;
}
NS_IMETHODIMP nsFilePicker::GetFiles(nsISimpleEnumerator **aFiles)
{
NS_ENSURE_ARG_POINTER(aFiles);
return NS_NewArrayEnumerator(aFiles, mFiles);
}
//-------------------------------------------------------------------------
//
// Get the file + path

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

@ -19,12 +19,15 @@
*
* Contributor(s):
* Stuart Parmenter <pavlov@netscape.com>
* Seth Spitzer <sspitzer@netscape.com>
*/
#ifndef nsFilePicker_h__
#define nsFilePicker_h__
#include "nsILocalFile.h"
#include "nsISimpleEnumerator.h"
#include "nsISupportsArray.h"
#include "nsICharsetConverterManager.h"
#include "nsBaseFilePicker.h"
@ -54,6 +57,7 @@ public:
NS_IMETHOD SetFilterIndex(PRInt32 aFilterIndex);
NS_IMETHOD GetFile(nsILocalFile * *aFile);
NS_IMETHOD GetFileURL(nsIFileURL * *aFileURL);
NS_IMETHOD GetFiles(nsISimpleEnumerator **aFiles);
NS_IMETHOD Show(PRInt16 *aReturnVal);
#ifdef MOZ_UNICODE
NS_IMETHOD ShowW(PRInt16 *aReturnVal);
@ -83,7 +87,7 @@ protected:
nsIUnicodeDecoder* mUnicodeDecoder;
nsCOMPtr<nsILocalFile> mDisplayDirectory;
PRInt16 mSelectedType;
nsCOMPtr <nsISupportsArray> mFiles;
static char mLastUsedDirectory[];
#ifdef MOZ_UNICODE

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

@ -36,6 +36,9 @@
#include "nsIStringBundle.h"
#include "nsXPIDLString.h"
#include "nsIServiceManager.h"
#include "nsISupportsArray.h"
#include "nsILocalFile.h"
#include "nsEnumeratorUtils.h"
#include "nsBaseFilePicker.h"
@ -183,3 +186,22 @@ NS_IMETHODIMP nsBaseFilePicker::SetFilterIndex(PRInt32 aFilterIndex)
return NS_OK;
}
NS_IMETHODIMP nsBaseFilePicker::GetFiles(nsISimpleEnumerator **aFiles)
{
NS_ENSURE_ARG_POINTER(aFiles);
nsCOMPtr <nsISupportsArray> files;
nsresult rv = NS_NewISupportsArray(getter_AddRefs(files));
NS_ENSURE_SUCCESS(rv,rv);
// if we get into the base class, the platform
// doesn't implement GetFiles() yet.
// so we fake it.
nsCOMPtr <nsILocalFile> file;
rv = GetFile(getter_AddRefs(file));
NS_ENSURE_SUCCESS(rv,rv);
rv = files->AppendElement(file);
NS_ENSURE_SUCCESS(rv,rv);
return NS_NewArrayEnumerator(aFiles, files);
}

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

@ -27,6 +27,7 @@
#include "nsIFilePicker.h"
#include "nsIWidget.h"
#include "nsISimpleEnumerator.h"
class nsBaseFilePicker : public nsIFilePicker
{
@ -41,6 +42,7 @@ public:
NS_IMETHOD AppendFilters(PRInt32 filterMask);
NS_IMETHOD GetFilterIndex(PRInt32 *aFilterIndex);
NS_IMETHOD SetFilterIndex(PRInt32 aFilterIndex);
NS_IMETHOD GetFiles(nsISimpleEnumerator **aFiles);
protected:

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

@ -78,12 +78,13 @@ function filepickerLoad() {
}
}
if (filePickerMode != nsIFilePicker.modeOpen) {
if (filePickerMode != nsIFilePicker.modeOpen && filePickerMode != nsIFilePicker.modeOpenMultiple) {
var newDirButton = document.getElementById("newDirButton");
newDirButton.removeAttribute("hidden");
}
if ((filePickerMode == nsIFilePicker.modeOpen) ||
(filePickerMode == nsIFilePicker.modeOpenMultiple) ||
(filePickerMode == nsIFilePicker.modeSave)) {
treeView.setFilter(filterTypes[0]);
@ -199,7 +200,9 @@ function openOnOK()
if (dir)
gotoDirectory(dir);
retvals.file = dir;
retvals.buttonStatus = nsIFilePicker.returnCancel;
var filterMenuList = document.getElementById("filterMenuList");
@ -248,6 +251,7 @@ function selectOnOK()
switch(filePickerMode) {
case nsIFilePicker.modeOpen:
case nsIFilePicker.modeOpenMultiple:
if (isFile) {
if (file.isReadable()) {
retvals.directory = file.parent.path;
@ -339,6 +343,11 @@ function selectOnOK()
}
retvals.file = file;
gFilesEnumerator.mFile = file;
gFilesEnumerator.mHasMore = true;
retvals.files = gFilesEnumerator;
retvals.buttonStatus = ret;
var filterMenuList = document.getElementById("filterMenuList");
@ -347,11 +356,27 @@ function selectOnOK()
return (ret != nsIFilePicker.returnCancel);
}
var gFilesEnumerator = {
mHasMore: false,
mFile: null,
hasMoreElements: function()
{
return this.mHasMore;
},
getNext: function()
{
this.mHasMore = false;
return this.mFile;
}
};
function onCancel()
{
// Close the window.
retvals.buttonStatus = nsIFilePicker.returnCancel;
retvals.file = null;
retvals.files = null;
return true;
}
@ -465,6 +490,7 @@ function getOKAction(file) {
buttonLabel = gFilePickerBundle.getString("selectFolderButtonLabel");
break;
case nsIFilePicker.modeOpen:
case nsIFilePicker.modeOpenMultiple:
buttonLabel = gFilePickerBundle.getString("openButtonLabel");
break;
case nsIFilePicker.modeSave:

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

@ -84,6 +84,10 @@ nsFilePicker.prototype = {
set file(a) { throw "readonly property"; },
get file() { return this.mFile; },
/* readonly attribute nsISimpleEnumerator files; */
set files(a) { throw "readonly property"; },
get files() { return this.mFilesEnumerator; },
/* readonly attribute nsIFileURL fileURL; */
set fileURL(a) { throw "readonly property"; },
get fileURL() {
@ -110,6 +114,7 @@ nsFilePicker.prototype = {
/* members */
mFile: undefined,
mFilesEnumerator: undefined,
mParentWindow: null,
/* methods */
@ -197,6 +202,7 @@ nsFilePicker.prototype = {
o);
this.mFile = o.retvals.file;
this.mFilterIndex = o.retvals.filterIndex;
this.mFilesEnumerator = o.retvals.files;
lastDirectory = o.retvals.directory;
return o.retvals.buttonStatus;
} catch(ex) { dump("unable to open file picker\n" + ex + "\n"); }

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

@ -84,6 +84,10 @@ nsFilePicker.prototype = {
set file(a) { throw "readonly property"; },
get file() { return this.mFile; },
/* readonly attribute nsISimpleEnumerator files; */
set files(a) { throw "readonly property"; },
get files() { return this.mFilesEnumerator; },
/* readonly attribute nsIFileURL fileURL; */
set fileURL(a) { throw "readonly property"; },
get fileURL() {
@ -110,6 +114,7 @@ nsFilePicker.prototype = {
/* members */
mFile: undefined,
mFilesEnumerator: undefined,
mParentWindow: null,
/* methods */
@ -197,6 +202,7 @@ nsFilePicker.prototype = {
o);
this.mFile = o.retvals.file;
this.mFilterIndex = o.retvals.filterIndex;
this.mFilesEnumerator = o.retvals.files;
lastDirectory = o.retvals.directory;
return o.retvals.buttonStatus;
} catch(ex) { dump("unable to open file picker\n" + ex + "\n"); }