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 |