Back to index

lightning-sunbird  0.9+nobinonly
nsFilePicker.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
00002  *
00003  * ***** BEGIN LICENSE BLOCK *****
00004  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00005  *
00006  * The contents of this file are subject to the Mozilla Public License Version
00007  * 1.1 (the "License"); you may not use this file except in compliance with
00008  * the License. You may obtain a copy of the License at
00009  * http://www.mozilla.org/MPL/
00010  *
00011  * Software distributed under the License is distributed on an "AS IS" basis,
00012  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00013  * for the specific language governing rights and limitations under the
00014  * License.
00015  *
00016  * The Original Code is the Mozilla browser.
00017  *
00018  * The Initial Developer of the Original Code is
00019  * Netscape Communications Corporation.
00020  * Portions created by the Initial Developer are Copyright (C) 2000
00021  * the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *   Stuart Parmenter <pavlov@netscape.com>
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either the GNU General Public License Version 2 or later (the "GPL"), or
00028  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 
00040 // Define so header files for openfilename are included
00041 #ifdef WIN32_LEAN_AND_MEAN
00042 #undef WIN32_LEAN_AND_MEAN
00043 #endif
00044 
00045 #include "nsCOMPtr.h"
00046 #include "nsReadableUtils.h"
00047 #include "nsNetUtil.h"
00048 #include "nsIServiceManager.h"
00049 #include "nsIPlatformCharset.h"
00050 #include "nsWidgetDefs.h"
00051 #include "nsFilePicker.h"
00052 #include "nsILocalFile.h"
00053 #include "nsIURL.h"
00054 #include "nsIFileURL.h"
00055 #include "nsIStringBundle.h"
00056 #include "nsEnumeratorUtils.h"
00057 #include "nsCRT.h"
00058 
00059 #include "nsOS2Uni.h"
00060 
00061 /* Item structure */
00062 typedef struct _MyData
00063 {
00064    PAPSZ    papszIFilterList;
00065    ULONG    ulCurExt;
00066    ULONG    ulNumFilters;
00067 }MYDATA, *PMYDATA;
00068 
00069 static NS_DEFINE_CID(kCharsetConverterManagerCID, NS_ICHARSETCONVERTERMANAGER_CID);
00070 
00071 NS_IMPL_ISUPPORTS1(nsFilePicker, nsIFilePicker)
00072 
00073 char nsFilePicker::mLastUsedDirectory[MAX_PATH+1] = { 0 };
00074 
00075 
00076 static char* gpszFDSaveCaption = 0;
00077 static char* gpszFDFileExists = 0;
00078 static char* gpszFDFileReadOnly = 0;
00079 
00080 MRESULT EXPENTRY DirDialogProc( HWND hwndDlg, ULONG msg, MPARAM mp1, MPARAM mp2);
00081 MRESULT EXPENTRY FileDialogProc( HWND hwndDlg, ULONG msg, MPARAM mp1, MPARAM mp2);
00082 
00083 //-------------------------------------------------------------------------
00084 //
00085 // nsFilePicker constructor
00086 //
00087 //-------------------------------------------------------------------------
00088 nsFilePicker::nsFilePicker()
00089 {
00090   mWnd = NULL;
00091   mUnicodeEncoder = nsnull;
00092   mUnicodeDecoder = nsnull;
00093   mSelectedType   = 0;
00094 }
00095 
00096 //-------------------------------------------------------------------------
00097 //
00098 // nsFilePicker destructor
00099 //
00100 //-------------------------------------------------------------------------
00101 nsFilePicker::~nsFilePicker()
00102 {
00103   mFilters.Clear();
00104   mTitles.Clear();
00105 
00106   NS_IF_RELEASE(mUnicodeEncoder);
00107   NS_IF_RELEASE(mUnicodeDecoder);
00108 }
00109 
00110 /* static */ void
00111 nsFilePicker::ReleaseGlobals()
00112 {
00113   if (gpszFDSaveCaption) {
00114      free(gpszFDSaveCaption);
00115      free(gpszFDFileExists);
00116      free(gpszFDFileReadOnly);
00117   }
00118 }
00119 
00120 //-------------------------------------------------------------------------
00121 //
00122 // Show - Display the file dialog
00123 //
00124 //-------------------------------------------------------------------------
00125 NS_IMETHODIMP nsFilePicker::Show(PRInt16 *retval)
00126 {
00127   NS_ENSURE_ARG_POINTER(retval);
00128 
00129   PRBool result = PR_FALSE;
00130   char fileBuffer[MAX_PATH+1] = "";
00131   char *converted = ConvertToFileSystemCharset(mDefault);
00132   if (nsnull == converted) {
00133     mDefault.ToCString(fileBuffer,MAX_PATH);
00134   }
00135   else {
00136     PL_strncpyz(fileBuffer, converted, MAX_PATH+1);
00137     nsMemory::Free( converted );
00138   }
00139 
00140   char *title = ConvertToFileSystemCharset(mTitle);
00141   if (nsnull == title)
00142     title = ToNewCString(mTitle);
00143   nsCAutoString initialDir;
00144   if (mDisplayDirectory)
00145     mDisplayDirectory->GetNativePath(initialDir);
00146   // If no display directory, re-use the last one.
00147   if(initialDir.IsEmpty())
00148     initialDir = mLastUsedDirectory;
00149 
00150   mFile.Truncate();
00151 
00152   FILEDLG filedlg;
00153   memset(&filedlg, 0, sizeof(FILEDLG));
00154   filedlg.cbSize = sizeof(FILEDLG);
00155   filedlg.pszTitle = title;
00156 
00157   if (mMode == modeGetFolder) {
00158     PL_strncat(filedlg.szFullFile, initialDir.get(), MAX_PATH);
00159     PL_strncat(filedlg.szFullFile, "\\", 1);
00160     PL_strncat(filedlg.szFullFile, "^", 1);
00161     filedlg.fl = FDS_OPEN_DIALOG | FDS_CENTER;
00162     filedlg.pfnDlgProc = DirDialogProc;
00163     DosError(FERR_DISABLEHARDERR);
00164     WinFileDlg(HWND_DESKTOP, mWnd, &filedlg);
00165     DosError(FERR_ENABLEHARDERR);
00166     char* tempptr = strstr(filedlg.szFullFile, "^");
00167     if (tempptr)
00168       *tempptr = '\0';
00169     if (filedlg.lReturn == DID_OK) {
00170       result = PR_TRUE;
00171       if (!mDisplayDirectory)
00172         mDisplayDirectory = do_CreateInstance("@mozilla.org/file/local;1");
00173       if (mDisplayDirectory)
00174         mDisplayDirectory->InitWithNativePath(nsDependentCString(filedlg.szFullFile));
00175       mFile.Assign(filedlg.szFullFile);
00176     }
00177   }
00178   else {
00179     PL_strncpy(filedlg.szFullFile, initialDir.get(), MAX_PATH);
00180     PL_strncat(filedlg.szFullFile, "\\", 1);
00181     PL_strncat(filedlg.szFullFile, fileBuffer, MAX_PATH);
00182     filedlg.fl = FDS_CENTER;
00183     if (mMode == modeSave) {
00184        filedlg.fl |= FDS_SAVEAS_DIALOG | FDS_ENABLEFILELB;
00185     } else if (mMode == modeOpenMultiple) {
00186        filedlg.fl |= FDS_MULTIPLESEL | FDS_OPEN_DIALOG;
00187     } else {
00188        filedlg.fl |= FDS_OPEN_DIALOG;
00189     }
00190     PMYDATA pmydata;
00191     pmydata = (PMYDATA)calloc(1, sizeof(MYDATA));
00192     filedlg.ulUser = (ULONG)pmydata;
00193     filedlg.pfnDlgProc = FileDialogProc;
00194 
00195     int i;
00196 
00197     PSZ *apszTypeList;
00198     apszTypeList = (PSZ *)malloc(mTitles.Count()*sizeof(PSZ)+1);
00199     for (i = 0; i < mTitles.Count(); i++)
00200     {
00201       const nsString& typeWide = *mTitles[i];
00202       nsAutoCharBuffer buffer;
00203       PRInt32 bufLength;
00204       WideCharToMultiByte(0, typeWide.get(), typeWide.Length(),
00205                           buffer, bufLength);
00206       apszTypeList[i] = ToNewCString(nsDependentCString(buffer.get()));
00207     }
00208     apszTypeList[i] = 0;
00209     filedlg.papszITypeList = (PAPSZ)apszTypeList;
00210 
00211     PSZ *apszFilterList;
00212     apszFilterList = (PSZ *)malloc(mFilters.Count()*sizeof(PSZ)+1);
00213     for (i = 0; i < mFilters.Count(); i++)
00214     {
00215       const nsString& filterWide = *mFilters[i];
00216       apszFilterList[i] = ToNewCString(filterWide);
00217     }
00218     apszFilterList[i] = 0;
00219     pmydata->papszIFilterList = (PAPSZ)apszFilterList;
00220 
00221     pmydata->ulCurExt = mSelectedType;
00222 
00223     PRBool fileExists;
00224     do {
00225       DosError(FERR_DISABLEHARDERR);
00226       WinFileDlg(HWND_DESKTOP, mWnd, &filedlg);
00227       DosError(FERR_ENABLEHARDERR);
00228       if ((filedlg.lReturn == DID_OK) && (mMode == modeSave)) {
00229          PRFileInfo64 fileinfo64;
00230          PRStatus status = PR_GetFileInfo64(filedlg.szFullFile, &fileinfo64);
00231          if (status == PR_SUCCESS) {
00232             fileExists = PR_TRUE;
00233          } else {
00234             fileExists = PR_FALSE;
00235          }
00236          if (fileExists) {
00237             if (!gpszFDSaveCaption) {
00238               HMODULE hmod;
00239               char LoadError[CCHMAXPATH];
00240               char loadedString[256];
00241               int length;
00242               DosLoadModule(LoadError, CCHMAXPATH, "PMSDMRI", &hmod);
00243               length = WinLoadString((HAB)0, hmod, 1110, 256, loadedString);
00244               gpszFDSaveCaption = (char*)malloc(length+1);
00245               strcpy(gpszFDSaveCaption, loadedString);
00246               length = WinLoadString((HAB)0, hmod, 1135, 256, loadedString);
00247               gpszFDFileExists = (char*)malloc(length+1);
00248               strcpy(gpszFDFileExists, loadedString);
00249               length = WinLoadString((HAB)0, hmod, 1136, 256, loadedString);
00250               gpszFDFileReadOnly = (char*)malloc(length+1);
00251               strcpy(gpszFDFileReadOnly, loadedString);
00252               int i;
00253               for (i=0;i<256 && gpszFDFileExists[i];i++ ) {
00254                 if (gpszFDFileExists[i] == '%') {
00255                   gpszFDFileExists[i+1] = 's';
00256                   break;
00257                 }
00258               }
00259               for (i=0;i<256 && gpszFDFileReadOnly[i];i++ ) {
00260                 if (gpszFDFileReadOnly[i] == '%') {
00261                   gpszFDFileReadOnly[i+1] = 's';
00262                   break;
00263                 }
00264               }
00265               DosFreeModule(hmod);
00266 
00267             }
00268             char pszFullText[256+CCHMAXPATH];
00269             FILESTATUS3 fsts3;
00270             ULONG ulResponse;
00271             DosQueryPathInfo( filedlg.szFullFile, FIL_STANDARD, &fsts3, sizeof(FILESTATUS3));
00272             if (fsts3.attrFile & FILE_READONLY) {
00273               sprintf(pszFullText, gpszFDFileReadOnly, filedlg.szFullFile);
00274               ulResponse = WinMessageBox(HWND_DESKTOP, mWnd, pszFullText,
00275                                                gpszFDSaveCaption, 0,
00276                                                MB_OK | MB_MOVEABLE | MB_WARNING);
00277             } else {
00278               sprintf(pszFullText, gpszFDFileExists, filedlg.szFullFile);
00279               ulResponse = WinMessageBox(HWND_DESKTOP, mWnd, pszFullText,
00280                                                gpszFDSaveCaption, 0,
00281                                                MB_YESNO | MB_MOVEABLE | MB_WARNING);
00282             }
00283 
00284             if (ulResponse == MBID_YES) {
00285                fileExists = PR_FALSE;
00286             }
00287          }
00288       }
00289     } while (mMode == modeSave && fileExists && filedlg.lReturn == DID_OK);
00290 
00291     if (filedlg.lReturn == DID_OK) {
00292       result = PR_TRUE;
00293       if (mMode == modeOpenMultiple) {
00294         nsresult rv = NS_NewISupportsArray(getter_AddRefs(mFiles));
00295         NS_ENSURE_SUCCESS(rv,rv);
00296 
00297         if (filedlg.papszFQFilename) {
00298           for (ULONG i=0;i<filedlg.ulFQFCount;i++) {
00299             nsCOMPtr<nsILocalFile> file = do_CreateInstance("@mozilla.org/file/local;1", &rv);
00300             NS_ENSURE_SUCCESS(rv,rv);
00301 
00302             rv = file->InitWithNativePath(nsDependentCString(*(filedlg.papszFQFilename)[i]));
00303             NS_ENSURE_SUCCESS(rv,rv);
00304 
00305             rv = mFiles->AppendElement(file);
00306             NS_ENSURE_SUCCESS(rv,rv);
00307           }
00308           WinFreeFileDlgList(filedlg.papszFQFilename);
00309         } else {
00310           nsCOMPtr<nsILocalFile> file = do_CreateInstance("@mozilla.org/file/local;1", &rv);
00311           NS_ENSURE_SUCCESS(rv,rv);
00312 
00313           rv = file->InitWithNativePath(nsDependentCString(filedlg.szFullFile));
00314           NS_ENSURE_SUCCESS(rv,rv);
00315 
00316           rv = mFiles->AppendElement(file);
00317           NS_ENSURE_SUCCESS(rv,rv);
00318         }
00319       } else {
00320         mFile.Assign(filedlg.szFullFile);
00321       }
00322       mSelectedType = (PRInt16)pmydata->ulCurExt;
00323     }
00324 
00325     for (i = 0; i < mTitles.Count(); i++)
00326     {
00327       nsMemory::Free(*(filedlg.papszITypeList[i]));
00328     }
00329     free(filedlg.papszITypeList);
00330 
00331     for (i = 0; i < mFilters.Count(); i++)
00332     {
00333       nsMemory::Free(*(pmydata->papszIFilterList[i]));
00334     }
00335     free(pmydata->papszIFilterList);
00336     free(pmydata);
00337   }
00338 
00339   if (title)
00340     nsMemory::Free( title );
00341 
00342   if (result) {
00343     PRInt16 returnOKorReplace = returnOK;
00344 
00345     nsresult rv;
00346     // Remember last used directory.
00347     nsCOMPtr<nsILocalFile> file(do_CreateInstance("@mozilla.org/file/local;1", &rv));
00348     NS_ENSURE_SUCCESS(rv, rv);
00349 
00350     file->InitWithNativePath(mFile);
00351     nsCOMPtr<nsIFile> dir;
00352     if (NS_SUCCEEDED(file->GetParent(getter_AddRefs(dir)))) {
00353       nsCOMPtr<nsILocalFile> localDir(do_QueryInterface(dir));
00354       if (localDir) {
00355         nsCAutoString newDir;
00356         localDir->GetNativePath(newDir);
00357         if(!newDir.IsEmpty())
00358           PL_strncpyz(mLastUsedDirectory, newDir.get(), MAX_PATH+1);
00359         // Update mDisplayDirectory with this directory, also.
00360         // Some callers rely on this.
00361         if (!mDisplayDirectory)
00362            mDisplayDirectory = do_CreateInstance("@mozilla.org/file/local;1");
00363         if (mDisplayDirectory)
00364            mDisplayDirectory->InitWithNativePath( nsDependentCString(mLastUsedDirectory) );
00365       }
00366     }
00367 
00368     if (mMode == modeSave) {
00369       // Windows does not return resultReplace,
00370       //   we must check if file already exists
00371       PRBool exists = PR_FALSE;
00372       file->Exists(&exists);
00373       if (exists)
00374         returnOKorReplace = returnReplace;
00375     }
00376     *retval = returnOKorReplace;
00377   }
00378   else {
00379     *retval = returnCancel;
00380   }
00381   return NS_OK;
00382 }
00383 
00384 
00385 
00386 NS_IMETHODIMP nsFilePicker::GetFile(nsILocalFile **aFile)
00387 {
00388   NS_ENSURE_ARG_POINTER(aFile);
00389 
00390   if (mFile.IsEmpty())
00391       return NS_OK;
00392 
00393   nsCOMPtr<nsILocalFile> file(do_CreateInstance("@mozilla.org/file/local;1"));
00394     
00395   NS_ENSURE_TRUE(file, NS_ERROR_FAILURE);
00396 
00397   file->InitWithNativePath(mFile);
00398 
00399   NS_ADDREF(*aFile = file);
00400 
00401   return NS_OK;
00402 }
00403 
00404 //-------------------------------------------------------------------------
00405 NS_IMETHODIMP nsFilePicker::GetFileURL(nsIFileURL **aFileURL)
00406 {
00407   nsCOMPtr<nsILocalFile> file(do_CreateInstance("@mozilla.org/file/local;1"));
00408   NS_ENSURE_TRUE(file, NS_ERROR_FAILURE);
00409   file->InitWithNativePath(mFile);
00410 
00411   nsCOMPtr<nsIURI> uri;
00412   NS_NewFileURI(getter_AddRefs(uri), file);
00413   nsCOMPtr<nsIFileURL> fileURL(do_QueryInterface(uri));
00414   NS_ENSURE_TRUE(fileURL, NS_ERROR_FAILURE);
00415   
00416   NS_ADDREF(*aFileURL = fileURL);
00417 
00418   return NS_OK;
00419 }
00420 
00421 NS_IMETHODIMP nsFilePicker::GetFiles(nsISimpleEnumerator **aFiles)
00422 {
00423   NS_ENSURE_ARG_POINTER(aFiles);
00424   return NS_NewArrayEnumerator(aFiles, mFiles);
00425 }
00426 
00427 //-------------------------------------------------------------------------
00428 //
00429 // Get the file + path
00430 //
00431 //-------------------------------------------------------------------------
00432 NS_IMETHODIMP nsFilePicker::SetDefaultString(const nsAString& aString)
00433 {
00434   mDefault = aString;
00435 
00436   //First, make sure the file name is not too long!
00437   PRInt32 nameLength;
00438   PRInt32 nameIndex = mDefault.RFind("\\");
00439   if (nameIndex == kNotFound)
00440     nameIndex = 0;
00441   else
00442     nameIndex ++;
00443   nameLength = mDefault.Length() - nameIndex;
00444   
00445   if (nameLength > CCHMAXPATH) {
00446     PRInt32 extIndex = mDefault.RFind(".");
00447     if (extIndex == kNotFound)
00448       extIndex = mDefault.Length();
00449 
00450     //Let's try to shave the needed characters from the name part
00451     PRInt32 charsToRemove = nameLength - CCHMAXPATH;
00452     if (extIndex - nameIndex >= charsToRemove) {
00453       mDefault.Cut(extIndex - charsToRemove, charsToRemove);
00454     }
00455   }
00456 
00457   //Then, we need to replace illegal characters.
00458   //Windows has the following statement:
00459   //At this stage, we cannot replace the backslash as the string might represent a file path.
00460   //But it is not correct - Windows assumes this is not a path as well,
00461   //as one of the FILE_ILLEGAL_CHARACTERS is a colon (:)
00462 
00463   mDefault.ReplaceChar("\"", '\'');
00464   mDefault.ReplaceChar("<", '(');
00465   mDefault.ReplaceChar(">", ')');
00466 
00467   mDefault.ReplaceChar(FILE_ILLEGAL_CHARACTERS, '_');
00468 
00469   return NS_OK;
00470 }
00471 
00472 NS_IMETHODIMP nsFilePicker::GetDefaultString(nsAString& aString)
00473 {
00474   return NS_ERROR_FAILURE;
00475 }
00476 
00477 //-------------------------------------------------------------------------
00478 //
00479 // The default extension to use for files
00480 //
00481 //-------------------------------------------------------------------------
00482 NS_IMETHODIMP nsFilePicker::GetDefaultExtension(nsAString& aExtension)
00483 {
00484   aExtension = mDefaultExtension;
00485   return NS_OK;
00486 }
00487 
00488 NS_IMETHODIMP nsFilePicker::SetDefaultExtension(const nsAString& aExtension)
00489 {
00490   mDefaultExtension = aExtension;
00491   return NS_OK;
00492 }
00493 
00494 //-------------------------------------------------------------------------
00495 //
00496 // Set the filter index
00497 //
00498 //-------------------------------------------------------------------------
00499 NS_IMETHODIMP nsFilePicker::GetFilterIndex(PRInt32 *aFilterIndex)
00500 {
00501   *aFilterIndex = mSelectedType;
00502   return NS_OK;
00503 }
00504 
00505 NS_IMETHODIMP nsFilePicker::SetFilterIndex(PRInt32 aFilterIndex)
00506 {
00507   mSelectedType = aFilterIndex;
00508   return NS_OK;
00509 }
00510 
00511 //-------------------------------------------------------------------------
00512 void nsFilePicker::InitNative(nsIWidget *aParent,
00513                               const nsAString& aTitle,
00514                               PRInt16 aMode)
00515 {
00516   mWnd = (HWND) ((aParent) ? aParent->GetNativeData(NS_NATIVE_WINDOW) : 0); 
00517   mTitle.Assign(aTitle);
00518   mMode = aMode;
00519 }
00520 
00521 
00522 //-------------------------------------------------------------------------
00523 void nsFilePicker::GetFileSystemCharset(nsCString & fileSystemCharset)
00524 {
00525   static nsCAutoString aCharset;
00526   nsresult rv;
00527 
00528   if (aCharset.Length() < 1) {
00529     nsCOMPtr <nsIPlatformCharset> platformCharset = do_GetService(NS_PLATFORMCHARSET_CONTRACTID, &rv);
00530          if (NS_SUCCEEDED(rv)) 
00531                 rv = platformCharset->GetCharset(kPlatformCharsetSel_FileName, aCharset);
00532 
00533     NS_ASSERTION(NS_SUCCEEDED(rv), "error getting platform charset");
00534          if (NS_FAILED(rv)) 
00535                 aCharset.AssignLiteral("IBM850");
00536   }
00537   fileSystemCharset = aCharset;
00538 }
00539 
00540 //-------------------------------------------------------------------------
00541 char * nsFilePicker::ConvertToFileSystemCharset(const nsAString& inString)
00542 {
00543   char *outString = nsnull;
00544   nsresult rv = NS_OK;
00545 
00546   // get file system charset and create a unicode encoder
00547   if (nsnull == mUnicodeEncoder) {
00548     nsCAutoString fileSystemCharset;
00549     GetFileSystemCharset(fileSystemCharset);
00550 
00551     nsCOMPtr<nsICharsetConverterManager> ccm = 
00552              do_GetService(kCharsetConverterManagerCID, &rv); 
00553     if (NS_SUCCEEDED(rv)) {
00554       rv = ccm->GetUnicodeEncoderRaw(fileSystemCharset.get(), &mUnicodeEncoder);
00555     }
00556   }
00557 
00558   // converts from unicode to the file system charset
00559   if (NS_SUCCEEDED(rv)) {
00560     PRInt32 inLength = inString.Length();
00561 
00562     const nsAFlatString& flatInString = PromiseFlatString(inString);
00563 
00564     PRInt32 outLength;
00565     rv = mUnicodeEncoder->GetMaxLength(flatInString.get(), inLength,
00566                                        &outLength);
00567     if (NS_SUCCEEDED(rv)) {
00568       outString = NS_STATIC_CAST( char*, nsMemory::Alloc( outLength+1 ) );
00569       if (nsnull == outString) {
00570         return nsnull;
00571       }
00572       rv = mUnicodeEncoder->Convert(flatInString.get(), &inLength, outString,
00573                                     &outLength);
00574       if (NS_SUCCEEDED(rv)) {
00575         outString[outLength] = '\0';
00576       }
00577     }
00578   }
00579   
00580   return NS_SUCCEEDED(rv) ? outString : nsnull;
00581 }
00582 
00583 //-------------------------------------------------------------------------
00584 PRUnichar * nsFilePicker::ConvertFromFileSystemCharset(const char *inString)
00585 {
00586   PRUnichar *outString = nsnull;
00587   nsresult rv = NS_OK;
00588 
00589   // get file system charset and create a unicode encoder
00590   if (nsnull == mUnicodeDecoder) {
00591     nsCAutoString fileSystemCharset;
00592     GetFileSystemCharset(fileSystemCharset);
00593 
00594     nsCOMPtr<nsICharsetConverterManager> ccm = 
00595              do_GetService(kCharsetConverterManagerCID, &rv); 
00596     if (NS_SUCCEEDED(rv)) {
00597       rv = ccm->GetUnicodeDecoderRaw(fileSystemCharset.get(), &mUnicodeDecoder);
00598     }
00599   }
00600 
00601   // converts from the file system charset to unicode
00602   if (NS_SUCCEEDED(rv)) {
00603     PRInt32 inLength = strlen(inString);
00604     PRInt32 outLength;
00605     rv = mUnicodeDecoder->GetMaxLength(inString, inLength, &outLength);
00606     if (NS_SUCCEEDED(rv)) {
00607       outString = NS_STATIC_CAST( PRUnichar*, nsMemory::Alloc( (outLength+1) * sizeof( PRUnichar ) ) );
00608       if (nsnull == outString) {
00609         return nsnull;
00610       }
00611       rv = mUnicodeDecoder->Convert(inString, &inLength, outString, &outLength);
00612       if (NS_SUCCEEDED(rv)) {
00613         outString[outLength] = 0;
00614       }
00615     }
00616   }
00617 
00618   NS_ASSERTION(NS_SUCCEEDED(rv), "error charset conversion");
00619   return NS_SUCCEEDED(rv) ? outString : nsnull;
00620 }
00621 
00622 
00623 NS_IMETHODIMP
00624 nsFilePicker::AppendFilter(const nsAString& aTitle, const nsAString& aFilter)
00625 {
00626   if (aFilter.EqualsLiteral("..apps"))
00627     mFilters.AppendString(NS_LITERAL_STRING("*.exe;*.cmd;*.com;*.bat"));
00628   else
00629     mFilters.AppendString(aFilter);
00630   mTitles.AppendString(aTitle);
00631 
00632   return NS_OK;
00633 }
00634 
00635 MRESULT EXPENTRY DirDialogProc( HWND hwndDlg, ULONG msg, MPARAM mp1, MPARAM mp2)
00636 {
00637    switch ( msg ) {
00638       case WM_INITDLG:
00639          {
00640          SWP swpFileST;
00641          SWP swpDirST;
00642          SWP swpDirLB;
00643          SWP swpDriveST;
00644          SWP swpDriveCB;
00645          SWP swpDriveCBEF;
00646          SWP swpOK;
00647          SWP swpCancel;
00648          HWND hwndFileST;
00649          HWND hwndDirST;
00650          HWND hwndDirLB;
00651          HWND hwndDriveST;
00652          HWND hwndDriveCB;
00653          HWND hwndOK;
00654          HWND hwndCancel;
00655          HENUM henum;
00656          HWND hwndNext;
00657          ULONG ulCurY, ulCurX;
00658          LONG lScreenX, lScreenY, lDlgFrameX, lDlgFrameY, lTitleBarY;
00659 
00660          lScreenX = WinQuerySysValue(HWND_DESKTOP, SV_CXSCREEN);
00661          lScreenY = WinQuerySysValue(HWND_DESKTOP, SV_CYSCREEN);
00662          lDlgFrameX = WinQuerySysValue(HWND_DESKTOP, SV_CXDLGFRAME);
00663          lDlgFrameY = WinQuerySysValue(HWND_DESKTOP, SV_CYDLGFRAME);
00664          lTitleBarY = WinQuerySysValue(HWND_DESKTOP, SV_CYTITLEBAR);
00665 
00666          hwndFileST = WinWindowFromID(hwndDlg, DID_FILENAME_TXT);
00667          hwndDirST = WinWindowFromID(hwndDlg, DID_DIRECTORY_TXT);
00668          hwndDirLB = WinWindowFromID(hwndDlg, DID_DIRECTORY_LB);
00669          hwndDriveST = WinWindowFromID(hwndDlg, DID_DRIVE_TXT);
00670          hwndDriveCB = WinWindowFromID(hwndDlg, DID_DRIVE_CB);
00671          hwndOK = WinWindowFromID(hwndDlg, DID_OK);
00672          hwndCancel = WinWindowFromID(hwndDlg, DID_CANCEL);
00673          
00674 #define SPACING 10
00675          // Reposition drives combobox
00676          ulCurY = SPACING;
00677          ulCurX = SPACING + lDlgFrameX;
00678          WinQueryWindowPos(hwndOK, &swpOK);
00679          WinSetWindowPos(hwndOK, 0, ulCurX, ulCurY, 0, 0, SWP_MOVE);
00680          ulCurY += swpOK.cy + SPACING;
00681          WinQueryWindowPos(hwndCancel, &swpCancel);
00682          WinSetWindowPos(hwndCancel, 0, ulCurX+swpOK.cx+10, SPACING, 0, 0, SWP_MOVE);
00683          WinQueryWindowPos(hwndDirLB, &swpDirLB);
00684          WinSetWindowPos(hwndDirLB, 0, ulCurX, ulCurY, swpDirLB.cx, swpDirLB.cy, SWP_MOVE | SWP_SIZE);
00685          ulCurY += swpDirLB.cy + SPACING;
00686          WinQueryWindowPos(hwndDirST, &swpDirST);
00687          WinSetWindowPos(hwndDirST, 0, ulCurX, ulCurY, swpDirST.cx, swpDirST.cy, SWP_MOVE | SWP_SIZE);
00688          ulCurY += swpDirST.cy + SPACING;
00689          WinQueryWindowPos(hwndDriveCB, &swpDriveCB);
00690          WinQueryWindowPos(WinWindowFromID(hwndDriveCB, CBID_EDIT), &swpDriveCBEF);
00691          WinSetWindowPos(hwndDriveCB, 0, ulCurX, ulCurY-(swpDriveCB.cy-swpDriveCBEF.cy)+5,
00692                                          swpDirLB.cx,
00693                                          swpDriveCB.cy,
00694                                          SWP_SIZE | SWP_MOVE);
00695          ulCurY += swpDriveCBEF.cy + SPACING;
00696          WinQueryWindowPos(hwndDriveST, &swpDriveST);
00697          WinSetWindowPos(hwndDriveST, 0, ulCurX, ulCurY, swpDriveST.cx, swpDriveST.cy, SWP_MOVE | SWP_SIZE);
00698          ulCurY += swpDriveST.cy + SPACING;
00699          WinQueryWindowPos(hwndFileST, &swpFileST);
00700          WinSetWindowPos(hwndFileST, 0, ulCurX, ulCurY, swpFileST.cx, swpFileST.cy, SWP_MOVE | SWP_SIZE);
00701          ulCurY += swpFileST.cy + SPACING;
00702 
00703          // Hide unused stuff
00704          henum = WinBeginEnumWindows(hwndDlg);
00705          while ((hwndNext = WinGetNextWindow(henum)) != NULLHANDLE)
00706          {
00707            USHORT usID = WinQueryWindowUShort(hwndNext, QWS_ID);
00708            if (usID != DID_FILENAME_TXT &&
00709                usID != DID_DIRECTORY_TXT &&
00710                usID != DID_DIRECTORY_LB &&
00711                usID != DID_DRIVE_TXT &&
00712                usID != DID_DRIVE_CB &&
00713                usID != DID_OK &&
00714                usID != DID_CANCEL &&
00715                usID != FID_TITLEBAR &&
00716                usID != FID_SYSMENU &&
00717                usID != FID_MINMAX) 
00718            {
00719              WinShowWindow(hwndNext, FALSE);
00720            }
00721          }
00722 
00723          WinSetWindowPos(hwndDlg,
00724                          HWND_TOP,
00725                          (lScreenX/2)-((swpDirLB.cx+2*SPACING+2*lDlgFrameX)/2),
00726                          (lScreenY/2)-((ulCurY+2*lDlgFrameY+lTitleBarY)/2),
00727                          swpDirLB.cx+2*SPACING+2*lDlgFrameX,
00728                          ulCurY+2*lDlgFrameY+lTitleBarY,
00729                          SWP_MOVE | SWP_SIZE);
00730          }
00731          break;
00732       case WM_CONTROL:
00733          {
00734          PFILEDLG pfiledlg;
00735          pfiledlg = (PFILEDLG)WinQueryWindowPtr(hwndDlg, QWL_USER);
00736 
00737          HPS           hps;
00738          SWP           swp;
00739          HWND          hwndST;
00740          RECTL         rectlString = {0,0,1000,1000};
00741          char          *ptr = NULL;
00742          int           iHalfLen;
00743          int           iLength;
00744          CHAR          szString[CCHMAXPATH];
00745 
00746          hwndST = WinWindowFromID(hwndDlg, DID_FILENAME_TXT);
00747        
00748          strcpy(szString, pfiledlg->szFullFile);
00749          iLength = strlen(pfiledlg->szFullFile);
00750          /* If we are not just a drive */
00751          if (iLength > 3) {
00752            if (szString[iLength-1] == '\\') {
00753              szString[iLength-1] = '\0';
00754              iLength--;
00755            }
00756          }
00757        
00758          hps = WinGetPS(hwndST);
00759          WinQueryWindowPos(hwndST, &swp);
00760        
00761          WinDrawText(hps, iLength, szString,
00762                           &rectlString, 0, 0, 
00763                           DT_BOTTOM | DT_QUERYEXTENT | DT_TEXTATTRS);
00764          while(rectlString.xRight > swp.cx)
00765          {
00766            iHalfLen = iLength / 2;
00767            if(iHalfLen == 2)
00768              break;
00769        
00770            ptr = szString + iHalfLen;
00771            memmove(ptr - 1, ptr, strlen(ptr) + 1);
00772            szString[iHalfLen - 2] = '.';
00773            szString[iHalfLen - 1] = '.';
00774            szString[iHalfLen]     = '.';
00775            iLength = strlen(szString);
00776            rectlString.xLeft = rectlString.yBottom = 0;
00777            rectlString.xRight = rectlString.yTop = 1000;
00778            WinDrawText(hps, iLength, szString,
00779                        &rectlString, 0, 0, 
00780                        DT_BOTTOM | DT_QUERYEXTENT | DT_TEXTATTRS);
00781          }
00782        
00783          WinReleasePS(hps);
00784          WinSetWindowText(hwndST, szString);
00785          }
00786          break;
00787    }      
00788    return WinDefFileDlgProc(hwndDlg, msg, mp1, mp2);
00789 }
00790 
00791 MRESULT EXPENTRY FileDialogProc( HWND hwndDlg, ULONG msg, MPARAM mp1, MPARAM mp2)
00792 {
00793   MRESULT mr;
00794   PFILEDLG pfiledlg;
00795   HWND hwndTypeCombo;
00796   INT i;
00797   SWP swp;
00798   PMYDATA pmydata;
00799 
00800   switch ( msg ) {
00801     case WM_INITDLG:
00802        /* Create another dropdown that we manage */
00803        mr = WinDefFileDlgProc(hwndDlg, msg, mp1, mp2);
00804        hwndTypeCombo = WinWindowFromID(hwndDlg, DID_FILTER_CB);
00805        WinQueryWindowPos(hwndTypeCombo, &swp);
00806        WinSetWindowPos(hwndTypeCombo, NULLHANDLE, 0, 0, 0, 0, SWP_HIDE);
00807        hwndTypeCombo = WinCreateWindow( hwndDlg, WC_COMBOBOX, "",
00808                                         WS_VISIBLE | WS_PARENTCLIP | WS_SYNCPAINT | WS_TABSTOP | CBS_DROPDOWNLIST,
00809                                         swp.x, swp.y,
00810                                         swp.cx, swp.cy, hwndDlg, swp.hwndInsertBehind, 290,
00811                                         NULL, NULL );
00812        WinSendMsg( hwndTypeCombo, LM_DELETEALL, (MPARAM)0, (MPARAM)0 );
00813        pfiledlg = (PFILEDLG)WinQueryWindowULong( hwndDlg, QWL_USER );
00814        pmydata = (PMYDATA)pfiledlg->ulUser;
00815        i = 0;
00816        while (*(pfiledlg->papszITypeList[i]) != NULL) {
00817            WinSendMsg( hwndTypeCombo, LM_INSERTITEM, (MPARAM)LIT_END, (MPARAM)*(pfiledlg->papszITypeList[i]) );
00818            i++;
00819        }
00820        WinSendMsg( hwndTypeCombo, LM_SELECTITEM, (MPARAM)pmydata->ulCurExt, (MPARAM)TRUE );
00821 
00822        return mr;
00823     case WM_CONTROL:
00824        {
00825          if ((SHORT1FROMMP(mp1) == 290) &&
00826            (SHORT2FROMMP(mp1) == CBN_LBSELECT)) {
00827            hwndTypeCombo = WinWindowFromID(hwndDlg, 290);
00828            pfiledlg = (PFILEDLG)WinQueryWindowULong( hwndDlg, QWL_USER );
00829            pmydata = (PMYDATA)pfiledlg->ulUser;
00830            pmydata->ulCurExt = (ULONG)WinSendMsg( hwndTypeCombo, LM_QUERYSELECTION, (MPARAM)LIT_FIRST, (MPARAM)0 );
00831            if (pfiledlg->fl & FDS_OPEN_DIALOG) {
00832              WinSetWindowText(WinWindowFromID(hwndDlg,DID_FILENAME_ED), *(pmydata->papszIFilterList[pmydata->ulCurExt]));
00833              WinSendMsg(WinWindowFromID(hwndDlg,DID_FILENAME_ED), EM_SETSEL, MPFROM2SHORT(0, 32000), (MPARAM)0 );
00834              WinSendMsg(hwndDlg, WM_CONTROL, MPFROM2SHORT(DID_FILTER_CB, CBN_LBSELECT), (MPARAM)0 );
00835            }
00836            return (MRESULT)TRUE;
00837          }
00838        }
00839        break;
00840   }      
00841   return WinDefFileDlgProc(hwndDlg, msg, mp1, mp2);
00842 }