| 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 "chrome/browser/app_modal_dialog.h" | 5 #include "chrome/browser/app_modal_dialog.h" |
| 6 | 6 |
| 7 #include "chrome/browser/app_modal_dialog_queue.h" | 7 #include "chrome/browser/app_modal_dialog_queue.h" |
| 8 #include "chrome/browser/extensions/extension_host.h" | |
| 9 #include "chrome/browser/tab_contents/tab_contents.h" | 8 #include "chrome/browser/tab_contents/tab_contents.h" |
| 10 #include "chrome/common/notification_service.h" | 9 #include "chrome/common/notification_service.h" |
| 11 #include "chrome/common/notification_type.h" | 10 #include "chrome/common/notification_type.h" |
| 12 #include "ipc/ipc_message.h" | |
| 13 | 11 |
| 14 AppModalDialog::AppModalDialog(JavaScriptMessageBoxClient* client, | 12 AppModalDialog::AppModalDialog(TabContents* tab_contents, |
| 15 const std::wstring& title, | 13 const std::wstring& title) |
| 16 int dialog_flags, | |
| 17 const std::wstring& message_text, | |
| 18 const std::wstring& default_prompt_text, | |
| 19 bool display_suppress_checkbox, | |
| 20 bool is_before_unload_dialog, | |
| 21 IPC::Message* reply_msg) | |
| 22 : dialog_(NULL), | 14 : dialog_(NULL), |
| 23 client_(client), | 15 tab_contents_(tab_contents), |
| 24 tab_contents_(client_->AsTabContents()), | |
| 25 extension_host_(client_->AsExtensionHost()), | |
| 26 skip_this_dialog_(false), | |
| 27 title_(title), | 16 title_(title), |
| 28 dialog_flags_(dialog_flags), | 17 skip_this_dialog_(false) { |
| 29 message_text_(message_text), | |
| 30 default_prompt_text_(default_prompt_text), | |
| 31 display_suppress_checkbox_(display_suppress_checkbox), | |
| 32 is_before_unload_dialog_(is_before_unload_dialog), | |
| 33 reply_msg_(reply_msg) { | |
| 34 InitNotifications(); | |
| 35 DCHECK((tab_contents_ != NULL) != (extension_host_ != NULL)); | |
| 36 } | 18 } |
| 37 | 19 |
| 38 void AppModalDialog::Observe(NotificationType type, | |
| 39 const NotificationSource& source, | |
| 40 const NotificationDetails& details) { | |
| 41 if (skip_this_dialog_) | |
| 42 return; | |
| 43 | |
| 44 if (NotificationType::EXTENSION_HOST_DESTROYED == type && | |
| 45 Details<ExtensionHost>(extension_host_) != details) | |
| 46 return; | |
| 47 | |
| 48 // If we reach here, we know the notification is relevant to us, either | |
| 49 // because we're only observing applicable sources or because we passed the | |
| 50 // check above. Both of those indicate that we should ignore this dialog. | |
| 51 // Also clear the client, since it's now invalid. | |
| 52 skip_this_dialog_ = true; | |
| 53 client_ = NULL; | |
| 54 CloseModalDialog(); | |
| 55 } | |
| 56 | |
| 57 void AppModalDialog::InitNotifications() { | |
| 58 // Make sure we get relevant navigation notifications so we know when our | |
| 59 // parent contents will disappear or navigate to a different page. | |
| 60 if (tab_contents_) { | |
| 61 registrar_.Add(this, NotificationType::NAV_ENTRY_COMMITTED, | |
| 62 Source<NavigationController>(&tab_contents_->controller())); | |
| 63 registrar_.Add(this, NotificationType::TAB_CONTENTS_DESTROYED, | |
| 64 Source<TabContents>(tab_contents_)); | |
| 65 } else if (extension_host_) { | |
| 66 // EXTENSION_HOST_DESTROYED uses the Profile as its source, but we care | |
| 67 // about the ExtensionHost (which is passed in the details). | |
| 68 registrar_.Add(this, NotificationType::EXTENSION_HOST_DESTROYED, | |
| 69 NotificationService::AllSources()); | |
| 70 } else { | |
| 71 NOTREACHED(); | |
| 72 } | |
| 73 } | |
| 74 | 20 |
| 75 void AppModalDialog::ShowModalDialog() { | 21 void AppModalDialog::ShowModalDialog() { |
| 76 // If the TabContents or ExtensionHost that created this dialog navigated | 22 // If the TabContents or ExtensionHost that created this dialog navigated |
| 77 // away or was destroyed before this dialog became visible, simply show the | 23 // away or was destroyed before this dialog became visible, simply show the |
| 78 // next dialog if any. | 24 // next dialog if any. |
| 79 if (skip_this_dialog_) { | 25 if (skip_this_dialog_) { |
| 80 Singleton<AppModalDialogQueue>()->ShowNextDialog(); | 26 Singleton<AppModalDialogQueue>()->ShowNextDialog(); |
| 81 delete this; | 27 delete this; |
| 82 return; | 28 return; |
| 83 } | 29 } |
| 84 if (tab_contents_) | 30 if (tab_contents_) |
| 85 tab_contents_->Activate(); | 31 tab_contents_->Activate(); |
| 86 | 32 |
| 87 CreateAndShowDialog(); | 33 CreateAndShowDialog(); |
| 88 | 34 |
| 89 NotificationService::current()->Notify( | 35 NotificationService::current()->Notify( |
| 90 NotificationType::APP_MODAL_DIALOG_SHOWN, | 36 NotificationType::APP_MODAL_DIALOG_SHOWN, |
| 91 Source<AppModalDialog>(this), | 37 Source<AppModalDialog>(this), |
| 92 NotificationService::NoDetails()); | 38 NotificationService::NoDetails()); |
| 93 } | 39 } |
| 94 | 40 |
| 95 void AppModalDialog::OnCancel() { | 41 void AppModalDialog::Cleanup() { |
| 96 // We need to do this before WM_DESTROY (WindowClosing()) as any parent frame | 42 NotificationService::current()->Notify( |
| 97 // will receive its activation messages before this dialog receives | 43 NotificationType::APP_MODAL_DIALOG_CLOSED, |
| 98 // WM_DESTROY. The parent frame would then try to activate any modal dialogs | 44 Source<AppModalDialog>(this), |
| 99 // that were still open in the ModalDialogQueue, which would send activation | 45 NotificationService::NoDetails()); |
| 100 // back to this one. The framework should be improved to handle this, so this | |
| 101 // is a temporary workaround. | |
| 102 Singleton<AppModalDialogQueue>()->ShowNextDialog(); | |
| 103 | |
| 104 if (!skip_this_dialog_) { | |
| 105 client_->OnMessageBoxClosed(reply_msg_, false, std::wstring()); | |
| 106 } | |
| 107 | |
| 108 Cleanup(); | |
| 109 } | 46 } |
| 110 | 47 |
| 111 void AppModalDialog::OnAccept(const std::wstring& prompt_text, | 48 void AppModalDialog::CompleteDialog() { |
| 112 bool suppress_js_messages) { | |
| 113 Singleton<AppModalDialogQueue>()->ShowNextDialog(); | 49 Singleton<AppModalDialogQueue>()->ShowNextDialog(); |
| 114 | |
| 115 if (!skip_this_dialog_) { | |
| 116 client_->OnMessageBoxClosed(reply_msg_, true, prompt_text); | |
| 117 if (suppress_js_messages) | |
| 118 client_->SetSuppressMessageBoxes(true); | |
| 119 } | |
| 120 | |
| 121 Cleanup(); | |
| 122 } | 50 } |
| 123 | 51 |
| 124 void AppModalDialog::OnClose() { | |
| 125 Cleanup(); | |
| 126 } | |
| 127 | |
| 128 void AppModalDialog::Cleanup() { | |
| 129 if (skip_this_dialog_) { | |
| 130 // We can't use the client_, because we might be in the process of | |
| 131 // destroying it. | |
| 132 if (tab_contents_) | |
| 133 tab_contents_->OnMessageBoxClosed(reply_msg_, false, L""); | |
| 134 // The extension_host_ will always be a dirty pointer on OS X because the alert | |
| 135 // window will cause the extension popup to close since it is resigning its key | |
| 136 // state, destroying the host. http://crbug.com/29355 | |
| 137 #if !defined(OS_MACOSX) | |
| 138 else if (extension_host_) | |
| 139 extension_host_->OnMessageBoxClosed(reply_msg_, false, L""); | |
| 140 else | |
| 141 NOTREACHED(); | |
| 142 #endif | |
| 143 } | |
| 144 NotificationService::current()->Notify( | |
| 145 NotificationType::APP_MODAL_DIALOG_CLOSED, | |
| 146 Source<AppModalDialog>(this), | |
| 147 NotificationService::NoDetails()); | |
| 148 } | |
| OLD | NEW |