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 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is the Mozilla GTK2 File Chooser.
00016  *
00017  * The Initial Developer of the Original Code is Red Hat, Inc.
00018  * Portions created by the Initial Developer are Copyright (C) 2004
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *   Christopher Aillon <caillon@redhat.com>
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 #include <gtk/gtkwindow.h>
00039 #include <gtk/gtkdialog.h>
00040 #include <gtk/gtkstock.h>
00041 #include <gtk/gtkmessagedialog.h>
00042 
00043 #include "nsIFileURL.h"
00044 #include "nsIURI.h"
00045 #include "nsIWidget.h"
00046 #include "nsILocalFile.h"
00047 #include "nsIStringBundle.h"
00048 
00049 #include "nsArrayEnumerator.h"
00050 #include "nsMemory.h"
00051 #include "nsEnumeratorUtils.h"
00052 #include "nsNetUtil.h"
00053 #include "nsReadableUtils.h"
00054 #include "mozcontainer.h"
00055 
00056 #include "prmem.h"
00057 #include "prlink.h"
00058 
00059 #include "nsFilePicker.h"
00060 
00061 #define DECL_FUNC_PTR(func) static _##func##_fn _##func
00062 #define GTK_FILE_CHOOSER(widget) ((GtkFileChooser*) widget)
00063 
00064 PRLibrary    *nsFilePicker::mGTK24 = nsnull;
00065 nsILocalFile *nsFilePicker::mPrevDisplayDirectory = nsnull;
00066 
00067 // XXX total ass.  We should really impose a build-time requirement on gtk2.4
00068 // and then check at run-time whether the user is actually running gtk2.4.
00069 // We should then decide to load the component (or not) from the component mgr.
00070 // We don't really have a mechanism to do that, though....
00071 
00072 typedef struct _GtkFileChooser GtkFileChooser;
00073 typedef struct _GtkFileFilter GtkFileFilter;
00074 
00075 /* Copied from gtkfilechooser.h */
00076 typedef enum
00077 {
00078   GTK_FILE_CHOOSER_ACTION_OPEN,
00079   GTK_FILE_CHOOSER_ACTION_SAVE,
00080   GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
00081   GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER
00082 } GtkFileChooserAction;
00083 
00084 
00085 typedef gchar* (*_gtk_file_chooser_get_filename_fn)(GtkFileChooser *chooser);
00086 typedef GSList* (*_gtk_file_chooser_get_filenames_fn)(GtkFileChooser *chooser);
00087 typedef GtkWidget* (*_gtk_file_chooser_dialog_new_fn)(const gchar *title,
00088                                                       GtkWindow *parent,
00089                                                       GtkFileChooserAction action,
00090                                                       const gchar *first_button_text,
00091                                                       ...);
00092 typedef void (*_gtk_file_chooser_set_select_multiple_fn)(GtkFileChooser* chooser, gboolean truth);
00093 typedef void (*_gtk_file_chooser_set_do_overwrite_confirmation_fn)(GtkFileChooser* chooser, gboolean do_confirm);
00094 typedef void (*_gtk_file_chooser_set_current_name_fn)(GtkFileChooser* chooser, const gchar* name);
00095 typedef void (*_gtk_file_chooser_set_current_folder_fn)(GtkFileChooser* chooser, const gchar* folder);
00096 typedef void (*_gtk_file_chooser_add_filter_fn)(GtkFileChooser* chooser, GtkFileFilter* filter);
00097 typedef void (*_gtk_file_chooser_set_filter_fn)(GtkFileChooser* chooser, GtkFileFilter* filter);
00098 typedef GtkFileFilter* (*_gtk_file_chooser_get_filter_fn)(GtkFileChooser* chooser);
00099 typedef GSList* (*_gtk_file_chooser_list_filters_fn)(GtkFileChooser* chooser);
00100 typedef GtkFileFilter* (*_gtk_file_filter_new_fn)();
00101 typedef void (*_gtk_file_filter_add_pattern_fn)(GtkFileFilter* filter, const gchar* pattern);
00102 typedef void (*_gtk_file_filter_set_name_fn)(GtkFileFilter* filter, const gchar* name);
00103 
00104 
00105 DECL_FUNC_PTR(gtk_file_chooser_get_filename);
00106 DECL_FUNC_PTR(gtk_file_chooser_get_filenames);
00107 DECL_FUNC_PTR(gtk_file_chooser_dialog_new);
00108 DECL_FUNC_PTR(gtk_file_chooser_set_select_multiple);
00109 DECL_FUNC_PTR(gtk_file_chooser_set_do_overwrite_confirmation);
00110 DECL_FUNC_PTR(gtk_file_chooser_set_current_name);
00111 DECL_FUNC_PTR(gtk_file_chooser_set_current_folder);
00112 DECL_FUNC_PTR(gtk_file_chooser_add_filter);
00113 DECL_FUNC_PTR(gtk_file_chooser_set_filter);
00114 DECL_FUNC_PTR(gtk_file_chooser_get_filter);
00115 DECL_FUNC_PTR(gtk_file_chooser_list_filters);
00116 DECL_FUNC_PTR(gtk_file_filter_new);
00117 DECL_FUNC_PTR(gtk_file_filter_add_pattern);
00118 DECL_FUNC_PTR(gtk_file_filter_set_name);
00119 
00120 static GtkWindow *
00121 get_gtk_window_for_nsiwidget(nsIWidget *widget)
00122 {
00123   // Get native GdkWindow
00124   GdkWindow *gdk_win = GDK_WINDOW(widget->GetNativeData(NS_NATIVE_WIDGET));
00125   if (!gdk_win)
00126     return NULL;
00127 
00128   // Get the container
00129   gpointer user_data = NULL;
00130   gdk_window_get_user_data(gdk_win, &user_data);
00131   if (!user_data)
00132     return NULL;
00133 
00134   // Make sure its really a container
00135   MozContainer *parent_container = MOZ_CONTAINER(user_data);
00136   if (!parent_container)
00137     return NULL;
00138 
00139   // Get its toplevel
00140   return GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(parent_container)));
00141 }
00142 
00143 static PRLibrary *
00144 LoadVersionedLibrary(const char* libName, const char* libVersion)
00145 {
00146   char *platformLibName = PR_GetLibraryName(nsnull, libName);
00147   nsCAutoString versionLibName(platformLibName);
00148   versionLibName.Append(libVersion);
00149   PR_FreeLibraryName(platformLibName);
00150   return PR_LoadLibrary(versionLibName.get());
00151 }
00152 
00153 /* static */
00154 nsresult
00155 nsFilePicker::LoadSymbolsGTK24()
00156 {
00157   static PRBool initialized;
00158   if (initialized) {
00159     return NS_OK;
00160   }
00161 
00162   #define GET_LIBGTK_FUNC_BASE(func, onerr)                  \
00163     PR_BEGIN_MACRO \
00164     _##func = (_##func##_fn) PR_FindFunctionSymbol(mGTK24, #func); \
00165     if (!_##func) { \
00166       NS_WARNING("Can't load gtk symbol " #func); \
00167       onerr \
00168     } \
00169     PR_END_MACRO
00170 
00171   #define GET_LIBGTK_FUNC(func) \
00172     GET_LIBGTK_FUNC_BASE(func, return NS_ERROR_NOT_AVAILABLE;)
00173 
00174   #define GET_LIBGTK_FUNC_OPT(func) \
00175     GET_LIBGTK_FUNC_BASE(func, ;)
00176 
00177   PRFuncPtr func = PR_FindFunctionSymbolAndLibrary("gtk_file_chooser_get_filename",
00178                                                    &mGTK24);
00179   if (mGTK24) {
00180     _gtk_file_chooser_get_filename = (_gtk_file_chooser_get_filename_fn)func;
00181   } else {
00182     // XXX hmm, this seems to fail when gtk 2.4 is already loaded...
00183     mGTK24 = LoadVersionedLibrary("gtk-2", ".4");
00184     if (!mGTK24) {
00185       return NS_ERROR_NOT_AVAILABLE;
00186     }
00187     GET_LIBGTK_FUNC(gtk_file_chooser_get_filename);
00188   }
00189 
00190   GET_LIBGTK_FUNC(gtk_file_chooser_get_filenames);
00191   GET_LIBGTK_FUNC(gtk_file_chooser_dialog_new);
00192   GET_LIBGTK_FUNC(gtk_file_chooser_set_select_multiple);
00193   GET_LIBGTK_FUNC_OPT(gtk_file_chooser_set_do_overwrite_confirmation);
00194   GET_LIBGTK_FUNC(gtk_file_chooser_set_current_name);
00195   GET_LIBGTK_FUNC(gtk_file_chooser_set_current_folder);
00196   GET_LIBGTK_FUNC(gtk_file_chooser_add_filter);
00197   GET_LIBGTK_FUNC(gtk_file_chooser_set_filter);
00198   GET_LIBGTK_FUNC(gtk_file_chooser_get_filter);
00199   GET_LIBGTK_FUNC(gtk_file_chooser_list_filters);
00200   GET_LIBGTK_FUNC(gtk_file_filter_new);
00201   GET_LIBGTK_FUNC(gtk_file_filter_add_pattern);
00202   GET_LIBGTK_FUNC(gtk_file_filter_set_name);
00203 
00204   initialized = PR_TRUE;
00205 
00206   // Woot.
00207   return NS_OK;
00208 }
00209 
00210 void
00211 nsFilePicker::Shutdown()
00212 {
00213   if (mGTK24) {
00214     PR_UnloadLibrary(mGTK24);
00215     mGTK24 = nsnull;
00216   }
00217 
00218   NS_IF_RELEASE(mPrevDisplayDirectory);
00219 }
00220 
00221 // Ok, lib loading crap is done... the real code starts here:
00222 
00223 static GtkFileChooserAction
00224 GetGtkFileChooserAction(PRInt16 aMode)
00225 {
00226   GtkFileChooserAction action;
00227 
00228   switch (aMode) {
00229     case nsIFilePicker::modeSave:
00230     action = GTK_FILE_CHOOSER_ACTION_SAVE;
00231     break;
00232 
00233     case nsIFilePicker::modeGetFolder:
00234     action = GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER;
00235     break;
00236 
00237     default:
00238     NS_WARNING("Unknown nsIFilePicker mode");
00239     // fall through
00240 
00241     case nsIFilePicker::modeOpen:
00242     case nsIFilePicker::modeOpenMultiple:
00243     action = GTK_FILE_CHOOSER_ACTION_OPEN;
00244     break;
00245   }
00246 
00247   return action;
00248 }
00249 
00250 
00251 NS_IMPL_ISUPPORTS1(nsFilePicker, nsIFilePicker)
00252 
00253 nsFilePicker::nsFilePicker()
00254   : mMode(nsIFilePicker::modeOpen),
00255     mSelectedType(0)
00256 {
00257 }
00258 
00259 nsFilePicker::~nsFilePicker()
00260 {
00261 }
00262 
00263 void
00264 ReadMultipleFiles(gpointer filename, gpointer array)
00265 {
00266   nsCOMPtr<nsILocalFile> localfile;
00267   nsresult rv = NS_NewNativeLocalFile(nsDependentCString(NS_STATIC_CAST(char*, filename)),
00268                                       PR_FALSE,
00269                                       getter_AddRefs(localfile));
00270   if (NS_SUCCEEDED(rv)) {
00271     nsCOMArray<nsILocalFile>& files = *NS_STATIC_CAST(nsCOMArray<nsILocalFile>*, array);
00272     files.AppendObject(localfile);
00273   }
00274 
00275   g_free(filename);
00276 }
00277 
00278 void
00279 nsFilePicker::ReadValuesFromFileChooser(GtkWidget *file_chooser)
00280 {
00281   mFiles.Clear();
00282 
00283   if (mMode == nsIFilePicker::modeOpenMultiple) {
00284     mFile.Truncate();
00285 
00286     GSList *list = _gtk_file_chooser_get_filenames (GTK_FILE_CHOOSER(file_chooser));
00287     g_slist_foreach(list, ReadMultipleFiles, NS_STATIC_CAST(gpointer, &mFiles));
00288     g_slist_free(list);
00289   } else {
00290     gchar *filename = _gtk_file_chooser_get_filename (GTK_FILE_CHOOSER(file_chooser));
00291     mFile.Assign(filename);
00292     g_free(filename);
00293   }
00294 
00295   GtkFileFilter *filter = _gtk_file_chooser_get_filter (GTK_FILE_CHOOSER(file_chooser));
00296   GSList *filter_list = _gtk_file_chooser_list_filters (GTK_FILE_CHOOSER(file_chooser));
00297 
00298   mSelectedType = NS_STATIC_CAST(PRInt16, g_slist_index (filter_list, filter));
00299   g_slist_free(filter_list);
00300 
00301   // Remember last used directory.
00302   nsCOMPtr<nsILocalFile> file;
00303   GetFile(getter_AddRefs(file));
00304   if (file) {
00305     nsCOMPtr<nsIFile> dir;
00306     file->GetParent(getter_AddRefs(dir));
00307     nsCOMPtr<nsILocalFile> localDir(do_QueryInterface(dir));
00308     if (localDir) {
00309       localDir.swap(mPrevDisplayDirectory);
00310     }
00311   }
00312 }
00313 
00314 NS_IMETHODIMP
00315 nsFilePicker::Init(nsIDOMWindow *aParent, const nsAString &aTitle, PRInt16 aMode)
00316 {
00317   nsresult rv = LoadSymbolsGTK24();
00318   if (NS_FAILED(rv)) {
00319     return rv;
00320   }
00321 
00322   return nsBaseFilePicker::Init(aParent, aTitle, aMode);
00323 }
00324 
00325 void
00326 nsFilePicker::InitNative(nsIWidget *aParent,
00327                          const nsAString& aTitle,
00328                          PRInt16 aMode)
00329 {
00330   mParentWidget = aParent;
00331   mTitle.Assign(aTitle);
00332   mMode = aMode;
00333 }
00334 
00335 NS_IMETHODIMP
00336 nsFilePicker::AppendFilters(PRInt32 aFilterMask)
00337 {
00338   return nsBaseFilePicker::AppendFilters(aFilterMask);
00339 }
00340 
00341 NS_IMETHODIMP
00342 nsFilePicker::AppendFilter(const nsAString& aTitle, const nsAString& aFilter)
00343 {
00344   if (aFilter.EqualsLiteral("..apps")) {
00345     // No platform specific thing we can do here, really....
00346     return NS_OK;
00347   }
00348 
00349   nsCAutoString filter, name;
00350   CopyUTF16toUTF8(aFilter, filter);
00351   CopyUTF16toUTF8(aTitle, name);
00352 
00353   mFilters.AppendCString(filter);
00354   mFilterNames.AppendCString(name);
00355 
00356   return NS_OK;
00357 }
00358 
00359 NS_IMETHODIMP
00360 nsFilePicker::SetDefaultString(const nsAString& aString)
00361 {
00362   mDefault = aString;
00363 
00364   return NS_OK;
00365 }
00366 
00367 NS_IMETHODIMP
00368 nsFilePicker::GetDefaultString(nsAString& aString)
00369 {
00370   // Per API...
00371   return NS_ERROR_FAILURE;
00372 }
00373 
00374 NS_IMETHODIMP
00375 nsFilePicker::SetDefaultExtension(const nsAString& aExtension)
00376 {
00377   mDefaultExtension = aExtension;
00378 
00379   return NS_OK;
00380 }
00381 
00382 NS_IMETHODIMP
00383 nsFilePicker::GetDefaultExtension(nsAString& aExtension)
00384 {
00385   aExtension = mDefaultExtension;
00386 
00387   return NS_OK;
00388 }
00389 
00390 NS_IMETHODIMP
00391 nsFilePicker::GetFilterIndex(PRInt32 *aFilterIndex)
00392 {
00393   *aFilterIndex = mSelectedType;
00394 
00395   return NS_OK;
00396 }
00397 
00398 NS_IMETHODIMP
00399 nsFilePicker::SetFilterIndex(PRInt32 aFilterIndex)
00400 {
00401   mSelectedType = aFilterIndex;
00402 
00403   return NS_OK;
00404 }
00405 
00406 NS_IMETHODIMP
00407 nsFilePicker::GetFile(nsILocalFile **aFile)
00408 {
00409   NS_ENSURE_ARG_POINTER(aFile);
00410 
00411   *aFile = nsnull;
00412   if (mFile.IsEmpty()) {
00413     return NS_OK;
00414   }
00415 
00416   nsCOMPtr<nsILocalFile> file(do_CreateInstance("@mozilla.org/file/local;1"));
00417   NS_ENSURE_TRUE(file, NS_ERROR_FAILURE);
00418 
00419   file->InitWithNativePath(mFile);
00420 
00421   NS_ADDREF(*aFile = file);
00422 
00423   return NS_OK;
00424 }
00425 
00426 NS_IMETHODIMP
00427 nsFilePicker::GetFileURL(nsIFileURL **aFileURL)
00428 {
00429   nsCOMPtr<nsILocalFile> file;
00430   GetFile(getter_AddRefs(file));
00431 
00432   nsCOMPtr<nsIURI> uri;
00433   NS_NewFileURI(getter_AddRefs(uri), file);
00434   NS_ENSURE_TRUE(uri, NS_ERROR_FAILURE);
00435 
00436   return CallQueryInterface(uri, aFileURL);
00437 }
00438 
00439 NS_IMETHODIMP
00440 nsFilePicker::GetFiles(nsISimpleEnumerator **aFiles)
00441 {
00442   NS_ENSURE_ARG_POINTER(aFiles);
00443 
00444   if (mMode == nsIFilePicker::modeOpenMultiple) {
00445     return NS_NewArrayEnumerator(aFiles, mFiles);
00446   }
00447 
00448   return NS_ERROR_FAILURE;
00449 }
00450 
00451 PRBool
00452 confirm_overwrite_file (GtkWidget *parent, nsILocalFile* file)
00453 {
00454   nsCOMPtr<nsIStringBundleService> sbs = do_GetService(NS_STRINGBUNDLE_CONTRACTID);
00455   nsCOMPtr<nsIStringBundle> bundle;
00456   nsresult rv = sbs->CreateBundle("chrome://global/locale/filepicker.properties",
00457                                   getter_AddRefs(bundle));
00458   if (NS_FAILED(rv)) {
00459     return PR_FALSE;
00460   }
00461 
00462   nsAutoString leafName;
00463   file->GetLeafName(leafName);
00464   const PRUnichar *formatStrings[] =
00465   {
00466     leafName.get()
00467   };
00468 
00469   nsXPIDLString title, message;
00470   bundle->GetStringFromName(NS_LITERAL_STRING("confirmTitle").get(),
00471                             getter_Copies(title));
00472   bundle->FormatStringFromName(NS_LITERAL_STRING("confirmFileReplacing").get(),
00473                                formatStrings, NS_ARRAY_LENGTH(formatStrings),
00474                                getter_Copies(message));
00475 
00476   GtkWindow *parent_window = GTK_WINDOW(parent);
00477   GtkWidget *dialog;
00478   
00479   dialog = gtk_message_dialog_new(parent_window,
00480                                   GTK_DIALOG_DESTROY_WITH_PARENT,
00481                                   GTK_MESSAGE_QUESTION,
00482                                   GTK_BUTTONS_YES_NO,
00483                                   NS_ConvertUTF16toUTF8(message).get());
00484   gtk_window_set_title(GTK_WINDOW(dialog), NS_ConvertUTF16toUTF8(title).get());
00485   if (parent_window && parent_window->group) {
00486     gtk_window_group_add_window(parent_window->group, GTK_WINDOW(dialog));
00487   }
00488 
00489   PRBool result = (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_YES);
00490   gtk_widget_destroy (dialog);
00491 
00492   return result;
00493 }
00494 
00495 NS_IMETHODIMP
00496 nsFilePicker::Show(PRInt16 *aReturn)
00497 {
00498   NS_ENSURE_ARG_POINTER(aReturn);
00499 
00500   nsXPIDLCString title;
00501   title.Adopt(ToNewUTF8String(mTitle));
00502 
00503   GtkWindow *parent_widget = get_gtk_window_for_nsiwidget(mParentWidget);
00504 
00505   GtkFileChooserAction action = GetGtkFileChooserAction(mMode);
00506   const gchar *accept_button = (mMode == GTK_FILE_CHOOSER_ACTION_SAVE)
00507                                ? GTK_STOCK_SAVE : GTK_STOCK_OPEN;
00508   GtkWidget *file_chooser =
00509       _gtk_file_chooser_dialog_new(title, parent_widget, action,
00510                                    GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
00511                                    accept_button, GTK_RESPONSE_ACCEPT,
00512                                    NULL);
00513 
00514   if (parent_widget && parent_widget->group) {
00515     gtk_window_group_add_window(parent_widget->group, GTK_WINDOW(file_chooser));
00516   }
00517 
00518   if (mMode == nsIFilePicker::modeOpenMultiple) {
00519     _gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER(file_chooser), TRUE);
00520   } else if (mMode == nsIFilePicker::modeSave) {
00521     char *default_filename = ToNewUTF8String(mDefault);
00522     _gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(file_chooser),
00523                                        NS_STATIC_CAST(const gchar*, default_filename));
00524     nsMemory::Free(default_filename);
00525   }
00526 
00527   gtk_dialog_set_default_response(GTK_DIALOG(file_chooser), GTK_RESPONSE_ACCEPT);
00528 
00529   nsCAutoString directory;
00530   if (mDisplayDirectory) {
00531     mDisplayDirectory->GetNativePath(directory);
00532   } else if (mPrevDisplayDirectory) {
00533     mPrevDisplayDirectory->GetNativePath(directory);
00534   }
00535 
00536   if (!directory.IsEmpty()) {
00537     _gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(file_chooser),
00538                                          directory.get());
00539   }
00540 
00541   PRInt32 count = mFilters.Count();
00542   for (PRInt32 i = 0; i < count; ++i) {
00543     // This is fun... the GTK file picker does not accept a list of filters
00544     // so we need to split out each string, and add it manually.
00545 
00546     char **patterns = g_strsplit(mFilters[i]->get(), ";", -1);
00547     if (!patterns) {
00548       return NS_ERROR_OUT_OF_MEMORY;
00549     }
00550 
00551     GtkFileFilter *filter = _gtk_file_filter_new ();
00552     for (int j = 0; patterns[j] != NULL; ++j) {
00553       _gtk_file_filter_add_pattern (filter, g_strstrip (patterns[j]));
00554     }
00555 
00556     g_strfreev(patterns);
00557 
00558     if (!mFilterNames[i]->IsEmpty()) {
00559       // If we have a name for our filter, let's use that.
00560       const char *filter_name = mFilterNames[i]->get();
00561       _gtk_file_filter_set_name (filter, filter_name);
00562     } else {
00563       // If we don't have a name, let's just use the filter pattern.
00564       const char *filter_pattern = mFilters[i]->get();
00565       _gtk_file_filter_set_name (filter, filter_pattern);
00566     }
00567 
00568     _gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (file_chooser), filter);
00569 
00570     // Set the initially selected filter
00571     if (mSelectedType == i) {
00572       _gtk_file_chooser_set_filter (GTK_FILE_CHOOSER(file_chooser), filter);
00573     }
00574   }
00575 
00576   PRBool checkForOverwrite = PR_TRUE;
00577   if (_gtk_file_chooser_set_do_overwrite_confirmation) {
00578     checkForOverwrite = PR_FALSE;
00579     // Only available in GTK 2.8
00580     _gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(file_chooser), PR_TRUE);
00581   }
00582 
00583   gint response = gtk_dialog_run (GTK_DIALOG (file_chooser));
00584 
00585   switch (response) {
00586     case GTK_RESPONSE_ACCEPT:
00587     ReadValuesFromFileChooser(file_chooser);
00588     *aReturn = nsIFilePicker::returnOK;
00589     if (mMode == nsIFilePicker::modeSave) {
00590       nsCOMPtr<nsILocalFile> file;
00591       GetFile(getter_AddRefs(file));
00592       if (file) {
00593         PRBool exists = PR_FALSE;
00594         file->Exists(&exists);
00595         if (exists) {
00596           PRBool overwrite = !checkForOverwrite ||
00597             confirm_overwrite_file (file_chooser, file);
00598 
00599           if (overwrite) {
00600             *aReturn = nsIFilePicker::returnReplace;
00601           } else {
00602             *aReturn = nsIFilePicker::returnCancel;
00603           }
00604         }
00605       }
00606     }
00607     break;
00608 
00609     case GTK_RESPONSE_CANCEL:
00610     case GTK_RESPONSE_CLOSE:
00611     case GTK_RESPONSE_DELETE_EVENT:
00612     *aReturn = nsIFilePicker::returnCancel;
00613     break;
00614 
00615     default:
00616     NS_WARNING("Unexpected response");
00617     *aReturn = nsIFilePicker::returnCancel;
00618     break;
00619   }
00620 
00621   gtk_widget_destroy(file_chooser);
00622 
00623   return NS_OK;
00624 }