Home | History | Annotate | Download | only in views
      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 "chrome/browser/ui/views/constrained_window_views.h"
      6 
      7 #include "base/memory/scoped_ptr.h"
      8 #include "chrome/browser/ui/browser.h"
      9 #include "chrome/browser/ui/browser_commands.h"
     10 #include "chrome/browser/ui/host_desktop.h"
     11 #include "chrome/browser/ui/tabs/tab_strip_model.h"
     12 #include "chrome/browser/ui/views/tab_modal_confirm_dialog_views.h"
     13 #include "chrome/common/url_constants.h"
     14 #include "chrome/test/base/in_process_browser_test.h"
     15 #include "chrome/test/base/interactive_test_utils.h"
     16 #include "chrome/test/base/ui_test_utils.h"
     17 #include "components/web_modal/web_contents_modal_dialog_host.h"
     18 #include "components/web_modal/web_contents_modal_dialog_manager.h"
     19 #include "components/web_modal/web_contents_modal_dialog_manager_delegate.h"
     20 #include "content/public/browser/web_contents.h"
     21 #include "content/public/test/browser_test_utils.h"
     22 #include "ui/base/accelerators/accelerator.h"
     23 #include "ui/views/focus/focus_manager.h"
     24 #include "ui/views/widget/widget.h"
     25 
     26 #if defined(OS_WIN)
     27 #include "base/win/windows_version.h"
     28 #endif
     29 
     30 namespace {
     31 
     32 class TestDialog : public views::DialogDelegateView {
     33  public:
     34   TestDialog() { SetFocusable(true); }
     35   virtual ~TestDialog() {}
     36 
     37   virtual views::View* GetInitiallyFocusedView() OVERRIDE { return this; }
     38   // Don't delete the delegate yet. Keep it around for inspection later.
     39   virtual void DeleteDelegate() OVERRIDE {}
     40 
     41   virtual ui::ModalType GetModalType() const OVERRIDE {
     42 #if defined(USE_ASH)
     43     return ui::MODAL_TYPE_CHILD;
     44 #else
     45     return views::WidgetDelegate::GetModalType();
     46 #endif
     47   }
     48 
     49  private:
     50   DISALLOW_COPY_AND_ASSIGN(TestDialog);
     51 };
     52 
     53 // A helper function to create and show a web contents modal dialog.
     54 scoped_ptr<TestDialog> ShowModalDialog(content::WebContents* web_contents) {
     55   scoped_ptr<TestDialog> dialog(new TestDialog());
     56   ShowWebModalDialogViews(dialog.get(), web_contents);
     57   return dialog.Pass();
     58 }
     59 
     60 } // namespace
     61 
     62 typedef InProcessBrowserTest ConstrainedWindowViewTest;
     63 
     64 // Tests the intial focus of tab-modal dialogs, the restoration of focus to the
     65 // browser when they close, and that queued dialogs don't register themselves as
     66 // accelerator targets until they are displayed.
     67 IN_PROC_BROWSER_TEST_F(ConstrainedWindowViewTest, FocusTest) {
     68   content::WebContents* web_contents =
     69       browser()->tab_strip_model()->GetActiveWebContents();
     70   EXPECT_TRUE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX));
     71   scoped_ptr<TestDialog> dialog1 = ShowModalDialog(web_contents);
     72 
     73   // |dialog1| should be active and focused.
     74   EXPECT_TRUE(dialog1->GetWidget()->IsVisible());
     75   views::FocusManager* focus_manager = dialog1->GetWidget()->GetFocusManager();
     76   EXPECT_EQ(dialog1->GetContentsView(), focus_manager->GetFocusedView());
     77 
     78   // Create a second dialog. This will also be modal to |web_contents|, but will
     79   // remain hidden since the |dialog1| is still showing.
     80   scoped_ptr<TestDialog> dialog2 = ShowModalDialog(web_contents);
     81   EXPECT_FALSE(dialog2->GetWidget()->IsVisible());
     82   EXPECT_TRUE(dialog1->GetWidget()->IsVisible());
     83   EXPECT_EQ(focus_manager, dialog2->GetWidget()->GetFocusManager());
     84   EXPECT_FALSE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX));
     85   EXPECT_EQ(dialog1->GetContentsView(), focus_manager->GetFocusedView());
     86 
     87   // Pressing return should close |dialog1|.
     88   EXPECT_TRUE(focus_manager->ProcessAccelerator(
     89       ui::Accelerator(ui::VKEY_RETURN, ui::EF_NONE)));
     90   content::RunAllPendingInMessageLoop();
     91   EXPECT_EQ(NULL, dialog1->GetWidget());
     92 
     93   // |dialog2| should be visible and focused.
     94   EXPECT_TRUE(dialog2->GetWidget()->IsVisible());
     95   EXPECT_FALSE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX));
     96   EXPECT_EQ(dialog2->GetContentsView(), focus_manager->GetFocusedView());
     97 
     98   // Creating a new tab should take focus away from the other tab's dialog.
     99   const int tab_with_dialog = browser()->tab_strip_model()->active_index();
    100   chrome::NewTab(browser());
    101   EXPECT_TRUE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX));
    102   EXPECT_NE(dialog2->GetContentsView(), focus_manager->GetFocusedView());
    103 
    104   // Activating the previous tab should bring focus to the dialog.
    105   browser()->tab_strip_model()->ActivateTabAt(tab_with_dialog, false);
    106   EXPECT_FALSE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX));
    107   EXPECT_EQ(dialog2->GetContentsView(), focus_manager->GetFocusedView());
    108 
    109   // Pressing enter again should close |dialog2|.
    110   EXPECT_TRUE(focus_manager->ProcessAccelerator(
    111       ui::Accelerator(ui::VKEY_RETURN, ui::EF_NONE)));
    112   content::RunAllPendingInMessageLoop();
    113   EXPECT_EQ(NULL, dialog2->GetWidget());
    114   EXPECT_TRUE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_TAB_CONTAINER));
    115 }
    116 
    117 // Tests that the tab-modal window is closed properly when its tab is closed.
    118 IN_PROC_BROWSER_TEST_F(ConstrainedWindowViewTest, TabCloseTest) {
    119   scoped_ptr<TestDialog> dialog = ShowModalDialog(
    120       browser()->tab_strip_model()->GetActiveWebContents());
    121   EXPECT_TRUE(dialog->GetWidget()->IsVisible());
    122   chrome::CloseTab(browser());
    123   content::RunAllPendingInMessageLoop();
    124   EXPECT_EQ(NULL, dialog->GetWidget());
    125 }
    126 
    127 // Tests that the tab-modal window is hidden when an other tab is selected and
    128 // shown when its tab is selected again.
    129 IN_PROC_BROWSER_TEST_F(ConstrainedWindowViewTest, TabSwitchTest) {
    130   scoped_ptr<TestDialog> dialog = ShowModalDialog(
    131       browser()->tab_strip_model()->GetActiveWebContents());
    132   EXPECT_TRUE(dialog->GetWidget()->IsVisible());
    133 
    134   // Open a new tab. The tab-modal window should hide itself.
    135   chrome::NewTab(browser());
    136   EXPECT_FALSE(dialog->GetWidget()->IsVisible());
    137 
    138   // Close the new tab. The tab-modal window should show itself again.
    139   chrome::CloseTab(browser());
    140   EXPECT_TRUE(dialog->GetWidget()->IsVisible());
    141 
    142   // Close the original tab.
    143   chrome::CloseTab(browser());
    144   content::RunAllPendingInMessageLoop();
    145   EXPECT_EQ(NULL, dialog->GetWidget());
    146 }
    147 
    148 // Tests that tab-modal dialogs follow tabs dragged between browser windows.
    149 IN_PROC_BROWSER_TEST_F(ConstrainedWindowViewTest, TabMoveTest) {
    150   content::WebContents* web_contents =
    151       browser()->tab_strip_model()->GetActiveWebContents();
    152   scoped_ptr<TestDialog> dialog = ShowModalDialog(web_contents);
    153   EXPECT_TRUE(dialog->GetWidget()->IsVisible());
    154 
    155   // Move the tab to a second browser window; but first create another tab.
    156   // That prevents the first browser window from closing when its tab is moved.
    157   chrome::NewTab(browser());
    158   browser()->tab_strip_model()->DetachWebContentsAt(
    159       browser()->tab_strip_model()->GetIndexOfWebContents(web_contents));
    160   Browser* browser2 = CreateBrowser(browser()->profile());
    161   browser2->tab_strip_model()->AppendWebContents(web_contents, true);
    162   EXPECT_TRUE(dialog->GetWidget()->IsVisible());
    163 
    164   // Close the first browser.
    165   chrome::CloseWindow(browser());
    166   content::RunAllPendingInMessageLoop();
    167   EXPECT_TRUE(dialog->GetWidget()->IsVisible());
    168 
    169   // Close the dialog's browser window.
    170   chrome::CloseTab(browser2);
    171   content::RunAllPendingInMessageLoop();
    172   EXPECT_EQ(NULL, dialog->GetWidget());
    173 }
    174 
    175 // Tests that the web contents navigates when backspace is pressed.
    176 IN_PROC_BROWSER_TEST_F(ConstrainedWindowViewTest, NavigationOnBackspace) {
    177   content::WebContents* web_contents =
    178       browser()->tab_strip_model()->GetActiveWebContents();
    179   content::WaitForLoadStop(web_contents);
    180   const GURL original_url = web_contents->GetURL();
    181   EXPECT_NE(GURL(chrome::kChromeUIVersionURL), original_url);
    182   ui_test_utils::NavigateToURL(browser(), GURL(chrome::kChromeUIVersionURL));
    183   content::WaitForLoadStop(web_contents);
    184   EXPECT_EQ(GURL(chrome::kChromeUIVersionURL), web_contents->GetURL());
    185 
    186   scoped_ptr<TestDialog> dialog = ShowModalDialog(web_contents);
    187   EXPECT_TRUE(dialog->GetWidget()->IsVisible());
    188   EXPECT_EQ(dialog->GetContentsView(),
    189             dialog->GetWidget()->GetFocusManager()->GetFocusedView());
    190 
    191   // Pressing backspace should navigate back and close the dialog.
    192   EXPECT_TRUE(chrome::CanGoBack(browser()));
    193   EXPECT_TRUE(ui_test_utils::SendKeyPressSync(browser(), ui::VKEY_BACK,
    194                                               false, false, false, false));
    195   content::RunAllPendingInMessageLoop();
    196   content::WaitForLoadStop(web_contents);
    197   EXPECT_EQ(NULL, dialog->GetWidget());
    198   EXPECT_EQ(original_url, web_contents->GetURL());
    199 }
    200 
    201 // Tests that the dialog closes when the escape key is pressed.
    202 IN_PROC_BROWSER_TEST_F(ConstrainedWindowViewTest, ClosesOnEscape) {
    203 #if defined(OS_WIN)
    204   // TODO(msw): The widget is not made NULL on XP. http://crbug.com/177482
    205   if (base::win::GetVersion() < base::win::VERSION_VISTA)
    206     return;
    207 #endif
    208 
    209   scoped_ptr<TestDialog> dialog = ShowModalDialog(
    210       browser()->tab_strip_model()->GetActiveWebContents());
    211   EXPECT_TRUE(dialog->GetWidget()->IsVisible());
    212   EXPECT_TRUE(ui_test_utils::SendKeyPressSync(browser(), ui::VKEY_ESCAPE,
    213                                               false, false, false, false));
    214   content::RunAllPendingInMessageLoop();
    215   EXPECT_EQ(NULL, dialog->GetWidget());
    216 }
    217