OLD | NEW |
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include <gtk/gtk.h> | 5 #include <gtk/gtk.h> |
6 #include <map> | 6 #include <map> |
7 #include <set> | 7 #include <set> |
8 | 8 |
9 #include "app/l10n_util.h" | 9 #include "app/l10n_util.h" |
10 #include "base/file_util.h" | 10 #include "base/file_util.h" |
11 #include "base/logging.h" | 11 #include "base/logging.h" |
12 #include "base/message_loop.h" | 12 #include "base/message_loop.h" |
13 #include "base/mime_util.h" | 13 #include "base/mime_util.h" |
14 #include "base/thread.h" | |
15 #include "base/string_util.h" | 14 #include "base/string_util.h" |
16 #include "base/sys_string_conversions.h" | 15 #include "base/sys_string_conversions.h" |
| 16 #include "base/thread.h" |
17 #include "chrome/browser/browser_process.h" | 17 #include "chrome/browser/browser_process.h" |
18 #include "chrome/browser/chrome_thread.h" | 18 #include "chrome/browser/chrome_thread.h" |
19 #include "chrome/browser/shell_dialogs.h" | 19 #include "chrome/browser/shell_dialogs.h" |
20 #include "grit/generated_resources.h" | 20 #include "grit/generated_resources.h" |
21 | 21 |
22 // The size of the preview we display for selected image files. We set height | 22 // The size of the preview we display for selected image files. We set height |
23 // larger than width because generally there is more free space vertically | 23 // larger than width because generally there is more free space vertically |
24 // than horiztonally (setting the preview image will alway expand the width of | 24 // than horiztonally (setting the preview image will alway expand the width of |
25 // the dialog, but usually not the height). The image's aspect ratio will always | 25 // the dialog, but usually not the height). The image's aspect ratio will always |
26 // be preserved. | 26 // be preserved. |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
74 GtkWidget* CreateMultiFileOpenDialog(const std::string& title, | 74 GtkWidget* CreateMultiFileOpenDialog(const std::string& title, |
75 const FilePath& default_path, gfx::NativeWindow parent); | 75 const FilePath& default_path, gfx::NativeWindow parent); |
76 | 76 |
77 GtkWidget* CreateSaveAsDialog(const std::string& title, | 77 GtkWidget* CreateSaveAsDialog(const std::string& title, |
78 const FilePath& default_path, gfx::NativeWindow parent); | 78 const FilePath& default_path, gfx::NativeWindow parent); |
79 | 79 |
80 // Removes and returns the |params| associated with |dialog| from | 80 // Removes and returns the |params| associated with |dialog| from |
81 // |params_map_|. | 81 // |params_map_|. |
82 void* PopParamsForDialog(GtkWidget* dialog); | 82 void* PopParamsForDialog(GtkWidget* dialog); |
83 | 83 |
84 // Removes and returns the parent associated with |dialog| from |parents_|. | 84 // Take care of internal data structures when a file dialog is destroyed. |
85 void RemoveParentForDialog(GtkWidget* dialog); | 85 void FileDialogDestroyed(GtkWidget* dialog); |
86 | 86 |
87 // Check whether response_id corresponds to the user cancelling/closing the | 87 // Check whether response_id corresponds to the user cancelling/closing the |
88 // dialog. Used as a helper for the below callbacks. | 88 // dialog. Used as a helper for the below callbacks. |
89 static bool IsCancelResponse(gint response_id); | 89 static bool IsCancelResponse(gint response_id); |
90 | 90 |
91 // Common function for OnSelectSingleFileDialogResponse and | 91 // Common function for OnSelectSingleFileDialogResponse and |
92 // OnSelectSingleFolderDialogResponse. | 92 // OnSelectSingleFolderDialogResponse. |
93 static void SelectSingleFileHelper(GtkWidget* dialog, | 93 static void SelectSingleFileHelper(GtkWidget* dialog, |
94 gint response_id, | 94 gint response_id, |
95 SelectFileDialogImpl* dialog_impl, | 95 SelectFileDialogImpl* dialog_impl, |
96 bool allow_folder); | 96 bool allow_folder); |
97 | 97 |
98 // Callback for when the user responds to a Save As or Open File dialog. | 98 // Callback for when the user responds to a Save As or Open File dialog. |
99 static void OnSelectSingleFileDialogResponse( | 99 static void OnSelectSingleFileDialogResponse( |
100 GtkWidget* dialog, gint response_id, SelectFileDialogImpl* dialog_impl); | 100 GtkWidget* dialog, gint response_id, SelectFileDialogImpl* dialog_impl); |
101 | 101 |
102 // Callback for when the user responds to a Select Folder dialog. | 102 // Callback for when the user responds to a Select Folder dialog. |
103 static void OnSelectSingleFolderDialogResponse( | 103 static void OnSelectSingleFolderDialogResponse( |
104 GtkWidget* dialog, gint response_id, SelectFileDialogImpl* dialog_impl); | 104 GtkWidget* dialog, gint response_id, SelectFileDialogImpl* dialog_impl); |
105 | 105 |
106 // Callback for when the user responds to a Open Multiple Files dialog. | 106 // Callback for when the user responds to a Open Multiple Files dialog. |
107 static void OnSelectMultiFileDialogResponse( | 107 static void OnSelectMultiFileDialogResponse( |
108 GtkWidget* dialog, gint response_id, SelectFileDialogImpl* dialog_impl); | 108 GtkWidget* dialog, gint response_id, SelectFileDialogImpl* dialog_impl); |
109 | 109 |
| 110 // Callback for when the file chooser gets destroyed. |
| 111 static void OnFileChooserDestroy(GtkWidget* dialog, |
| 112 SelectFileDialogImpl* dialog_impl); |
| 113 |
110 // Callback for when we update the preview for the selection. | 114 // Callback for when we update the preview for the selection. |
111 static void OnUpdatePreview(GtkFileChooser* chooser, | 115 static void OnUpdatePreview(GtkFileChooser* chooser, |
112 SelectFileDialogImpl* dialog); | 116 SelectFileDialogImpl* dialog); |
113 | 117 |
114 // The listener to be notified of selection completion. | 118 // The listener to be notified of selection completion. |
115 Listener* listener_; | 119 Listener* listener_; |
116 | 120 |
117 // A map from dialog windows to the |params| user data associated with them. | 121 // A map from dialog windows to the |params| user data associated with them. |
118 std::map<GtkWidget*, void*> params_map_; | 122 std::map<GtkWidget*, void*> params_map_; |
119 | 123 |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
156 | 160 |
157 SelectFileDialogImpl::SelectFileDialogImpl(Listener* listener) | 161 SelectFileDialogImpl::SelectFileDialogImpl(Listener* listener) |
158 : listener_(listener) { | 162 : listener_(listener) { |
159 if (!last_saved_path_) { | 163 if (!last_saved_path_) { |
160 last_saved_path_ = new FilePath(); | 164 last_saved_path_ = new FilePath(); |
161 last_opened_path_ = new FilePath(); | 165 last_opened_path_ = new FilePath(); |
162 } | 166 } |
163 } | 167 } |
164 | 168 |
165 SelectFileDialogImpl::~SelectFileDialogImpl() { | 169 SelectFileDialogImpl::~SelectFileDialogImpl() { |
166 for (std::set<GtkWidget*>::iterator iter = dialogs_.begin(); | 170 while (dialogs_.begin() != dialogs_.end()) { |
167 iter != dialogs_.end(); ++iter) { | 171 gtk_widget_destroy(*(dialogs_.begin())); |
168 gtk_widget_destroy(*iter); | |
169 } | 172 } |
170 } | 173 } |
171 | 174 |
172 bool SelectFileDialogImpl::IsRunning(gfx::NativeWindow parent_window) const { | 175 bool SelectFileDialogImpl::IsRunning(gfx::NativeWindow parent_window) const { |
173 return parents_.find(parent_window) != parents_.end(); | 176 return parents_.find(parent_window) != parents_.end(); |
174 } | 177 } |
175 | 178 |
176 void SelectFileDialogImpl::ListenerDestroyed() { | 179 void SelectFileDialogImpl::ListenerDestroyed() { |
177 listener_ = NULL; | 180 listener_ = NULL; |
178 } | 181 } |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
217 case SELECT_SAVEAS_FILE: | 220 case SELECT_SAVEAS_FILE: |
218 dialog = CreateSaveAsDialog(title_string, default_path, owning_window); | 221 dialog = CreateSaveAsDialog(title_string, default_path, owning_window); |
219 break; | 222 break; |
220 default: | 223 default: |
221 NOTREACHED(); | 224 NOTREACHED(); |
222 return; | 225 return; |
223 } | 226 } |
224 dialogs_.insert(dialog); | 227 dialogs_.insert(dialog); |
225 | 228 |
226 preview_ = gtk_image_new(); | 229 preview_ = gtk_image_new(); |
| 230 g_signal_connect(dialog, "destroy", G_CALLBACK(OnFileChooserDestroy), this); |
227 g_signal_connect(dialog, "update-preview", G_CALLBACK(OnUpdatePreview), this); | 231 g_signal_connect(dialog, "update-preview", G_CALLBACK(OnUpdatePreview), this); |
228 gtk_file_chooser_set_preview_widget(GTK_FILE_CHOOSER(dialog), preview_); | 232 gtk_file_chooser_set_preview_widget(GTK_FILE_CHOOSER(dialog), preview_); |
229 | 233 |
230 params_map_[dialog] = params; | 234 params_map_[dialog] = params; |
231 | 235 |
232 // Set window-to-parent modality by adding the dialog to the same window | 236 // Set window-to-parent modality by adding the dialog to the same window |
233 // group as the parent. | 237 // group as the parent. |
234 gtk_window_group_add_window(gtk_window_get_group(owning_window), | 238 gtk_window_group_add_window(gtk_window_get_group(owning_window), |
235 GTK_WINDOW(dialog)); | 239 GTK_WINDOW(dialog)); |
236 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE); | 240 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE); |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
295 NOTREACHED(); | 299 NOTREACHED(); |
296 | 300 |
297 if (listener_) { | 301 if (listener_) { |
298 GtkFileFilter* selected_filter = | 302 GtkFileFilter* selected_filter = |
299 gtk_file_chooser_get_filter(GTK_FILE_CHOOSER(dialog)); | 303 gtk_file_chooser_get_filter(GTK_FILE_CHOOSER(dialog)); |
300 GSList* filters = gtk_file_chooser_list_filters(GTK_FILE_CHOOSER(dialog)); | 304 GSList* filters = gtk_file_chooser_list_filters(GTK_FILE_CHOOSER(dialog)); |
301 int idx = g_slist_index(filters, selected_filter); | 305 int idx = g_slist_index(filters, selected_filter); |
302 g_slist_free(filters); | 306 g_slist_free(filters); |
303 listener_->FileSelected(path, idx + 1, PopParamsForDialog(dialog)); | 307 listener_->FileSelected(path, idx + 1, PopParamsForDialog(dialog)); |
304 } | 308 } |
305 RemoveParentForDialog(dialog); | |
306 gtk_widget_destroy(dialog); | 309 gtk_widget_destroy(dialog); |
307 dialogs_.erase(dialog); | |
308 } | 310 } |
309 | 311 |
310 void SelectFileDialogImpl::MultiFilesSelected(GtkWidget* dialog, | 312 void SelectFileDialogImpl::MultiFilesSelected(GtkWidget* dialog, |
311 const std::vector<FilePath>& files) { | 313 const std::vector<FilePath>& files) { |
312 *last_opened_path_ = files[0].DirName(); | 314 *last_opened_path_ = files[0].DirName(); |
313 | 315 |
314 if (listener_) | 316 if (listener_) |
315 listener_->MultiFilesSelected(files, PopParamsForDialog(dialog)); | 317 listener_->MultiFilesSelected(files, PopParamsForDialog(dialog)); |
316 RemoveParentForDialog(dialog); | |
317 gtk_widget_destroy(dialog); | 318 gtk_widget_destroy(dialog); |
318 dialogs_.erase(dialog); | |
319 } | 319 } |
320 | 320 |
321 void SelectFileDialogImpl::FileNotSelected(GtkWidget* dialog) { | 321 void SelectFileDialogImpl::FileNotSelected(GtkWidget* dialog) { |
322 void* params = PopParamsForDialog(dialog); | 322 void* params = PopParamsForDialog(dialog); |
323 if (listener_) | 323 if (listener_) |
324 listener_->FileSelectionCanceled(params); | 324 listener_->FileSelectionCanceled(params); |
325 RemoveParentForDialog(dialog); | |
326 gtk_widget_destroy(dialog); | 325 gtk_widget_destroy(dialog); |
327 dialogs_.erase(dialog); | |
328 } | 326 } |
329 | 327 |
330 GtkWidget* SelectFileDialogImpl::CreateSelectFolderDialog( | 328 GtkWidget* SelectFileDialogImpl::CreateSelectFolderDialog( |
331 const std::string& title, | 329 const std::string& title, |
332 const FilePath& default_path, | 330 const FilePath& default_path, |
333 gfx::NativeWindow parent) { | 331 gfx::NativeWindow parent) { |
334 std::string title_string = !title.empty() ? title : | 332 std::string title_string = !title.empty() ? title : |
335 l10n_util::GetStringUTF8(IDS_SELECT_FOLDER_DIALOG_TITLE); | 333 l10n_util::GetStringUTF8(IDS_SELECT_FOLDER_DIALOG_TITLE); |
336 | 334 |
337 GtkWidget* dialog = | 335 GtkWidget* dialog = |
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
444 } | 442 } |
445 | 443 |
446 void* SelectFileDialogImpl::PopParamsForDialog(GtkWidget* dialog) { | 444 void* SelectFileDialogImpl::PopParamsForDialog(GtkWidget* dialog) { |
447 std::map<GtkWidget*, void*>::iterator iter = params_map_.find(dialog); | 445 std::map<GtkWidget*, void*>::iterator iter = params_map_.find(dialog); |
448 DCHECK(iter != params_map_.end()); | 446 DCHECK(iter != params_map_.end()); |
449 void* params = iter->second; | 447 void* params = iter->second; |
450 params_map_.erase(iter); | 448 params_map_.erase(iter); |
451 return params; | 449 return params; |
452 } | 450 } |
453 | 451 |
454 void SelectFileDialogImpl::RemoveParentForDialog(GtkWidget* dialog) { | 452 void SelectFileDialogImpl::FileDialogDestroyed(GtkWidget* dialog) { |
| 453 dialogs_.erase(dialog); |
| 454 |
| 455 // Parent may be NULL on shutdown when AllBrowsersClosed() trigger this |
| 456 // handler after all the browser windows got destroyed. |
455 GtkWindow* parent = gtk_window_get_transient_for(GTK_WINDOW(dialog)); | 457 GtkWindow* parent = gtk_window_get_transient_for(GTK_WINDOW(dialog)); |
456 DCHECK(parent); | 458 if (!parent) |
| 459 return; |
457 std::set<GtkWindow*>::iterator iter = parents_.find(parent); | 460 std::set<GtkWindow*>::iterator iter = parents_.find(parent); |
458 if (iter != parents_.end()) | 461 if (iter != parents_.end()) |
459 parents_.erase(iter); | 462 parents_.erase(iter); |
460 else | 463 else |
461 NOTREACHED(); | 464 NOTREACHED(); |
462 } | 465 } |
463 | 466 |
464 // static | 467 // static |
465 bool SelectFileDialogImpl::IsCancelResponse(gint response_id) { | 468 bool SelectFileDialogImpl::IsCancelResponse(gint response_id) { |
466 bool is_cancel = response_id == GTK_RESPONSE_CANCEL || | 469 bool is_cancel = response_id == GTK_RESPONSE_CANCEL || |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
545 g_slist_free(filenames); | 548 g_slist_free(filenames); |
546 | 549 |
547 if (filenames_fp.empty()) { | 550 if (filenames_fp.empty()) { |
548 dialog_impl->FileNotSelected(dialog); | 551 dialog_impl->FileNotSelected(dialog); |
549 return; | 552 return; |
550 } | 553 } |
551 dialog_impl->MultiFilesSelected(dialog, filenames_fp); | 554 dialog_impl->MultiFilesSelected(dialog, filenames_fp); |
552 } | 555 } |
553 | 556 |
554 // static | 557 // static |
| 558 void SelectFileDialogImpl::OnFileChooserDestroy(GtkWidget* dialog, |
| 559 SelectFileDialogImpl* dialog_impl) { |
| 560 dialog_impl->FileDialogDestroyed(dialog); |
| 561 } |
| 562 |
| 563 // static |
555 void SelectFileDialogImpl::OnUpdatePreview(GtkFileChooser* chooser, | 564 void SelectFileDialogImpl::OnUpdatePreview(GtkFileChooser* chooser, |
556 SelectFileDialogImpl* dialog) { | 565 SelectFileDialogImpl* dialog) { |
557 gchar* filename = gtk_file_chooser_get_preview_filename(chooser); | 566 gchar* filename = gtk_file_chooser_get_preview_filename(chooser); |
558 if (!filename) | 567 if (!filename) |
559 return; | 568 return; |
560 // This will preserve the image's aspect ratio. | 569 // This will preserve the image's aspect ratio. |
561 GdkPixbuf* pixbuf = gdk_pixbuf_new_from_file_at_size(filename, kPreviewWidth, | 570 GdkPixbuf* pixbuf = gdk_pixbuf_new_from_file_at_size(filename, kPreviewWidth, |
562 kPreviewHeight, NULL); | 571 kPreviewHeight, NULL); |
563 g_free(filename); | 572 g_free(filename); |
564 if (pixbuf) { | 573 if (pixbuf) { |
565 gtk_image_set_from_pixbuf(GTK_IMAGE(dialog->preview_), pixbuf); | 574 gtk_image_set_from_pixbuf(GTK_IMAGE(dialog->preview_), pixbuf); |
566 g_object_unref(pixbuf); | 575 g_object_unref(pixbuf); |
567 } | 576 } |
568 gtk_file_chooser_set_preview_widget_active(chooser, pixbuf ? TRUE : FALSE); | 577 gtk_file_chooser_set_preview_widget_active(chooser, pixbuf ? TRUE : FALSE); |
569 } | 578 } |
OLD | NEW |