// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "chrome/browser/ui/views/constrained_window_views.h" #include "base/memory/scoped_ptr.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_commands.h" #include "chrome/browser/ui/host_desktop.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/browser/ui/views/tab_modal_confirm_dialog_views.h" #include "chrome/common/url_constants.h" #include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/base/interactive_test_utils.h" #include "chrome/test/base/ui_test_utils.h" #include "components/web_modal/web_contents_modal_dialog_host.h" #include "components/web_modal/web_contents_modal_dialog_manager.h" #include "components/web_modal/web_contents_modal_dialog_manager_delegate.h" #include "content/public/browser/web_contents.h" #include "content/public/test/browser_test_utils.h" #include "ui/base/accelerators/accelerator.h" #include "ui/views/focus/focus_manager.h" #include "ui/views/widget/widget.h" #if defined(OS_WIN) #include "base/win/windows_version.h" #endif namespace { class TestDialog : public views::DialogDelegateView { public: TestDialog() { SetFocusable(true); } virtual ~TestDialog() {} virtual views::View* GetInitiallyFocusedView() OVERRIDE { return this; } // Don't delete the delegate yet. Keep it around for inspection later. virtual void DeleteDelegate() OVERRIDE {} virtual ui::ModalType GetModalType() const OVERRIDE { #if defined(USE_ASH) return ui::MODAL_TYPE_CHILD; #else return views::WidgetDelegate::GetModalType(); #endif } private: DISALLOW_COPY_AND_ASSIGN(TestDialog); }; // A helper function to create and show a web contents modal dialog. scoped_ptr ShowModalDialog(content::WebContents* web_contents) { scoped_ptr dialog(new TestDialog()); ShowWebModalDialogViews(dialog.get(), web_contents); return dialog.Pass(); } } // namespace typedef InProcessBrowserTest ConstrainedWindowViewTest; // Tests the intial focus of tab-modal dialogs, the restoration of focus to the // browser when they close, and that queued dialogs don't register themselves as // accelerator targets until they are displayed. IN_PROC_BROWSER_TEST_F(ConstrainedWindowViewTest, FocusTest) { content::WebContents* web_contents = browser()->tab_strip_model()->GetActiveWebContents(); EXPECT_TRUE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX)); scoped_ptr dialog1 = ShowModalDialog(web_contents); // |dialog1| should be active and focused. EXPECT_TRUE(dialog1->GetWidget()->IsVisible()); views::FocusManager* focus_manager = dialog1->GetWidget()->GetFocusManager(); EXPECT_EQ(dialog1->GetContentsView(), focus_manager->GetFocusedView()); // Create a second dialog. This will also be modal to |web_contents|, but will // remain hidden since the |dialog1| is still showing. scoped_ptr dialog2 = ShowModalDialog(web_contents); EXPECT_FALSE(dialog2->GetWidget()->IsVisible()); EXPECT_TRUE(dialog1->GetWidget()->IsVisible()); EXPECT_EQ(focus_manager, dialog2->GetWidget()->GetFocusManager()); EXPECT_FALSE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX)); EXPECT_EQ(dialog1->GetContentsView(), focus_manager->GetFocusedView()); // Pressing return should close |dialog1|. EXPECT_TRUE(focus_manager->ProcessAccelerator( ui::Accelerator(ui::VKEY_RETURN, ui::EF_NONE))); content::RunAllPendingInMessageLoop(); EXPECT_EQ(NULL, dialog1->GetWidget()); // |dialog2| should be visible and focused. EXPECT_TRUE(dialog2->GetWidget()->IsVisible()); EXPECT_FALSE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX)); EXPECT_EQ(dialog2->GetContentsView(), focus_manager->GetFocusedView()); // Creating a new tab should take focus away from the other tab's dialog. const int tab_with_dialog = browser()->tab_strip_model()->active_index(); chrome::NewTab(browser()); EXPECT_TRUE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX)); EXPECT_NE(dialog2->GetContentsView(), focus_manager->GetFocusedView()); // Activating the previous tab should bring focus to the dialog. browser()->tab_strip_model()->ActivateTabAt(tab_with_dialog, false); EXPECT_FALSE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX)); EXPECT_EQ(dialog2->GetContentsView(), focus_manager->GetFocusedView()); // Pressing enter again should close |dialog2|. EXPECT_TRUE(focus_manager->ProcessAccelerator( ui::Accelerator(ui::VKEY_RETURN, ui::EF_NONE))); content::RunAllPendingInMessageLoop(); EXPECT_EQ(NULL, dialog2->GetWidget()); EXPECT_TRUE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_TAB_CONTAINER)); } // Tests that the tab-modal window is closed properly when its tab is closed. IN_PROC_BROWSER_TEST_F(ConstrainedWindowViewTest, TabCloseTest) { scoped_ptr dialog = ShowModalDialog( browser()->tab_strip_model()->GetActiveWebContents()); EXPECT_TRUE(dialog->GetWidget()->IsVisible()); chrome::CloseTab(browser()); content::RunAllPendingInMessageLoop(); EXPECT_EQ(NULL, dialog->GetWidget()); } // Tests that the tab-modal window is hidden when an other tab is selected and // shown when its tab is selected again. IN_PROC_BROWSER_TEST_F(ConstrainedWindowViewTest, TabSwitchTest) { scoped_ptr dialog = ShowModalDialog( browser()->tab_strip_model()->GetActiveWebContents()); EXPECT_TRUE(dialog->GetWidget()->IsVisible()); // Open a new tab. The tab-modal window should hide itself. chrome::NewTab(browser()); EXPECT_FALSE(dialog->GetWidget()->IsVisible()); // Close the new tab. The tab-modal window should show itself again. chrome::CloseTab(browser()); EXPECT_TRUE(dialog->GetWidget()->IsVisible()); // Close the original tab. chrome::CloseTab(browser()); content::RunAllPendingInMessageLoop(); EXPECT_EQ(NULL, dialog->GetWidget()); } // Tests that tab-modal dialogs follow tabs dragged between browser windows. IN_PROC_BROWSER_TEST_F(ConstrainedWindowViewTest, TabMoveTest) { content::WebContents* web_contents = browser()->tab_strip_model()->GetActiveWebContents(); scoped_ptr dialog = ShowModalDialog(web_contents); EXPECT_TRUE(dialog->GetWidget()->IsVisible()); // Move the tab to a second browser window; but first create another tab. // That prevents the first browser window from closing when its tab is moved. chrome::NewTab(browser()); browser()->tab_strip_model()->DetachWebContentsAt( browser()->tab_strip_model()->GetIndexOfWebContents(web_contents)); Browser* browser2 = CreateBrowser(browser()->profile()); browser2->tab_strip_model()->AppendWebContents(web_contents, true); EXPECT_TRUE(dialog->GetWidget()->IsVisible()); // Close the first browser. chrome::CloseWindow(browser()); content::RunAllPendingInMessageLoop(); EXPECT_TRUE(dialog->GetWidget()->IsVisible()); // Close the dialog's browser window. chrome::CloseTab(browser2); content::RunAllPendingInMessageLoop(); EXPECT_EQ(NULL, dialog->GetWidget()); } // Tests that the web contents navigates when backspace is pressed. IN_PROC_BROWSER_TEST_F(ConstrainedWindowViewTest, NavigationOnBackspace) { content::WebContents* web_contents = browser()->tab_strip_model()->GetActiveWebContents(); content::WaitForLoadStop(web_contents); const GURL original_url = web_contents->GetURL(); EXPECT_NE(GURL(chrome::kChromeUIVersionURL), original_url); ui_test_utils::NavigateToURL(browser(), GURL(chrome::kChromeUIVersionURL)); content::WaitForLoadStop(web_contents); EXPECT_EQ(GURL(chrome::kChromeUIVersionURL), web_contents->GetURL()); scoped_ptr dialog = ShowModalDialog(web_contents); EXPECT_TRUE(dialog->GetWidget()->IsVisible()); EXPECT_EQ(dialog->GetContentsView(), dialog->GetWidget()->GetFocusManager()->GetFocusedView()); // Pressing backspace should navigate back and close the dialog. EXPECT_TRUE(chrome::CanGoBack(browser())); EXPECT_TRUE(ui_test_utils::SendKeyPressSync(browser(), ui::VKEY_BACK, false, false, false, false)); content::RunAllPendingInMessageLoop(); content::WaitForLoadStop(web_contents); EXPECT_EQ(NULL, dialog->GetWidget()); EXPECT_EQ(original_url, web_contents->GetURL()); } // Tests that the dialog closes when the escape key is pressed. IN_PROC_BROWSER_TEST_F(ConstrainedWindowViewTest, ClosesOnEscape) { #if defined(OS_WIN) // TODO(msw): The widget is not made NULL on XP. http://crbug.com/177482 if (base::win::GetVersion() < base::win::VERSION_VISTA) return; #endif scoped_ptr dialog = ShowModalDialog( browser()->tab_strip_model()->GetActiveWebContents()); EXPECT_TRUE(dialog->GetWidget()->IsVisible()); EXPECT_TRUE(ui_test_utils::SendKeyPressSync(browser(), ui::VKEY_ESCAPE, false, false, false, false)); content::RunAllPendingInMessageLoop(); EXPECT_EQ(NULL, dialog->GetWidget()); }