Bug 661991 - add support for new file pickers. r=ehsan

This commit is contained in:
Jim Mathies 2011-12-14 15:22:28 -06:00
parent 6540425368
commit 218e530c99
2 changed files with 238 additions and 22 deletions

View File

@ -450,8 +450,7 @@ nsFilePicker::ShowFolderPicker(const nsString& aInitialDir)
dialog->Advise(this, &mFDECookie);
// options
FILEOPENDIALOGOPTIONS fos = 0;
fos |= FOS_PICKFOLDERS;
FILEOPENDIALOGOPTIONS fos = FOS_PICKFOLDERS;
dialog->SetOptions(fos);
// initial strings
@ -521,7 +520,7 @@ nsFilePicker::ShowXPFilePicker(const nsString& aInitialDir)
nsString filterBuffer = mFilterList;
nsAutoArrayPtr<PRUnichar> fileBuffer(new PRUnichar[FILE_BUFFER_SIZE]);
wcsncpy(fileBuffer, mDefault.get(), FILE_BUFFER_SIZE);
wcsncpy(fileBuffer, mDefaultFilePath.get(), FILE_BUFFER_SIZE);
fileBuffer[FILE_BUFFER_SIZE-1] = '\0'; // null terminate in case copy truncated
if (!aInitialDir.IsEmpty()) {
@ -638,7 +637,7 @@ nsFilePicker::ShowXPFilePicker(const nsString& aInitialDir)
break;
default:
NS_ERROR("unsupported file picker mode");
NS_NOTREACHED("unsupported file picker mode");
return false;
}
@ -711,7 +710,148 @@ nsFilePicker::ShowXPFilePicker(const nsString& aInitialDir)
bool
nsFilePicker::ShowFilePicker(const nsString& aInitialDir)
{
return false;
nsRefPtr<IFileDialog> dialog;
if (mMode != modeSave) {
if (FAILED(CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_INPROC,
IID_IFileOpenDialog,
getter_AddRefs(dialog))))
return false;
} else {
if (FAILED(CoCreateInstance(CLSID_FileSaveDialog, NULL, CLSCTX_INPROC,
IID_IFileSaveDialog,
getter_AddRefs(dialog))))
return false;
}
// hook up event callbacks
dialog->Advise(this, &mFDECookie);
// options
FILEOPENDIALOGOPTIONS fos = 0;
fos |= FOS_SHAREAWARE | FOS_OVERWRITEPROMPT | FOS_NOREADONLYRETURN;
// Handle add to recent docs settings
if (IsPrivacyModeEnabled() || !mAddToRecentDocs) {
fos |= FOS_DONTADDTORECENT;
}
// Msdn claims FOS_NOCHANGEDIR is not needed. We'll add this
// just in case.
AutoRestoreWorkingPath arw;
// mode specific
switch(mMode) {
case modeOpen:
fos |= FOS_FILEMUSTEXIST;
break;
case modeOpenMultiple:
fos |= FOS_FILEMUSTEXIST | FOS_ALLOWMULTISELECT;
break;
case modeSave:
// Don't follow shortcuts when saving a shortcut, this can be used
// to trick users (bug 271732)
if (IsDefaultPathLink())
fos |= FOS_NODEREFERENCELINKS;
break;
}
dialog->SetOptions(fos);
// initial strings
// title
dialog->SetTitle(mTitle.get());
// default filename
if (!mDefaultFilename.IsEmpty()) {
dialog->SetFileName(mDefaultFilename.get());
}
NS_NAMED_LITERAL_STRING(htmExt, "html");
// default extension to append to new files
if (!mDefaultExtension.IsEmpty()) {
dialog->SetDefaultExtension(mDefaultExtension.get());
} else if (IsDefaultPathHtml()) {
dialog->SetDefaultExtension(htmExt.get());
}
// initial location
if (!aInitialDir.IsEmpty()) {
nsRefPtr<IShellItem> folder;
if (SUCCEEDED(SHCreateItemFromParsingName(aInitialDir.get(), NULL,
IID_IShellItem,
getter_AddRefs(folder)))) {
dialog->SetFolder(folder);
}
}
// filter types and the default index
if (!mComFilterList.IsEmpty()) {
dialog->SetFileTypes(mComFilterList.Length(), mComFilterList.get());
dialog->SetFileTypeIndex(mSelectedType);
}
// display
AutoDestroyTmpWindow adtw((HWND)(mParentWidget.get() ?
mParentWidget->GetNativeData(NS_NATIVE_TMP_WINDOW) : NULL));
AutoWidgetPickerState awps(mParentWidget);
if (FAILED(dialog->Show(adtw.get()))) {
dialog->Unadvise(mFDECookie);
return false;
}
dialog->Unadvise(mFDECookie);
// results
// single selection
if (mMode != modeOpenMultiple) {
nsRefPtr<IShellItem> item;
if (FAILED(dialog->GetResult(getter_AddRefs(item))) || !item) {
return false;
}
LPWSTR str = NULL;
if (FAILED(item->GetDisplayName(SIGDN_FILESYSPATH, &str)))
return false;
mUnicodeFile.Assign(str);
CoTaskMemFree(str);
return true;
}
// multiple selection
nsRefPtr<IFileOpenDialog> openDlg;
dialog->QueryInterface(IID_IFileOpenDialog, getter_AddRefs(openDlg));
if (!openDlg) {
// should not happen
return false;
}
nsRefPtr<IShellItemArray> items;
if (FAILED(openDlg->GetResults(getter_AddRefs(items))) || !items) {
return false;
}
DWORD count = 0;
items->GetCount(&count);
for (unsigned int idx = 0; idx < count; idx++) {
nsRefPtr<IShellItem> item;
if (SUCCEEDED(items->GetItemAt(idx, getter_AddRefs(item)))) {
LPWSTR str = NULL;
if (FAILED(item->GetDisplayName(SIGDN_FILESYSPATH, &str)))
continue;
nsCOMPtr<nsILocalFile> file = do_CreateInstance("@mozilla.org/file/local;1");
if (file && NS_SUCCEEDED(file->InitWithPath(nsDependentString(str))))
mFiles.AppendObject(file);
CoTaskMemFree(str);
}
}
return true;
}
///////////////////////////////////////////////////////////////////////////////
@ -830,32 +970,33 @@ nsFilePicker::GetFiles(nsISimpleEnumerator **aFiles)
NS_IMETHODIMP
nsFilePicker::SetDefaultString(const nsAString& aString)
{
mDefault = aString;
mDefaultFilePath = aString;
//First, make sure the file name is not too long!
// First, make sure the file name is not too long.
PRInt32 nameLength;
PRInt32 nameIndex = mDefault.RFind("\\");
PRInt32 nameIndex = mDefaultFilePath.RFind("\\");
if (nameIndex == kNotFound)
nameIndex = 0;
else
nameIndex ++;
nameLength = mDefault.Length() - nameIndex;
nameLength = mDefaultFilePath.Length() - nameIndex;
mDefaultFilename.Assign(Substring(mDefaultFilePath, nameIndex));
if (nameLength > MAX_PATH) {
PRInt32 extIndex = mDefault.RFind(".");
PRInt32 extIndex = mDefaultFilePath.RFind(".");
if (extIndex == kNotFound)
extIndex = mDefault.Length();
extIndex = mDefaultFilePath.Length();
//Let's try to shave the needed characters from the name part
// Let's try to shave the needed characters from the name part.
PRInt32 charsToRemove = nameLength - MAX_PATH;
if (extIndex - nameIndex >= charsToRemove) {
mDefault.Cut(extIndex - charsToRemove, charsToRemove);
mDefaultFilePath.Cut(extIndex - charsToRemove, charsToRemove);
}
}
//Then, we need to replace illegal characters.
//At this stage, we cannot replace the backslash as the string might represent a file path.
mDefault.ReplaceChar(FILE_ILLEGAL_CHARACTERS, '-');
// Then, we need to replace illegal characters. At this stage, we cannot
// replace the backslash as the string might represent a file path.
mDefaultFilePath.ReplaceChar(FILE_ILLEGAL_CHARACTERS, '-');
return NS_OK;
}
@ -922,8 +1063,8 @@ nsFilePicker::GetQualifiedPath(const PRUnichar *aInPath, nsString &aOutPath)
}
}
NS_IMETHODIMP
nsFilePicker::AppendFilter(const nsAString& aTitle, const nsAString& aFilter)
void
nsFilePicker::AppendXPFilter(const nsAString& aTitle, const nsAString& aFilter)
{
mFilterList.Append(aTitle);
mFilterList.Append(PRUnichar('\0'));
@ -940,7 +1081,20 @@ nsFilePicker::AppendFilter(const nsAString& aTitle, const nsAString& aFilter)
}
mFilterList.Append(PRUnichar('\0'));
}
NS_IMETHODIMP
nsFilePicker::AppendFilter(const nsAString& aTitle, const nsAString& aFilter)
{
#if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
if (nsWindow::GetWindowsVersion() >= VISTA_VERSION) {
mComFilterList.Append(aTitle, aFilter);
} else {
AppendXPFilter(aTitle, aFilter);
}
#else
AppendXPFilter(aTitle, aFilter);
#endif
return NS_OK;
}
@ -986,7 +1140,7 @@ nsFilePicker::IsPrivacyModeEnabled()
bool
nsFilePicker::IsDefaultPathLink()
{
NS_ConvertUTF16toUTF8 ext(mDefault);
NS_ConvertUTF16toUTF8 ext(mDefaultFilePath);
ext.Trim(" .", false, true); // watch out for trailing space and dots
ToLowerCase(ext);
if (StringEndsWith(ext, NS_LITERAL_CSTRING(".lnk")) ||
@ -999,10 +1153,10 @@ nsFilePicker::IsDefaultPathLink()
bool
nsFilePicker::IsDefaultPathHtml()
{
PRInt32 extIndex = mDefault.RFind(".");
PRInt32 extIndex = mDefaultFilePath.RFind(".");
if (extIndex >= 0) {
nsAutoString ext;
mDefault.Right(ext, mDefault.Length() - extIndex);
mDefaultFilePath.Right(ext, mDefaultFilePath.Length() - extIndex);
if (ext.LowerCaseEqualsLiteral(".htm") ||
ext.LowerCaseEqualsLiteral(".html") ||
ext.LowerCaseEqualsLiteral(".shtml"))
@ -1010,3 +1164,30 @@ nsFilePicker::IsDefaultPathHtml()
}
return false;
}
void
nsFilePicker::ComDlgFilterSpec::Append(const nsAString& aTitle, const nsAString& aFilter)
{
PRUint32 size = sizeof(COMDLG_FILTERSPEC);
PRUint32 hdrLen = size * (mLength + 1);
mSpecList = (COMDLG_FILTERSPEC*)realloc(mSpecList, hdrLen);
if (!mSpecList) {
NS_WARNING("mSpecList realloc failed.");
return;
}
COMDLG_FILTERSPEC* pSpecForward = (COMDLG_FILTERSPEC*)(mSpecList + mLength);
memset(pSpecForward, 0, size);
nsString* pStr = mStrings.AppendElement(aTitle);
if (!pStr) {
NS_WARNING("mStrings.AppendElement failed.");
return;
}
pSpecForward->pszName = pStr->get();
pStr = mStrings.AppendElement(aFilter);
if (!pStr) {
NS_WARNING("mStrings.AppendElement failed.");
return;
}
pSpecForward->pszSpec = pStr->get();
mLength++;
}

View File

@ -129,6 +129,7 @@ protected:
bool ShowXPFolderPicker(const nsString& aInitialDir);
bool ShowFilePicker(const nsString& aInitialDir);
bool ShowXPFilePicker(const nsString& aInitialDir);
void AppendXPFilter(const nsAString& aTitle, const nsAString& aFilter);
void RememberLastUsedDirectory();
bool IsPrivacyModeEnabled();
bool IsDefaultPathLink();
@ -138,7 +139,8 @@ protected:
nsString mTitle;
PRInt16 mMode;
nsCString mFile;
nsString mDefault;
nsString mDefaultFilePath;
nsString mDefaultFilename;
nsString mDefaultExtension;
nsString mFilterList;
PRInt16 mSelectedType;
@ -147,6 +149,39 @@ protected:
nsString mUnicodeFile;
static PRUnichar *mLastUsedUnicodeDirectory;
DWORD mFDECookie;
#if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
class ComDlgFilterSpec
{
public:
ComDlgFilterSpec() :
mSpecList(nsnull),
mLength(0) {}
~ComDlgFilterSpec() {
free(mSpecList);
}
PRUint32 Length() {
return mLength;
}
bool IsEmpty() {
return (mLength == 0);
}
const COMDLG_FILTERSPEC* get() {
return mSpecList;
}
void Append(const nsAString& aTitle, const nsAString& aFilter);
private:
COMDLG_FILTERSPEC* mSpecList;
nsAutoTArray<nsString, 2> mStrings;
PRUint32 mLength;
};
ComDlgFilterSpec mComFilterList;
#endif
};
#if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN