widget/gtk/nsFilePicker.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 #include "mozilla/Types.h"
michael@0 7
michael@0 8 #include <gtk/gtk.h>
michael@0 9
michael@0 10 #include "nsGtkUtils.h"
michael@0 11 #include "nsIFileURL.h"
michael@0 12 #include "nsIURI.h"
michael@0 13 #include "nsIWidget.h"
michael@0 14 #include "nsIFile.h"
michael@0 15 #include "nsIStringBundle.h"
michael@0 16
michael@0 17 #include "nsArrayEnumerator.h"
michael@0 18 #include "nsMemory.h"
michael@0 19 #include "nsEnumeratorUtils.h"
michael@0 20 #include "nsNetUtil.h"
michael@0 21 #include "nsReadableUtils.h"
michael@0 22 #include "mozcontainer.h"
michael@0 23
michael@0 24 #include "nsFilePicker.h"
michael@0 25
michael@0 26 using namespace mozilla;
michael@0 27
michael@0 28 #define MAX_PREVIEW_SIZE 180
michael@0 29
michael@0 30 nsIFile *nsFilePicker::mPrevDisplayDirectory = nullptr;
michael@0 31
michael@0 32 void
michael@0 33 nsFilePicker::Shutdown()
michael@0 34 {
michael@0 35 NS_IF_RELEASE(mPrevDisplayDirectory);
michael@0 36 }
michael@0 37
michael@0 38 static GtkFileChooserAction
michael@0 39 GetGtkFileChooserAction(int16_t aMode)
michael@0 40 {
michael@0 41 GtkFileChooserAction action;
michael@0 42
michael@0 43 switch (aMode) {
michael@0 44 case nsIFilePicker::modeSave:
michael@0 45 action = GTK_FILE_CHOOSER_ACTION_SAVE;
michael@0 46 break;
michael@0 47
michael@0 48 case nsIFilePicker::modeGetFolder:
michael@0 49 action = GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER;
michael@0 50 break;
michael@0 51
michael@0 52 case nsIFilePicker::modeOpen:
michael@0 53 case nsIFilePicker::modeOpenMultiple:
michael@0 54 action = GTK_FILE_CHOOSER_ACTION_OPEN;
michael@0 55 break;
michael@0 56
michael@0 57 default:
michael@0 58 NS_WARNING("Unknown nsIFilePicker mode");
michael@0 59 action = GTK_FILE_CHOOSER_ACTION_OPEN;
michael@0 60 break;
michael@0 61 }
michael@0 62
michael@0 63 return action;
michael@0 64 }
michael@0 65
michael@0 66
michael@0 67 static void
michael@0 68 UpdateFilePreviewWidget(GtkFileChooser *file_chooser,
michael@0 69 gpointer preview_widget_voidptr)
michael@0 70 {
michael@0 71 GtkImage *preview_widget = GTK_IMAGE(preview_widget_voidptr);
michael@0 72 char *image_filename = gtk_file_chooser_get_preview_filename(file_chooser);
michael@0 73
michael@0 74 if (!image_filename) {
michael@0 75 gtk_file_chooser_set_preview_widget_active(file_chooser, FALSE);
michael@0 76 return;
michael@0 77 }
michael@0 78
michael@0 79 gint preview_width = 0;
michael@0 80 gint preview_height = 0;
michael@0 81 GdkPixbufFormat *preview_format = gdk_pixbuf_get_file_info(image_filename,
michael@0 82 &preview_width,
michael@0 83 &preview_height);
michael@0 84 if (!preview_format) {
michael@0 85 g_free(image_filename);
michael@0 86 gtk_file_chooser_set_preview_widget_active(file_chooser, FALSE);
michael@0 87 return;
michael@0 88 }
michael@0 89
michael@0 90 GdkPixbuf *preview_pixbuf;
michael@0 91 // Only scale down images that are too big
michael@0 92 if (preview_width > MAX_PREVIEW_SIZE || preview_height > MAX_PREVIEW_SIZE) {
michael@0 93 preview_pixbuf = gdk_pixbuf_new_from_file_at_size(image_filename,
michael@0 94 MAX_PREVIEW_SIZE,
michael@0 95 MAX_PREVIEW_SIZE,
michael@0 96 nullptr);
michael@0 97 }
michael@0 98 else {
michael@0 99 preview_pixbuf = gdk_pixbuf_new_from_file(image_filename, nullptr);
michael@0 100 }
michael@0 101
michael@0 102 g_free(image_filename);
michael@0 103
michael@0 104 if (!preview_pixbuf) {
michael@0 105 gtk_file_chooser_set_preview_widget_active(file_chooser, FALSE);
michael@0 106 return;
michael@0 107 }
michael@0 108
michael@0 109 #if GTK_CHECK_VERSION(2,12,0)
michael@0 110 GdkPixbuf *preview_pixbuf_temp = preview_pixbuf;
michael@0 111 preview_pixbuf = gdk_pixbuf_apply_embedded_orientation(preview_pixbuf_temp);
michael@0 112 g_object_unref(preview_pixbuf_temp);
michael@0 113 #endif
michael@0 114
michael@0 115 // This is the easiest way to do center alignment without worrying about containers
michael@0 116 // Minimum 3px padding each side (hence the 6) just to make things nice
michael@0 117 gint x_padding = (MAX_PREVIEW_SIZE + 6 - gdk_pixbuf_get_width(preview_pixbuf)) / 2;
michael@0 118 gtk_misc_set_padding(GTK_MISC(preview_widget), x_padding, 0);
michael@0 119
michael@0 120 gtk_image_set_from_pixbuf(preview_widget, preview_pixbuf);
michael@0 121 g_object_unref(preview_pixbuf);
michael@0 122 gtk_file_chooser_set_preview_widget_active(file_chooser, TRUE);
michael@0 123 }
michael@0 124
michael@0 125 static nsAutoCString
michael@0 126 MakeCaseInsensitiveShellGlob(const char* aPattern) {
michael@0 127 // aPattern is UTF8
michael@0 128 nsAutoCString result;
michael@0 129 unsigned int len = strlen(aPattern);
michael@0 130
michael@0 131 for (unsigned int i = 0; i < len; i++) {
michael@0 132 if (!g_ascii_isalpha(aPattern[i])) {
michael@0 133 // non-ASCII characters will also trigger this path, so unicode
michael@0 134 // is safely handled albeit case-sensitively
michael@0 135 result.Append(aPattern[i]);
michael@0 136 continue;
michael@0 137 }
michael@0 138
michael@0 139 // add the lowercase and uppercase version of a character to a bracket
michael@0 140 // match, so it matches either the lowercase or uppercase char.
michael@0 141 result.Append('[');
michael@0 142 result.Append(g_ascii_tolower(aPattern[i]));
michael@0 143 result.Append(g_ascii_toupper(aPattern[i]));
michael@0 144 result.Append(']');
michael@0 145
michael@0 146 }
michael@0 147
michael@0 148 return result;
michael@0 149 }
michael@0 150
michael@0 151 NS_IMPL_ISUPPORTS(nsFilePicker, nsIFilePicker)
michael@0 152
michael@0 153 nsFilePicker::nsFilePicker()
michael@0 154 : mSelectedType(0),
michael@0 155 mRunning(false),
michael@0 156 mAllowURLs(false)
michael@0 157 {
michael@0 158 }
michael@0 159
michael@0 160 nsFilePicker::~nsFilePicker()
michael@0 161 {
michael@0 162 }
michael@0 163
michael@0 164 void
michael@0 165 ReadMultipleFiles(gpointer filename, gpointer array)
michael@0 166 {
michael@0 167 nsCOMPtr<nsIFile> localfile;
michael@0 168 nsresult rv = NS_NewNativeLocalFile(nsDependentCString(static_cast<char*>(filename)),
michael@0 169 false,
michael@0 170 getter_AddRefs(localfile));
michael@0 171 if (NS_SUCCEEDED(rv)) {
michael@0 172 nsCOMArray<nsIFile>& files = *static_cast<nsCOMArray<nsIFile>*>(array);
michael@0 173 files.AppendObject(localfile);
michael@0 174 }
michael@0 175
michael@0 176 g_free(filename);
michael@0 177 }
michael@0 178
michael@0 179 void
michael@0 180 nsFilePicker::ReadValuesFromFileChooser(GtkWidget *file_chooser)
michael@0 181 {
michael@0 182 mFiles.Clear();
michael@0 183
michael@0 184 if (mMode == nsIFilePicker::modeOpenMultiple) {
michael@0 185 mFileURL.Truncate();
michael@0 186
michael@0 187 GSList *list = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(file_chooser));
michael@0 188 g_slist_foreach(list, ReadMultipleFiles, static_cast<gpointer>(&mFiles));
michael@0 189 g_slist_free(list);
michael@0 190 } else {
michael@0 191 gchar *filename = gtk_file_chooser_get_uri(GTK_FILE_CHOOSER(file_chooser));
michael@0 192 mFileURL.Assign(filename);
michael@0 193 g_free(filename);
michael@0 194 }
michael@0 195
michael@0 196 GtkFileFilter *filter = gtk_file_chooser_get_filter(GTK_FILE_CHOOSER(file_chooser));
michael@0 197 GSList *filter_list = gtk_file_chooser_list_filters(GTK_FILE_CHOOSER(file_chooser));
michael@0 198
michael@0 199 mSelectedType = static_cast<int16_t>(g_slist_index(filter_list, filter));
michael@0 200 g_slist_free(filter_list);
michael@0 201
michael@0 202 // Remember last used directory.
michael@0 203 nsCOMPtr<nsIFile> file;
michael@0 204 GetFile(getter_AddRefs(file));
michael@0 205 if (file) {
michael@0 206 nsCOMPtr<nsIFile> dir;
michael@0 207 file->GetParent(getter_AddRefs(dir));
michael@0 208 if (dir) {
michael@0 209 dir.swap(mPrevDisplayDirectory);
michael@0 210 }
michael@0 211 }
michael@0 212 }
michael@0 213
michael@0 214 void
michael@0 215 nsFilePicker::InitNative(nsIWidget *aParent,
michael@0 216 const nsAString& aTitle)
michael@0 217 {
michael@0 218 mParentWidget = aParent;
michael@0 219 mTitle.Assign(aTitle);
michael@0 220 }
michael@0 221
michael@0 222 NS_IMETHODIMP
michael@0 223 nsFilePicker::AppendFilters(int32_t aFilterMask)
michael@0 224 {
michael@0 225 mAllowURLs = !!(aFilterMask & filterAllowURLs);
michael@0 226 return nsBaseFilePicker::AppendFilters(aFilterMask);
michael@0 227 }
michael@0 228
michael@0 229 NS_IMETHODIMP
michael@0 230 nsFilePicker::AppendFilter(const nsAString& aTitle, const nsAString& aFilter)
michael@0 231 {
michael@0 232 if (aFilter.EqualsLiteral("..apps")) {
michael@0 233 // No platform specific thing we can do here, really....
michael@0 234 return NS_OK;
michael@0 235 }
michael@0 236
michael@0 237 nsAutoCString filter, name;
michael@0 238 CopyUTF16toUTF8(aFilter, filter);
michael@0 239 CopyUTF16toUTF8(aTitle, name);
michael@0 240
michael@0 241 mFilters.AppendElement(filter);
michael@0 242 mFilterNames.AppendElement(name);
michael@0 243
michael@0 244 return NS_OK;
michael@0 245 }
michael@0 246
michael@0 247 NS_IMETHODIMP
michael@0 248 nsFilePicker::SetDefaultString(const nsAString& aString)
michael@0 249 {
michael@0 250 mDefault = aString;
michael@0 251
michael@0 252 return NS_OK;
michael@0 253 }
michael@0 254
michael@0 255 NS_IMETHODIMP
michael@0 256 nsFilePicker::GetDefaultString(nsAString& aString)
michael@0 257 {
michael@0 258 // Per API...
michael@0 259 return NS_ERROR_FAILURE;
michael@0 260 }
michael@0 261
michael@0 262 NS_IMETHODIMP
michael@0 263 nsFilePicker::SetDefaultExtension(const nsAString& aExtension)
michael@0 264 {
michael@0 265 mDefaultExtension = aExtension;
michael@0 266
michael@0 267 return NS_OK;
michael@0 268 }
michael@0 269
michael@0 270 NS_IMETHODIMP
michael@0 271 nsFilePicker::GetDefaultExtension(nsAString& aExtension)
michael@0 272 {
michael@0 273 aExtension = mDefaultExtension;
michael@0 274
michael@0 275 return NS_OK;
michael@0 276 }
michael@0 277
michael@0 278 NS_IMETHODIMP
michael@0 279 nsFilePicker::GetFilterIndex(int32_t *aFilterIndex)
michael@0 280 {
michael@0 281 *aFilterIndex = mSelectedType;
michael@0 282
michael@0 283 return NS_OK;
michael@0 284 }
michael@0 285
michael@0 286 NS_IMETHODIMP
michael@0 287 nsFilePicker::SetFilterIndex(int32_t aFilterIndex)
michael@0 288 {
michael@0 289 mSelectedType = aFilterIndex;
michael@0 290
michael@0 291 return NS_OK;
michael@0 292 }
michael@0 293
michael@0 294 NS_IMETHODIMP
michael@0 295 nsFilePicker::GetFile(nsIFile **aFile)
michael@0 296 {
michael@0 297 NS_ENSURE_ARG_POINTER(aFile);
michael@0 298
michael@0 299 *aFile = nullptr;
michael@0 300 nsCOMPtr<nsIURI> uri;
michael@0 301 nsresult rv = GetFileURL(getter_AddRefs(uri));
michael@0 302 if (!uri)
michael@0 303 return rv;
michael@0 304
michael@0 305 nsCOMPtr<nsIFileURL> fileURL(do_QueryInterface(uri, &rv));
michael@0 306 NS_ENSURE_SUCCESS(rv, rv);
michael@0 307
michael@0 308 nsCOMPtr<nsIFile> file;
michael@0 309 rv = fileURL->GetFile(getter_AddRefs(file));
michael@0 310 NS_ENSURE_SUCCESS(rv, rv);
michael@0 311
michael@0 312 file.forget(aFile);
michael@0 313 return NS_OK;
michael@0 314 }
michael@0 315
michael@0 316 NS_IMETHODIMP
michael@0 317 nsFilePicker::GetFileURL(nsIURI **aFileURL)
michael@0 318 {
michael@0 319 *aFileURL = nullptr;
michael@0 320 return NS_NewURI(aFileURL, mFileURL);
michael@0 321 }
michael@0 322
michael@0 323 NS_IMETHODIMP
michael@0 324 nsFilePicker::GetFiles(nsISimpleEnumerator **aFiles)
michael@0 325 {
michael@0 326 NS_ENSURE_ARG_POINTER(aFiles);
michael@0 327
michael@0 328 if (mMode == nsIFilePicker::modeOpenMultiple) {
michael@0 329 return NS_NewArrayEnumerator(aFiles, mFiles);
michael@0 330 }
michael@0 331
michael@0 332 return NS_ERROR_FAILURE;
michael@0 333 }
michael@0 334
michael@0 335 NS_IMETHODIMP
michael@0 336 nsFilePicker::Show(int16_t *aReturn)
michael@0 337 {
michael@0 338 NS_ENSURE_ARG_POINTER(aReturn);
michael@0 339
michael@0 340 nsresult rv = Open(nullptr);
michael@0 341 if (NS_FAILED(rv))
michael@0 342 return rv;
michael@0 343
michael@0 344 while (mRunning) {
michael@0 345 g_main_context_iteration(nullptr, TRUE);
michael@0 346 }
michael@0 347
michael@0 348 *aReturn = mResult;
michael@0 349 return NS_OK;
michael@0 350 }
michael@0 351
michael@0 352 NS_IMETHODIMP
michael@0 353 nsFilePicker::Open(nsIFilePickerShownCallback *aCallback)
michael@0 354 {
michael@0 355 // Can't show two dialogs concurrently with the same filepicker
michael@0 356 if (mRunning)
michael@0 357 return NS_ERROR_NOT_AVAILABLE;
michael@0 358
michael@0 359 nsXPIDLCString title;
michael@0 360 title.Adopt(ToNewUTF8String(mTitle));
michael@0 361
michael@0 362 GtkWindow *parent_widget =
michael@0 363 GTK_WINDOW(mParentWidget->GetNativeData(NS_NATIVE_SHELLWIDGET));
michael@0 364
michael@0 365 GtkFileChooserAction action = GetGtkFileChooserAction(mMode);
michael@0 366 const gchar *accept_button = (action == GTK_FILE_CHOOSER_ACTION_SAVE)
michael@0 367 ? GTK_STOCK_SAVE : GTK_STOCK_OPEN;
michael@0 368 GtkWidget *file_chooser =
michael@0 369 gtk_file_chooser_dialog_new(title, parent_widget, action,
michael@0 370 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
michael@0 371 accept_button, GTK_RESPONSE_ACCEPT,
michael@0 372 nullptr);
michael@0 373 gtk_dialog_set_alternative_button_order(GTK_DIALOG(file_chooser),
michael@0 374 GTK_RESPONSE_ACCEPT,
michael@0 375 GTK_RESPONSE_CANCEL,
michael@0 376 -1);
michael@0 377 if (mAllowURLs) {
michael@0 378 gtk_file_chooser_set_local_only(GTK_FILE_CHOOSER(file_chooser), FALSE);
michael@0 379 }
michael@0 380
michael@0 381 if (action == GTK_FILE_CHOOSER_ACTION_OPEN || action == GTK_FILE_CHOOSER_ACTION_SAVE) {
michael@0 382 GtkWidget *img_preview = gtk_image_new();
michael@0 383 gtk_file_chooser_set_preview_widget(GTK_FILE_CHOOSER(file_chooser), img_preview);
michael@0 384 g_signal_connect(file_chooser, "update-preview", G_CALLBACK(UpdateFilePreviewWidget), img_preview);
michael@0 385 }
michael@0 386
michael@0 387 GtkWindow *window = GTK_WINDOW(file_chooser);
michael@0 388 gtk_window_set_modal(window, TRUE);
michael@0 389 if (parent_widget) {
michael@0 390 gtk_window_set_destroy_with_parent(window, TRUE);
michael@0 391 }
michael@0 392
michael@0 393 NS_ConvertUTF16toUTF8 defaultName(mDefault);
michael@0 394 switch (mMode) {
michael@0 395 case nsIFilePicker::modeOpenMultiple:
michael@0 396 gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(file_chooser), TRUE);
michael@0 397 break;
michael@0 398 case nsIFilePicker::modeSave:
michael@0 399 gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(file_chooser),
michael@0 400 defaultName.get());
michael@0 401 break;
michael@0 402 }
michael@0 403
michael@0 404 nsCOMPtr<nsIFile> defaultPath;
michael@0 405 if (mDisplayDirectory) {
michael@0 406 mDisplayDirectory->Clone(getter_AddRefs(defaultPath));
michael@0 407 } else if (mPrevDisplayDirectory) {
michael@0 408 mPrevDisplayDirectory->Clone(getter_AddRefs(defaultPath));
michael@0 409 }
michael@0 410
michael@0 411 if (defaultPath) {
michael@0 412 if (!defaultName.IsEmpty() && mMode != nsIFilePicker::modeSave) {
michael@0 413 // Try to select the intended file. Even if it doesn't exist, GTK still switches
michael@0 414 // directories.
michael@0 415 defaultPath->AppendNative(defaultName);
michael@0 416 nsAutoCString path;
michael@0 417 defaultPath->GetNativePath(path);
michael@0 418 gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(file_chooser), path.get());
michael@0 419 } else {
michael@0 420 nsAutoCString directory;
michael@0 421 defaultPath->GetNativePath(directory);
michael@0 422 gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(file_chooser),
michael@0 423 directory.get());
michael@0 424 }
michael@0 425 }
michael@0 426
michael@0 427 gtk_dialog_set_default_response(GTK_DIALOG(file_chooser), GTK_RESPONSE_ACCEPT);
michael@0 428
michael@0 429 int32_t count = mFilters.Length();
michael@0 430 for (int32_t i = 0; i < count; ++i) {
michael@0 431 // This is fun... the GTK file picker does not accept a list of filters
michael@0 432 // so we need to split out each string, and add it manually.
michael@0 433
michael@0 434 char **patterns = g_strsplit(mFilters[i].get(), ";", -1);
michael@0 435 if (!patterns) {
michael@0 436 return NS_ERROR_OUT_OF_MEMORY;
michael@0 437 }
michael@0 438
michael@0 439 GtkFileFilter *filter = gtk_file_filter_new();
michael@0 440 for (int j = 0; patterns[j] != nullptr; ++j) {
michael@0 441 nsAutoCString caseInsensitiveFilter = MakeCaseInsensitiveShellGlob(g_strstrip(patterns[j]));
michael@0 442 gtk_file_filter_add_pattern(filter, caseInsensitiveFilter.get());
michael@0 443 }
michael@0 444
michael@0 445 g_strfreev(patterns);
michael@0 446
michael@0 447 if (!mFilterNames[i].IsEmpty()) {
michael@0 448 // If we have a name for our filter, let's use that.
michael@0 449 const char *filter_name = mFilterNames[i].get();
michael@0 450 gtk_file_filter_set_name(filter, filter_name);
michael@0 451 } else {
michael@0 452 // If we don't have a name, let's just use the filter pattern.
michael@0 453 const char *filter_pattern = mFilters[i].get();
michael@0 454 gtk_file_filter_set_name(filter, filter_pattern);
michael@0 455 }
michael@0 456
michael@0 457 gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(file_chooser), filter);
michael@0 458
michael@0 459 // Set the initially selected filter
michael@0 460 if (mSelectedType == i) {
michael@0 461 gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(file_chooser), filter);
michael@0 462 }
michael@0 463 }
michael@0 464
michael@0 465 gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(file_chooser), TRUE);
michael@0 466
michael@0 467 mRunning = true;
michael@0 468 mCallback = aCallback;
michael@0 469 NS_ADDREF_THIS();
michael@0 470 g_signal_connect(file_chooser, "response", G_CALLBACK(OnResponse), this);
michael@0 471 g_signal_connect(file_chooser, "destroy", G_CALLBACK(OnDestroy), this);
michael@0 472 gtk_widget_show(file_chooser);
michael@0 473
michael@0 474 return NS_OK;
michael@0 475 }
michael@0 476
michael@0 477 /* static */ void
michael@0 478 nsFilePicker::OnResponse(GtkWidget* file_chooser, gint response_id,
michael@0 479 gpointer user_data)
michael@0 480 {
michael@0 481 static_cast<nsFilePicker*>(user_data)->
michael@0 482 Done(file_chooser, response_id);
michael@0 483 }
michael@0 484
michael@0 485 /* static */ void
michael@0 486 nsFilePicker::OnDestroy(GtkWidget* file_chooser, gpointer user_data)
michael@0 487 {
michael@0 488 static_cast<nsFilePicker*>(user_data)->
michael@0 489 Done(file_chooser, GTK_RESPONSE_CANCEL);
michael@0 490 }
michael@0 491
michael@0 492 void
michael@0 493 nsFilePicker::Done(GtkWidget* file_chooser, gint response)
michael@0 494 {
michael@0 495 mRunning = false;
michael@0 496
michael@0 497 int16_t result;
michael@0 498 switch (response) {
michael@0 499 case GTK_RESPONSE_OK:
michael@0 500 case GTK_RESPONSE_ACCEPT:
michael@0 501 ReadValuesFromFileChooser(file_chooser);
michael@0 502 result = nsIFilePicker::returnOK;
michael@0 503 if (mMode == nsIFilePicker::modeSave) {
michael@0 504 nsCOMPtr<nsIFile> file;
michael@0 505 GetFile(getter_AddRefs(file));
michael@0 506 if (file) {
michael@0 507 bool exists = false;
michael@0 508 file->Exists(&exists);
michael@0 509 if (exists)
michael@0 510 result = nsIFilePicker::returnReplace;
michael@0 511 }
michael@0 512 }
michael@0 513 break;
michael@0 514
michael@0 515 case GTK_RESPONSE_CANCEL:
michael@0 516 case GTK_RESPONSE_CLOSE:
michael@0 517 case GTK_RESPONSE_DELETE_EVENT:
michael@0 518 result = nsIFilePicker::returnCancel;
michael@0 519 break;
michael@0 520
michael@0 521 default:
michael@0 522 NS_WARNING("Unexpected response");
michael@0 523 result = nsIFilePicker::returnCancel;
michael@0 524 break;
michael@0 525 }
michael@0 526
michael@0 527 // A "response" signal won't be sent again but "destroy" will be.
michael@0 528 g_signal_handlers_disconnect_by_func(file_chooser,
michael@0 529 FuncToGpointer(OnDestroy), this);
michael@0 530
michael@0 531 // When response_id is GTK_RESPONSE_DELETE_EVENT or when called from
michael@0 532 // OnDestroy, the widget would be destroyed anyway but it is fine if
michael@0 533 // gtk_widget_destroy is called more than once. gtk_widget_destroy has
michael@0 534 // requests that any remaining references be released, but the reference
michael@0 535 // count will not be decremented again if GtkWindow's reference has already
michael@0 536 // been released.
michael@0 537 gtk_widget_destroy(file_chooser);
michael@0 538
michael@0 539 if (mCallback) {
michael@0 540 mCallback->Done(result);
michael@0 541 mCallback = nullptr;
michael@0 542 } else {
michael@0 543 mResult = result;
michael@0 544 }
michael@0 545 NS_RELEASE_THIS();
michael@0 546 }

mercurial