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) 2001
00021  * the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *   Makoto Hamanaka <VYA04230@nifty.com>
00025  *   Paul Ashford <arougthopher@lizardland.net>
00026  *   Sergei Dolgov <sergei_d@fi.tartu.ee>
00027  *
00028  * Alternatively, the contents of this file may be used under the terms of
00029  * either the GNU General Public License Version 2 or later (the "GPL"), or
00030  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00031  * in which case the provisions of the GPL or the LGPL are applicable instead
00032  * of those above. If you wish to allow use of your version of this file only
00033  * under the terms of either the GPL or the LGPL, and not to allow others to
00034  * use your version of this file under the terms of the MPL, indicate your
00035  * decision by deleting the provisions above and replace them with the notice
00036  * and other provisions required by the GPL or the LGPL. If you do not delete
00037  * the provisions above, a recipient may use your version of this file under
00038  * the terms of any one of the MPL, the GPL or the LGPL.
00039  *
00040  * ***** END LICENSE BLOCK ***** */
00041 
00042 #include "nsCOMPtr.h"
00043 #include "nsNetUtil.h"
00044 #include "nsIServiceManager.h"
00045 #include "nsIPlatformCharset.h"
00046 #include "nsFilePicker.h"
00047 #include "nsILocalFile.h"
00048 #include "nsIURL.h"
00049 #include "nsIFileURL.h"
00050 #include "nsIStringBundle.h"
00051 #include "nsReadableUtils.h"
00052 #include "nsEscape.h"
00053 #include "nsEnumeratorUtils.h"
00054 #include "nsString.h"
00055 #include "nsWidgetsCID.h"
00056 #include <Window.h>
00057 #include <View.h>
00058 #include <Button.h>
00059 
00060 static NS_DEFINE_CID(kCharsetConverterManagerCID, NS_ICHARSETCONVERTERMANAGER_CID);
00061 NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
00062 
00063 NS_IMPL_THREADSAFE_ISUPPORTS1(nsFilePicker, nsIFilePicker)
00064 
00065 #ifdef FILEPICKER_SAVE_LAST_DIR
00066 char nsFilePicker::mLastUsedDirectory[B_PATH_NAME_LENGTH+1] = { 0 };
00067 #endif
00068 
00069 
00070 //-------------------------------------------------------------------------
00071 //
00072 // nsFilePicker constructor
00073 //
00074 //-------------------------------------------------------------------------
00075 nsFilePicker::nsFilePicker()
00076               : mParentWindow(nsnull)
00077               , mUnicodeEncoder(nsnull)
00078               , mUnicodeDecoder(nsnull)
00079 {
00080 }
00081 
00082 //-------------------------------------------------------------------------
00083 //
00084 // nsFilePicker destructor
00085 //
00086 //-------------------------------------------------------------------------
00087 nsFilePicker::~nsFilePicker()
00088 {
00089        NS_IF_RELEASE(mUnicodeEncoder);
00090        NS_IF_RELEASE(mUnicodeDecoder);
00091 }
00092 
00093 //-------------------------------------------------------------------------
00094 //
00095 // Show - Display the file dialog
00096 //
00097 //-------------------------------------------------------------------------
00098 NS_IMETHODIMP nsFilePicker::Show(PRInt16 *retval)
00099 {
00100        PRBool result = PR_TRUE;
00101        nsFilePanelBeOS *ppanel;
00102        file_panel_mode panel_mode;
00103        bool allow_multiple_selection = false;
00104        uint32 node_flavors;
00105 
00106        if (mMode == modeGetFolder)
00107        {
00108               node_flavors = B_DIRECTORY_NODE;
00109               panel_mode = B_OPEN_PANEL;
00110        }
00111        else if (mMode == modeOpen)
00112        {
00113               node_flavors = B_FILE_NODE;
00114               panel_mode = B_OPEN_PANEL;
00115        }
00116        else if (mMode == modeOpenMultiple)
00117        {
00118               node_flavors = B_FILE_NODE;
00119               panel_mode = B_OPEN_PANEL;
00120               allow_multiple_selection = true;
00121        }
00122        else if (mMode == modeSave)
00123        {
00124               node_flavors = B_FILE_NODE;
00125               panel_mode = B_SAVE_PANEL;
00126        }
00127        else
00128        {
00129               printf("nsFilePicker::Show() wrong mode");
00130               return PR_FALSE;
00131        }
00132 
00133        ppanel = new nsFilePanelBeOS(
00134                             panel_mode, //file_panel_mode mode
00135                       node_flavors,  //uint32 node_flavors
00136                       allow_multiple_selection,  //bool allow_multiple_selection
00137                       false, //bool modal
00138                       true //bool hide_when_done
00139                             );
00140        if (!ppanel)
00141               return PR_FALSE;
00142        nsCOMPtr<nsIAppShell> appShell(do_CreateInstance(kAppShellCID));
00143        NS_ENSURE_TRUE(appShell, NS_ERROR_FAILURE);
00144        appShell->Create(0, nsnull);
00145        appShell->Spinup();
00146        // set title
00147        if (!mTitle.IsEmpty())
00148        {
00149               char *title_utf8 = ToNewUTF8String(mTitle);
00150               ppanel->Window()->SetTitle(title_utf8);
00151               Recycle(title_utf8);
00152        }
00153 
00154        // set default text
00155        if (!mDefault.IsEmpty() && panel_mode == B_SAVE_PANEL)
00156        {
00157               char *defaultText = ToNewUTF8String(mDefault);
00158               ppanel->SetSaveText(defaultText);
00159               Recycle(defaultText);
00160        }
00161 
00162        // set initial directory
00163        nsCAutoString initialDir;
00164        if (mDisplayDirectory)
00165               mDisplayDirectory->GetNativePath(initialDir);
00166        if(initialDir.IsEmpty())
00167        {
00168 #ifdef FILEPICKER_SAVE_LAST_DIR           
00169               if (strlen(mLastUsedDirectory) < 2)
00170                      initialDir.Assign("/boot/home");
00171               else
00172                      initialDir.Assign(mLastUsedDirectory);
00173 #else
00174               ppanel->SetPanelDirectory(initialDir.get());
00175 #endif               
00176        }
00177 
00178 #ifdef FILEPICKER_SAVE_LAST_DIR
00179        ppanel->SetPanelDirectory(initialDir.get());
00180 #endif
00181 
00182        // set modal feel
00183        if (ppanel->LockLooper())
00184        {
00185               ppanel->Window()->SetFeel(B_MODAL_APP_WINDOW_FEEL);
00186               ppanel->UnlockLooper();
00187        }
00188 
00189        // Show File Panel
00190        ppanel->Show();
00191        while(!ppanel->SelectionDone())
00192        {
00193               void* data;
00194               PRBool isRealEvent;
00195               nsresult rv = NS_OK;
00196               if(mParentWindow)
00197               {
00198                      // flushing pending native drawing
00199                      mParentWindow->UpdateIfNeeded();
00200               }
00201               rv = appShell->GetNativeEvent(isRealEvent, data);
00202               if(NS_SUCCEEDED(rv))
00203               {
00204                      // ModalEventFilter always returns true in our implementation
00205                      // window->ModalEventFilter(isRealEvent, data, &processEvent);
00206                      appShell->DispatchNativeEvent(isRealEvent, data);
00207               }
00208        };
00209 
00210        if (ppanel->IsCancelSelected())
00211               result = PR_FALSE;
00212 
00213        if ((mMode == modeOpen || mMode == modeOpenMultiple || mMode == modeGetFolder) && ppanel->IsOpenSelected())
00214        {
00215               BList *list = ppanel->OpenRefs();
00216               uint32 numfiles = list->CountItems();
00217               if ((list) && numfiles >= 1)
00218               {
00219                      nsresult rv = NS_NewISupportsArray(getter_AddRefs(mFiles));
00220                      for (uint32 i = 0; i< numfiles; i++)
00221                      {
00222                             BPath *path = (BPath *)list->ItemAt(i);
00223 
00224                             if (path->InitCheck() == B_OK)
00225                             {
00226                                    mFile.Truncate();
00227                                    // Single and Multiple are exclusive now, though, maybe there is sense
00228                                    // to assign also first list element to mFile even in openMultiple case ?
00229                                    if (mMode == modeOpenMultiple)
00230                                    {
00231                                           nsCOMPtr<nsILocalFile> file = do_CreateInstance("@mozilla.org/file/local;1", &rv);
00232                                           NS_ENSURE_SUCCESS(rv,rv);
00233                                           rv = file->InitWithNativePath(nsDependentCString(path->Path()));
00234                                           NS_ENSURE_SUCCESS(rv,rv);
00235                                           rv = mFiles->AppendElement(file);
00236                                           NS_ENSURE_SUCCESS(rv,rv);
00237                                    }
00238                                    else
00239                                    {
00240                                           if (i == 0) mFile.Assign(path->Path());
00241                                    }
00242                             }
00243                             else
00244                             {
00245                                    printf("path.init failed \n");
00246                             }
00247                      }
00248               }
00249               else
00250               {
00251                      printf("list not init \n");
00252               }
00253        }
00254        else if (mMode == modeSave && ppanel->IsSaveSelected())
00255        {
00256               BString savefilename = ppanel->SaveFileName();
00257               entry_ref ref = ppanel->SaveDirRef();
00258               BPath path(&ref);
00259               if (path.InitCheck() == B_OK)
00260               {
00261                      path.Append(savefilename.String(), true);
00262                      mFile.Assign(path.Path());
00263               }
00264        }
00265        else
00266        {
00267               result = PR_FALSE;
00268        }
00269 
00270        // set current directory to mDisplayDirectory
00271        entry_ref dir_ref;
00272        ppanel->GetPanelDirectory(&dir_ref);
00273        BEntry dir_entry(&dir_ref);
00274        BPath dir_path;
00275        dir_entry.GetPath(&dir_path);
00276        if (!mDisplayDirectory)
00277               mDisplayDirectory = do_CreateInstance("@mozilla.org/file/local;1");
00278        if (mDisplayDirectory)
00279               mDisplayDirectory->InitWithNativePath(nsDependentCString(dir_path.Path()));
00280 
00281        if (ppanel->Lock())
00282               ppanel->Quit();
00283 
00284        if (result)
00285        {
00286               PRInt16 returnOKorReplace = returnOK;
00287 
00288 #ifdef FILEPICKER_SAVE_LAST_DIR
00289               strncpy(mLastUsedDirectory, dir_path.Path(), B_PATH_NAME_LENGTH+1);
00290               if (mDisplayDirectory)
00291                      mDisplayDirectory->InitWithNativePath( nsDependentCString(mLastUsedDirectory) );
00292 #endif
00293 
00294               if (mMode == modeSave)
00295               {
00296                      //   we must check if file already exists
00297                      PRBool exists = PR_FALSE;
00298                      nsCOMPtr<nsILocalFile> file(do_CreateInstance("@mozilla.org/file/local;1"));
00299                      NS_ENSURE_TRUE(file, NS_ERROR_FAILURE);
00300 
00301                      file->InitWithNativePath(mFile);
00302                      file->Exists(&exists);
00303                      if (exists)
00304                             returnOKorReplace = returnReplace;
00305               }
00306               *retval = returnOKorReplace;
00307        }
00308        else
00309        {
00310               *retval = returnCancel;
00311        }
00312        appShell->Spindown();
00313        return NS_OK;
00314 
00315        // TODO: implement filters
00316 }
00317 
00318 
00319 
00320 NS_IMETHODIMP nsFilePicker::GetFile(nsILocalFile **aFile)
00321 {
00322        NS_ENSURE_ARG_POINTER(aFile);
00323        if (mFile.IsEmpty())
00324               return NS_OK;
00325        nsCOMPtr<nsILocalFile> file(do_CreateInstance("@mozilla.org/file/local;1"));
00326        NS_ENSURE_TRUE(file, NS_ERROR_FAILURE);
00327        file->InitWithNativePath(mFile);
00328 
00329        NS_ADDREF(*aFile = file);
00330 
00331        return NS_OK;
00332 }
00333 
00334 NS_IMETHODIMP nsFilePicker::GetFiles(nsISimpleEnumerator **aFiles)
00335 {
00336        NS_ENSURE_ARG_POINTER(aFiles);
00337        return NS_NewArrayEnumerator(aFiles, mFiles);
00338 }
00339 
00340 //-------------------------------------------------------------------------
00341 
00342 NS_IMETHODIMP nsFilePicker::GetFileURL(nsIFileURL **aFileURL)
00343 {
00344        nsCOMPtr<nsILocalFile> file(do_CreateInstance("@mozilla.org/file/local;1"));
00345        NS_ENSURE_TRUE(file, NS_ERROR_FAILURE);
00346        file->InitWithNativePath(mFile);
00347        nsCOMPtr<nsIURI> uri;
00348        NS_NewFileURI(getter_AddRefs(uri), file);
00349        nsCOMPtr<nsIFileURL> fileURL(do_QueryInterface(uri));
00350        NS_ENSURE_TRUE(fileURL, NS_ERROR_FAILURE);
00351 
00352        NS_ADDREF(*aFileURL = fileURL);
00353 
00354        return NS_OK;
00355 }
00356 
00357 //-------------------------------------------------------------------------
00358 //
00359 // Get the file + path
00360 //
00361 //-------------------------------------------------------------------------
00362 NS_IMETHODIMP nsFilePicker::SetDefaultString(const nsAString& aString)
00363 {
00364        mDefault = aString;
00365        return NS_OK;
00366 }
00367 
00368 NS_IMETHODIMP nsFilePicker::GetDefaultString(nsAString& aString)
00369 {
00370        return NS_ERROR_FAILURE;
00371 }
00372 
00373 //-------------------------------------------------------------------------
00374 //
00375 // The default extension to use for files
00376 //
00377 //-------------------------------------------------------------------------
00378 NS_IMETHODIMP nsFilePicker::GetDefaultExtension(nsAString& aExtension)
00379 {
00380        aExtension.Truncate();
00381        return NS_OK;
00382 }
00383 
00384 NS_IMETHODIMP nsFilePicker::SetDefaultExtension(const nsAString& aExtension)
00385 {
00386        return NS_OK;
00387 }
00388 
00389 //-------------------------------------------------------------------------
00390 void nsFilePicker::InitNative(nsIWidget *aParent,
00391                               const nsAString& aTitle,
00392                               PRInt16 aMode)
00393 {
00394        mParentWindow = 0;
00395 
00396        BView *view = (BView *) aParent->GetNativeData(NS_NATIVE_WIDGET);
00397        if (view && view->LockLooper())
00398        {
00399               mParentWindow = view->Window();
00400               view->UnlockLooper();
00401        }
00402 
00403        mTitle.Assign(aTitle);
00404        mMode = aMode;
00405 }
00406 
00407 NS_IMETHODIMP
00408 nsFilePicker::AppendFilter(const nsAString& aTitle, const nsAString& aFilter)
00409 {
00410        mFilterList.Append(aTitle);
00411        mFilterList.Append(PRUnichar('\0'));
00412        mFilterList.Append(aFilter);
00413        mFilterList.Append(PRUnichar('\0'));
00414 
00415        return NS_OK;
00416 }
00417 
00418 //-------------------------------------------------------------------------
00419 //
00420 // BeOS native File Panel
00421 //
00422 //-------------------------------------------------------------------------
00423 
00424 // Internal message for when the 'Select <dir>' button is used
00425 const uint32 MSG_DIRECTORY = 'mDIR';
00426 
00427 nsFilePanelBeOS::nsFilePanelBeOS(file_panel_mode mode,
00428                                                                uint32 node_flavors,
00429                                                                bool allow_multiple_selection,
00430                                                                bool modal,
00431                                                                bool hide_when_done)
00432                             : BLooper("FilePickerLooper", B_DISPLAY_PRIORITY)
00433                             , BFilePanel(mode,
00434                                                  NULL, NULL,
00435                                                  node_flavors,
00436                                                  allow_multiple_selection,
00437                                                  NULL, NULL,
00438                                                  modal,
00439                                                  hide_when_done)
00440                             , mSelectedActivity(nsFilePanelBeOS::NOT_SELECTED)
00441                             , mIsSelected(false)
00442                             , mSaveFileName("")
00443                             , mSaveDirRef()
00444                             , mOpenRefs()
00445 {
00446        SetTarget(BMessenger(this));
00447 
00448        if ( mode == B_OPEN_PANEL && node_flavors == B_DIRECTORY_NODE ) 
00449        {
00450               // Add a 'Select <dirname>' button to the open dialog
00451               Window()->Lock();
00452 
00453               BView *background = Window()->ChildAt(0); 
00454               entry_ref ref;
00455               char label[10+B_FILE_NAME_LENGTH];
00456               GetPanelDirectory(&ref);
00457               sprintf(label, "Select '%s'", ref.name);
00458               mDirectoryButton = new BButton(
00459                      BRect(113, background->Bounds().bottom-35, 269, background->Bounds().bottom-10),
00460                      "directoryButton", label, new BMessage(MSG_DIRECTORY), B_FOLLOW_LEFT | B_FOLLOW_BOTTOM);
00461 
00462               if(mDirectoryButton)
00463               {
00464                      background->AddChild(mDirectoryButton);
00465                      mDirectoryButton->SetTarget(Messenger());
00466               }
00467               else
00468                      NS_ASSERTION(false, "Out of memory: failed to create mDirectoryButton");
00469 
00470               SetButtonLabel(B_DEFAULT_BUTTON, "Select");
00471 
00472               Window()->Unlock();
00473        }
00474        else 
00475               mDirectoryButton = nsnull;
00476        this->Run();
00477 }
00478 
00479 nsFilePanelBeOS::~nsFilePanelBeOS()
00480 {
00481        int count = mOpenRefs.CountItems();
00482        for (int i=0 ; i<count ; i++)
00483               delete mOpenRefs.ItemAt(i);
00484 }
00485 
00486 void nsFilePanelBeOS::MessageReceived(BMessage *msg)
00487 {
00488        switch ( msg->what )
00489        {
00490        case B_REFS_RECEIVED: // open
00491               int32 count;
00492               type_code code;
00493               msg->GetInfo("refs", &code, &count);
00494               if (code == B_REF_TYPE)
00495               {
00496                      for (int i=0 ; i<count ; i++)
00497                      {
00498                             // XXX change - adding BPaths * to list instead entry_refs,
00499                             // entry_refs are too unsafe objects in our case.
00500                             entry_ref ref;
00501                             if (msg->FindRef("refs", i, &ref) == B_OK)
00502                             {
00503                                    BPath *path = new BPath(&ref);
00504                                    mOpenRefs.AddItem((void *) path);
00505                             }
00506                      }
00507               }
00508               else
00509               {
00510                      printf("nsFilePanelBeOS::MessageReceived() no ref!\n");
00511               }
00512               mSelectedActivity = OPEN_SELECTED;
00513               mIsSelected = true;
00514               break;
00515        
00516        case MSG_DIRECTORY: // Directory selected
00517        {
00518               entry_ref ref;
00519               GetPanelDirectory(&ref);
00520               BPath *path = new BPath(&ref);
00521               mOpenRefs.AddItem((void *) path);
00522               mSelectedActivity = OPEN_SELECTED;
00523               mIsSelected = true;
00524               break;
00525        }
00526 
00527        case B_SAVE_REQUESTED: // save
00528               msg->FindString("name", &mSaveFileName);
00529               msg->FindRef("directory", &mSaveDirRef);
00530               mSelectedActivity = SAVE_SELECTED;
00531               mIsSelected = true;
00532               break;
00533 
00534        case B_CANCEL: // cancel
00535               if (mIsSelected) break;
00536               mSelectedActivity = CANCEL_SELECTED;
00537               mIsSelected = true;
00538               break;
00539        default:
00540               break;
00541        }
00542 }
00543 
00544 bool nsFilePanelBeOS::SelectionDone()
00545 {
00546        return mIsSelected;
00547 }
00548 
00549 uint32 nsFilePanelBeOS::SelectedActivity()
00550 {
00551        uint32 result = 0;
00552        result = mSelectedActivity;
00553 
00554        return result;
00555 }
00556 
00557 void nsFilePanelBeOS::SelectionChanged(void)
00558 {
00559        if(mDirectoryButton)
00560        {
00561               //Update the 'Select <dir>' button
00562               entry_ref ref;
00563               char label[50];
00564               GetPanelDirectory(&ref);
00565               Window()->Lock();
00566               sprintf(label, "Select '%s'", ref.name);
00567               mDirectoryButton->SetLabel(label);
00568               Window()->Unlock();
00569        }
00570        BFilePanel::SelectionChanged();
00571 }