Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / components / web_modal / web_contents_modal_dialog_manager.cc
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "components/web_modal/web_contents_modal_dialog_manager.h"
6
7 #include "components/web_modal/web_contents_modal_dialog_manager_delegate.h"
8 #include "content/public/browser/navigation_details.h"
9 #include "content/public/browser/navigation_entry.h"
10 #include "content/public/browser/render_view_host.h"
11 #include "content/public/browser/web_contents.h"
12 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
13
14 using content::WebContents;
15
16 DEFINE_WEB_CONTENTS_USER_DATA_KEY(web_modal::WebContentsModalDialogManager);
17
18 namespace web_modal {
19
20 WebContentsModalDialogManager::~WebContentsModalDialogManager() {
21   DCHECK(child_dialogs_.empty());
22 }
23
24 void WebContentsModalDialogManager::SetDelegate(
25     WebContentsModalDialogManagerDelegate* d) {
26   delegate_ = d;
27
28   for (WebContentsModalDialogList::iterator it = child_dialogs_.begin();
29        it != child_dialogs_.end(); it++) {
30     // Delegate can be NULL on Views/Win32 during tab drag.
31     (*it)->manager->HostChanged(d ? d->GetWebContentsModalDialogHost() : NULL);
32   }
33 }
34
35 void WebContentsModalDialogManager::ShowModalDialog(
36     NativeWebContentsModalDialog dialog) {
37   scoped_ptr<SingleWebContentsDialogManager> mgr(
38       CreateNativeWebModalManager(dialog, this));
39   ShowDialogWithManager(dialog, mgr.Pass());
40 }
41
42 // TODO(gbillock): Maybe "ShowBubbleWithManager"?
43 void WebContentsModalDialogManager::ShowDialogWithManager(
44     NativeWebContentsModalDialog dialog,
45     scoped_ptr<SingleWebContentsDialogManager> manager) {
46   if (delegate_)
47     manager->HostChanged(delegate_->GetWebContentsModalDialogHost());
48   child_dialogs_.push_back(new DialogState(dialog, manager.Pass()));
49
50   if (child_dialogs_.size() == 1) {
51     BlockWebContentsInteraction(true);
52     if (delegate_ && delegate_->IsWebContentsVisible(web_contents()))
53       child_dialogs_.back()->manager->Show();
54   }
55 }
56
57 bool WebContentsModalDialogManager::IsDialogActive() const {
58   return !child_dialogs_.empty();
59 }
60
61 void WebContentsModalDialogManager::FocusTopmostDialog() const {
62   DCHECK(!child_dialogs_.empty());
63   child_dialogs_.front()->manager->Focus();
64 }
65
66 content::WebContents* WebContentsModalDialogManager::GetWebContents() const {
67   return web_contents();
68 }
69
70 void WebContentsModalDialogManager::WillClose(
71     NativeWebContentsModalDialog dialog) {
72   WebContentsModalDialogList::iterator dlg = FindDialogState(dialog);
73
74   // The Views tab contents modal dialog calls WillClose twice.  Ignore the
75   // second invocation.
76   if (dlg == child_dialogs_.end())
77     return;
78
79   bool removed_topmost_dialog = dlg == child_dialogs_.begin();
80   scoped_ptr<DialogState> deleter(*dlg);
81   child_dialogs_.erase(dlg);
82   if (!child_dialogs_.empty() && removed_topmost_dialog &&
83       !closing_all_dialogs_) {
84     child_dialogs_.front()->manager->Show();
85   }
86
87   BlockWebContentsInteraction(!child_dialogs_.empty());
88 }
89
90 WebContentsModalDialogManager::WebContentsModalDialogManager(
91     content::WebContents* web_contents)
92     : content::WebContentsObserver(web_contents),
93       delegate_(NULL),
94       closing_all_dialogs_(false) {
95 }
96
97 WebContentsModalDialogManager::DialogState::DialogState(
98     NativeWebContentsModalDialog dialog,
99     scoped_ptr<SingleWebContentsDialogManager> mgr)
100     : dialog(dialog),
101       manager(mgr.release()) {
102 }
103
104 WebContentsModalDialogManager::DialogState::~DialogState() {}
105
106 WebContentsModalDialogManager::WebContentsModalDialogList::iterator
107     WebContentsModalDialogManager::FindDialogState(
108         NativeWebContentsModalDialog dialog) {
109   WebContentsModalDialogList::iterator i;
110   for (i = child_dialogs_.begin(); i != child_dialogs_.end(); ++i) {
111     if ((*i)->dialog == dialog)
112       break;
113   }
114
115   return i;
116 }
117
118 // TODO(gbillock): Move this to Views impl within Show()? It would
119 // call WebContents* contents = native_delegate_->GetWebContents(); and
120 // then set the block state. Advantage: could restrict some of the
121 // WCMDM delegate methods, then, and pass them behind the scenes.
122 void WebContentsModalDialogManager::BlockWebContentsInteraction(bool blocked) {
123   WebContents* contents = web_contents();
124   if (!contents) {
125     // The WebContents has already disconnected.
126     return;
127   }
128
129   // RenderViewHost may be NULL during shutdown.
130   content::RenderViewHost* host = contents->GetRenderViewHost();
131   if (host)
132     host->SetIgnoreInputEvents(blocked);
133   if (delegate_)
134     delegate_->SetWebContentsBlocked(contents, blocked);
135 }
136
137 void WebContentsModalDialogManager::CloseAllDialogs() {
138   closing_all_dialogs_ = true;
139
140   // Clear out any dialogs since we are leaving this page entirely.
141   while (!child_dialogs_.empty()) {
142     child_dialogs_.front()->manager->Close();
143   }
144
145   closing_all_dialogs_ = false;
146 }
147
148 void WebContentsModalDialogManager::DidNavigateMainFrame(
149     const content::LoadCommittedDetails& details,
150     const content::FrameNavigateParams& params) {
151   // Close constrained windows if necessary.
152   if (!net::registry_controlled_domains::SameDomainOrHost(
153           details.previous_url, details.entry->GetURL(),
154           net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES))
155     CloseAllDialogs();
156 }
157
158 void WebContentsModalDialogManager::DidGetIgnoredUIEvent() {
159   if (!child_dialogs_.empty()) {
160     child_dialogs_.front()->manager->Focus();
161   }
162 }
163
164 void WebContentsModalDialogManager::WasShown() {
165   if (!child_dialogs_.empty())
166     child_dialogs_.front()->manager->Show();
167 }
168
169 void WebContentsModalDialogManager::WasHidden() {
170   if (!child_dialogs_.empty())
171     child_dialogs_.front()->manager->Hide();
172 }
173
174 void WebContentsModalDialogManager::WebContentsDestroyed() {
175   // First cleanly close all child dialogs.
176   // TODO(mpcomplete): handle case if MaybeCloseChildWindows() already asked
177   // some of these to close.  CloseAllDialogs is async, so it might get called
178   // twice before it runs.
179   CloseAllDialogs();
180 }
181
182 void WebContentsModalDialogManager::DidAttachInterstitialPage() {
183   // TODO(wittman): Test closing on interstitial webui works properly on Mac.
184 #if defined(USE_AURA)
185   CloseAllDialogs();
186 #endif
187 }
188
189 }  // namespace web_modal