diff options
-rw-r--r-- | chrome/browser/app_modal_dialog_queue.cc | 5 | ||||
-rw-r--r-- | chrome/browser/automation/automation_provider.cc | 37 | ||||
-rw-r--r-- | chrome/browser/automation/automation_provider.h | 2 | ||||
-rw-r--r-- | chrome/browser/browser_list.cc | 17 | ||||
-rw-r--r-- | chrome/browser/browser_list.h | 32 | ||||
-rw-r--r-- | chrome/test/automation/automation.vsprops | 2 | ||||
-rw-r--r-- | chrome/test/automation/automation_messages_internal.h | 15 | ||||
-rw-r--r-- | chrome/test/automation/automation_proxy.cc | 49 | ||||
-rw-r--r-- | chrome/test/automation/automation_proxy.h | 9 | ||||
-rw-r--r-- | chrome/test/automation/automation_proxy_uitest.cc | 88 |
10 files changed, 203 insertions, 53 deletions
diff --git a/chrome/browser/app_modal_dialog_queue.cc b/chrome/browser/app_modal_dialog_queue.cc index b0736bc..0bcceb0 100644 --- a/chrome/browser/app_modal_dialog_queue.cc +++ b/chrome/browser/app_modal_dialog_queue.cc @@ -24,7 +24,7 @@ void AppModalDialogQueue::AddDialog(views::AppModalDialogDelegate* dialog) { // static void AppModalDialogQueue::ShowNextDialog() { app_modal_dialog_queue_->pop(); - BrowserList::SetIsShowingAppModalDialog(false); + BrowserList::SetShowingAppModalDialog(NULL); if (!app_modal_dialog_queue_->empty()) { ShowModalDialog(app_modal_dialog_queue_->front()); } else { @@ -43,6 +43,7 @@ void AppModalDialogQueue::ActivateModalDialog() { void AppModalDialogQueue::ShowModalDialog( views::AppModalDialogDelegate* dialog) { dialog->ShowModalDialog(); - BrowserList::SetIsShowingAppModalDialog(true); + BrowserList::SetShowingAppModalDialog(dialog); } + diff --git a/chrome/browser/automation/automation_provider.cc b/chrome/browser/automation/automation_provider.cc index 146883b..c1d4a15 100644 --- a/chrome/browser/automation/automation_provider.cc +++ b/chrome/browser/automation/automation_provider.cc @@ -30,6 +30,8 @@ #include "chrome/common/chrome_paths.h" #include "chrome/common/pref_service.h" #include "chrome/test/automation/automation_messages.h" +#include "chrome/views/app_modal_dialog_delegate.h" +#include "chrome/views/window.h" #include "net/base/cookie_monster.h" #include "net/url_request/url_request_filter.h" @@ -811,6 +813,8 @@ void AutomationProvider::OnMessageReceived(const IPC::Message& message) { SetIntPreference) IPC_MESSAGE_HANDLER(AutomationMsg_ShowingAppModalDialogRequest, GetShowingAppModalDialog) + IPC_MESSAGE_HANDLER(AutomationMsg_ClickAppModalDialogButtonRequest, + ClickAppModalDialogButton) IPC_END_MESSAGE_MAP() } @@ -1074,9 +1078,38 @@ void AutomationProvider::GetBrowserWindowCount(const IPC::Message& message) { } void AutomationProvider::GetShowingAppModalDialog(const IPC::Message& message) { + views::AppModalDialogDelegate* dialog_delegate = + BrowserList::GetShowingAppModalDialog(); Send(new AutomationMsg_ShowingAppModalDialogResponse( - message.routing_id(), - static_cast<bool>(BrowserList::IsShowingAppModalDialog()))); + message.routing_id(), dialog_delegate != NULL, + dialog_delegate ? dialog_delegate->GetDialogButtons() : + views::DialogDelegate::DIALOGBUTTON_NONE)); +} + +void AutomationProvider::ClickAppModalDialogButton(const IPC::Message& message, + int button) { + bool success = false; + + views::AppModalDialogDelegate* dialog_delegate = + BrowserList::GetShowingAppModalDialog(); + if (dialog_delegate && + (dialog_delegate->GetDialogButtons() & button) == button) { + views::DialogClientView* client_view = + dialog_delegate->window()->client_view()->AsDialogClientView(); + if ((button & views::DialogDelegate::DIALOGBUTTON_OK) == + views::DialogDelegate::DIALOGBUTTON_OK) { + client_view->AcceptWindow(); + success = true; + } + if ((button & views::DialogDelegate::DIALOGBUTTON_CANCEL) == + views::DialogDelegate::DIALOGBUTTON_CANCEL) { + DCHECK(!success) << "invalid param, OK and CANCEL specified"; + client_view->CancelWindow(); + success = true; + } + } + Send(new AutomationMsg_ClickAppModalDialogButtonResponse( + message.routing_id(), success)); } void AutomationProvider::GetBrowserWindow(const IPC::Message& message, diff --git a/chrome/browser/automation/automation_provider.h b/chrome/browser/automation/automation_provider.h index 401e0b5..b0e21d3 100644 --- a/chrome/browser/automation/automation_provider.h +++ b/chrome/browser/automation/automation_provider.h @@ -106,6 +106,8 @@ class AutomationProvider : public base::RefCounted<AutomationProvider>, int handle); void GetBrowserWindowCount(const IPC::Message& message); void GetShowingAppModalDialog(const IPC::Message& message); + void ClickAppModalDialogButton(const IPC::Message& message, + int button); void GetBrowserWindow(const IPC::Message& message, int index); void GetLastActiveBrowserWindow(const IPC::Message& message); void GetActiveWindow(const IPC::Message& message); diff --git a/chrome/browser/browser_list.cc b/chrome/browser/browser_list.cc index 67d6a56..2665daa 100644 --- a/chrome/browser/browser_list.cc +++ b/chrome/browser/browser_list.cc @@ -176,18 +176,23 @@ bool BrowserList::HasBrowserWithProfile(Profile* profile) { } // static -bool BrowserList::is_app_modal_ = false; +views::AppModalDialogDelegate* BrowserList::app_modal_dialog_ = NULL; // static -void BrowserList::SetIsShowingAppModalDialog(bool is_app_modal) { - // If we are already modal, we can't go modal again. - DCHECK(!(is_app_modal_ && is_app_modal)); - is_app_modal_ = is_app_modal; +void BrowserList::SetShowingAppModalDialog( + views::AppModalDialogDelegate* dialog) { + DCHECK(!(app_modal_dialog_ && dialog)); + app_modal_dialog_ = dialog; +} + +// static +views::AppModalDialogDelegate* BrowserList::GetShowingAppModalDialog() { + return app_modal_dialog_; } // static bool BrowserList::IsShowingAppModalDialog() { - return is_app_modal_; + return app_modal_dialog_ != NULL; } // static diff --git a/chrome/browser/browser_list.h b/chrome/browser/browser_list.h index ef9a16f..f9d76c3 100644 --- a/chrome/browser/browser_list.h +++ b/chrome/browser/browser_list.h @@ -11,6 +11,7 @@ #include "chrome/browser/browser.h" namespace views { +class AppModalDialogDelegate; class Window; }; class WebContents; @@ -76,30 +77,9 @@ class BrowserList { // Returns true if there is at least one Browser with the specified profile. static bool HasBrowserWithProfile(Profile* profile); - // Set whether the last active browser should be modal or not, if - // |is_app_modal| is true, the last active browser window will be activated - // and brought to the front whenever the user attempts to activate any other - // browser window. If |is_app_modal| is false all window activation works as - // normal. SetIsShowingAppModalDialog should not be called with |is_app_modal| - // set to true if the last active browser is already modal. - // - // TODO(devint): http://b/issue?id=1123402 Application modal dialogs aren't - // selected, just the last active browser. Therefore, to properly use this - // function we have to set the modal dialog as a child of a browser, - // activate that browser window, call SetIsShowingAppModalDialog(true), and - // implement the modal dialog as window modal to its parent. This still isn't - // perfect,however, because it just assures that the browser is activated, and - // the dialog will be on top of that browser, but inactive. It will activate - // if the users attempts to interact with its parent window (the browser). - // Ideally we should activate the modal dialog, not just its parent browser. - // - // There is probably a less clunky way overall to implement application - // modality. Currently, if IsShowingAppModalDialog returns true, we handle - // messages right before the browser activates, and activate whatever - // GetLastActive() returns instead of whatever was trying to be activated. - // It'd be better if we could use built in OS modality handling to deal with - // this, but Windows only supports system modal or parent window modal. - static void SetIsShowingAppModalDialog(bool is_app_modal); + // Sets the passed dialog delegate as the currently showing dialog. + static void SetShowingAppModalDialog(views::AppModalDialogDelegate* dialog); + static views::AppModalDialogDelegate* GetShowingAppModalDialog(); // True if the last active browser is application modal, false otherwise. See // SetIsShowingAppModalDialog for more details. @@ -153,8 +133,8 @@ class BrowserList { typedef std::vector<views::Window*> DependentWindowList; static DependentWindowList dependent_windows_; - // True if last_active_ is app modal, false otherwise. - static bool is_app_modal_; + // Set to the currently showing modal dialog delegate if any, NULL otherwise. + static views::AppModalDialogDelegate* app_modal_dialog_; }; diff --git a/chrome/test/automation/automation.vsprops b/chrome/test/automation/automation.vsprops index 4cc3b79..23a5fc4 100644 --- a/chrome/test/automation/automation.vsprops +++ b/chrome/test/automation/automation.vsprops @@ -3,7 +3,7 @@ ProjectType="Visual C++" Version="8.00" Name="automation" - InheritedPropertySheets="$(SolutionDir)..\build\common.vsprops;$(SolutionDir)..\skia\using_skia.vsprops" + InheritedPropertySheets="$(SolutionDir)..\build\common.vsprops;$(SolutionDir)..\skia\using_skia.vsprops;$(SolutionDir)third_party\wtl\using_wtl.vsprops" > <Tool Name="VCCLCompilerTool" diff --git a/chrome/test/automation/automation_messages_internal.h b/chrome/test/automation/automation_messages_internal.h index b71457d..165b606 100644 --- a/chrome/test/automation/automation_messages_internal.h +++ b/chrome/test/automation/automation_messages_internal.h @@ -802,14 +802,23 @@ IPC_BEGIN_MESSAGES(Automation, 0) bool /* success */) // Queries whether an app modal dialog is currently being shown. (i.e. a - // javascript alert). + // javascript alert) and which buttons it contains. IPC_MESSAGE_ROUTED0(AutomationMsg_ShowingAppModalDialogRequest) - IPC_MESSAGE_ROUTED1(AutomationMsg_ShowingAppModalDialogResponse, - bool /* showing dialog */) + IPC_MESSAGE_ROUTED2(AutomationMsg_ShowingAppModalDialogResponse, + bool /* showing dialog */, + int /* view::DelegateDialog::DialogButton */) // Returns the ordinal and the number of matches found as a response to // a AutomationMsg_FindRequest. IPC_MESSAGE_ROUTED2(AutomationMsg_FindInPageResponse2, int /* active_ordinal */, int /* matches_found */) + + // This message triggers the specified button for the currently showing + // modal dialog. + IPC_MESSAGE_ROUTED1(AutomationMsg_ClickAppModalDialogButtonRequest, + int /* view::DelegateDialog::DialogButton */) + IPC_MESSAGE_ROUTED1(AutomationMsg_ClickAppModalDialogButtonResponse, + bool /* success */) + IPC_END_MESSAGES(Automation) diff --git a/chrome/test/automation/automation_proxy.cc b/chrome/test/automation/automation_proxy.cc index 348ce0f..60806b5 100644 --- a/chrome/test/automation/automation_proxy.cc +++ b/chrome/test/automation/automation_proxy.cc @@ -15,6 +15,7 @@ #include "chrome/test/automation/browser_proxy.h" #include "chrome/test/automation/tab_proxy.h" #include "chrome/test/automation/window_proxy.h" +#include "chrome/views/dialog_delegate.h" using base::TimeDelta; using base::TimeTicks; @@ -302,32 +303,56 @@ bool AutomationProxy::WaitForWindowCountToBecome(int count, return false; } -bool AutomationProxy::GetShowingAppModalDialog(bool* showing_app_modal_dialog) { - if (!showing_app_modal_dialog) { +bool AutomationProxy::GetShowingAppModalDialog( + bool* showing_app_modal_dialog, + views::DialogDelegate::DialogButton* button) { + if (!showing_app_modal_dialog || !button) { NOTREACHED(); return false; } IPC::Message* response = NULL; bool is_timeout = true; - bool succeeded = SendAndWaitForResponseWithTimeout( - new AutomationMsg_ShowingAppModalDialogRequest(0), &response, - AutomationMsg_ShowingAppModalDialogResponse::ID, - kMaxCommandExecutionTime, &is_timeout); - if (!succeeded) + if (!SendAndWaitForResponseWithTimeout( + new AutomationMsg_ShowingAppModalDialogRequest(0), &response, + AutomationMsg_ShowingAppModalDialogResponse::ID, + kMaxCommandExecutionTime, &is_timeout)) { return false; + } + scoped_ptr<IPC::Message> response_deleter(response); // Delete on exit. if (is_timeout) { DLOG(ERROR) << "ShowingAppModalDialog did not complete in a timely fashion"; return false; } void* iter = NULL; - if (!response->ReadBool(&iter, showing_app_modal_dialog)) { - succeeded = false; + int button_int = 0; + if (!response->ReadBool(&iter, showing_app_modal_dialog) || + !response->ReadInt(&iter, &button_int)) + return false; + + *button = static_cast<views::DialogDelegate::DialogButton>(button_int); + return true; +} + +bool AutomationProxy::ClickAppModalDialogButton( + views::DialogDelegate::DialogButton button) { + IPC::Message* response = NULL; + bool is_timeout = true; + if (!SendAndWaitForResponseWithTimeout( + new AutomationMsg_ClickAppModalDialogButtonRequest(0, button), + &response, + AutomationMsg_ClickAppModalDialogButtonResponse::ID, + kMaxCommandExecutionTime, &is_timeout)) { + return false; } - delete response; + bool succeeded = false; + void* iter = NULL; + if (!response->ReadBool(&iter, &succeeded)) + return false; + return succeeded; } @@ -336,7 +361,9 @@ bool AutomationProxy::WaitForAppModalDialog(int wait_timeout) { const TimeDelta timeout = TimeDelta::FromMilliseconds(wait_timeout); while (TimeTicks::Now() - start < timeout) { bool dialog_shown = false; - bool succeeded = GetShowingAppModalDialog(&dialog_shown); + views::DialogDelegate::DialogButton button = + views::DialogDelegate::DIALOGBUTTON_NONE; + bool succeeded = GetShowingAppModalDialog(&dialog_shown, &button); if (!succeeded) { // Try again next round, but log it. DLOG(ERROR) << "GetShowingAppModalDialog returned false"; diff --git a/chrome/test/automation/automation_proxy.h b/chrome/test/automation/automation_proxy.h index 5621b011..0c147fa 100644 --- a/chrome/test/automation/automation_proxy.h +++ b/chrome/test/automation/automation_proxy.h @@ -14,6 +14,7 @@ #include "chrome/common/ipc_message.h" #include "chrome/test/automation/automation_handle_tracker.h" #include "chrome/test/automation/automation_messages.h" +#include "chrome/views/dialog_delegate.h" class AutomationRequest; class BrowserProxy; @@ -109,8 +110,12 @@ class AutomationProxy : public IPC::Channel::Listener, bool WaitForWindowCountToBecome(int target_count, int wait_timeout); // Returns whether an app modal dialog window is showing right now (i.e., a - // javascript alert). - bool GetShowingAppModalDialog(bool* showing_app_modal_dialog); + // javascript alert), and what buttons it contains. + bool GetShowingAppModalDialog(bool* showing_app_modal_dialog, + views::DialogDelegate::DialogButton* button); + + // Simulates a click on a dialog button. + bool ClickAppModalDialogButton(views::DialogDelegate::DialogButton button); // Block the thread until a modal dialog is displayed. Returns true on // success. diff --git a/chrome/test/automation/automation_proxy_uitest.cc b/chrome/test/automation/automation_proxy_uitest.cc index aa24354..ece5fd8 100644 --- a/chrome/test/automation/automation_proxy_uitest.cc +++ b/chrome/test/automation/automation_proxy_uitest.cc @@ -17,12 +17,14 @@ #include "chrome/test/automation/tab_proxy.h" #include "chrome/test/automation/window_proxy.h" #include "chrome/test/ui/ui_test.h" +#include "chrome/views/dialog_delegate.h" #include "chrome/views/event.h" #include "net/base/net_util.h" class AutomationProxyTest : public UITest { protected: AutomationProxyTest() { + dom_automation_enabled_ = true; CommandLine::AppendSwitchWithValue(&launch_arguments_, switches::kLang, L"en-us"); @@ -818,3 +820,89 @@ TEST_F(AutomationProxyVisibleTest, AutocompleteMatchesTest) { EXPECT_TRUE(edit->GetAutocompleteMatches(&matches)); EXPECT_FALSE(matches.empty()); } + +TEST_F(AutomationProxyTest, AppModalDialogTest) { + scoped_ptr<BrowserProxy> browser(automation()->GetBrowserWindow(0)); + ASSERT_TRUE(browser.get()); + scoped_ptr<TabProxy> tab(browser->GetTab(0)); + tab.reset(browser->GetTab(0)); + ASSERT_TRUE(tab.get()); + + bool modal_dialog_showing = false; + views::DialogDelegate::DialogButton button = + views::DialogDelegate::DIALOGBUTTON_NONE; + EXPECT_TRUE(automation()->GetShowingAppModalDialog(&modal_dialog_showing, + &button)); + EXPECT_FALSE(modal_dialog_showing); + EXPECT_EQ(views::DialogDelegate::DIALOGBUTTON_NONE, button); + + // Show a simple alert. + std::string content = + "data:text/html,<html><head><script>function onload() {" + "setTimeout(\"alert('hello');\", 1000); }</script></head>" + "<body onload='onload()'></body></html>"; + tab->NavigateToURL(GURL(content)); + EXPECT_TRUE(automation()->WaitForAppModalDialog(3000)); + EXPECT_TRUE(automation()->GetShowingAppModalDialog(&modal_dialog_showing, + &button)); + EXPECT_TRUE(modal_dialog_showing); + EXPECT_EQ(views::DialogDelegate::DIALOGBUTTON_OK, button); + + // Test that clicking missing button fails graciously and does not close the + // dialog. + EXPECT_FALSE(automation()->ClickAppModalDialogButton( + views::DialogDelegate::DIALOGBUTTON_CANCEL)); + EXPECT_TRUE(automation()->GetShowingAppModalDialog(&modal_dialog_showing, + &button)); + EXPECT_TRUE(modal_dialog_showing); + + // Now click OK, that should close the dialog. + EXPECT_TRUE(automation()->ClickAppModalDialogButton( + views::DialogDelegate::DIALOGBUTTON_OK)); + EXPECT_TRUE(automation()->GetShowingAppModalDialog(&modal_dialog_showing, + &button)); + EXPECT_FALSE(modal_dialog_showing); + + // Show a confirm dialog. + content = + "data:text/html,<html><head><script>var result = -1; function onload() {" + "setTimeout(\"result = confirm('hello') ? 0 : 1;\", 1000);} </script>" + "</head><body onload='onload()'></body></html>"; + tab->NavigateToURL(GURL(content)); + EXPECT_TRUE(automation()->WaitForAppModalDialog(3000)); + EXPECT_TRUE(automation()->GetShowingAppModalDialog(&modal_dialog_showing, + &button)); + EXPECT_TRUE(modal_dialog_showing); + EXPECT_EQ(views::DialogDelegate::DIALOGBUTTON_OK | + views::DialogDelegate::DIALOGBUTTON_CANCEL, button); + + // Click OK. + EXPECT_TRUE(automation()->ClickAppModalDialogButton( + views::DialogDelegate::DIALOGBUTTON_OK)); + EXPECT_TRUE(automation()->GetShowingAppModalDialog(&modal_dialog_showing, + &button)); + EXPECT_FALSE(modal_dialog_showing); + int result = -1; + EXPECT_TRUE(tab->ExecuteAndExtractInt( + L"", L"window.domAutomationController.send(result);", &result)); + EXPECT_EQ(0, result); + + // Try again. + tab->NavigateToURL(GURL(content)); + EXPECT_TRUE(automation()->WaitForAppModalDialog(3000)); + EXPECT_TRUE(automation()->GetShowingAppModalDialog(&modal_dialog_showing, + &button)); + EXPECT_TRUE(modal_dialog_showing); + EXPECT_EQ(views::DialogDelegate::DIALOGBUTTON_OK | + views::DialogDelegate::DIALOGBUTTON_CANCEL, button); + + // Click Cancel this time. + EXPECT_TRUE(automation()->ClickAppModalDialogButton( + views::DialogDelegate::DIALOGBUTTON_CANCEL)); + EXPECT_TRUE(automation()->GetShowingAppModalDialog(&modal_dialog_showing, + &button)); + EXPECT_FALSE(modal_dialog_showing); + EXPECT_TRUE(tab->ExecuteAndExtractInt( + L"", L"window.domAutomationController.send(result);", &result)); + EXPECT_EQ(1, result); +}
\ No newline at end of file |