Home | History | Annotate | Download | only in window
      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 "base/basictypes.h"
      6 #include "base/strings/utf_string_conversions.h"
      7 #include "ui/base/ui_base_types.h"
      8 #include "ui/views/controls/button/label_button.h"
      9 #include "ui/views/test/test_views.h"
     10 #include "ui/views/test/views_test_base.h"
     11 #include "ui/views/widget/widget.h"
     12 #include "ui/views/window/dialog_client_view.h"
     13 #include "ui/views/window/dialog_delegate.h"
     14 
     15 namespace views {
     16 
     17 class TestDialogClientView : public DialogClientView {
     18  public:
     19   TestDialogClientView(View* contents_view,
     20                        DialogDelegate* dialog_delegate)
     21       : DialogClientView(contents_view),
     22         dialog_(dialog_delegate) {}
     23   virtual ~TestDialogClientView() {}
     24 
     25   // DialogClientView implementation.
     26   virtual DialogDelegate* GetDialogDelegate() const OVERRIDE { return dialog_; }
     27 
     28   View* GetContentsView() { return contents_view(); }
     29 
     30   void CreateExtraViews() {
     31     CreateExtraView();
     32     CreateFootnoteView();
     33   }
     34 
     35  private:
     36   DialogDelegate* dialog_;
     37 
     38   DISALLOW_COPY_AND_ASSIGN(TestDialogClientView);
     39 };
     40 
     41 class DialogClientViewTest : public ViewsTestBase,
     42                              public DialogDelegateView {
     43  public:
     44   DialogClientViewTest()
     45       : dialog_buttons_(ui::DIALOG_BUTTON_NONE),
     46         extra_view_(NULL),
     47         footnote_view_(NULL) {}
     48   virtual ~DialogClientViewTest() {}
     49 
     50   // testing::Test implementation.
     51   virtual void SetUp() OVERRIDE {
     52     dialog_buttons_ = ui::DIALOG_BUTTON_NONE;
     53     contents_.reset(new StaticSizedView(gfx::Size(100, 200)));
     54     client_view_.reset(new TestDialogClientView(contents_.get(), this));
     55 
     56     ViewsTestBase::SetUp();
     57   }
     58 
     59   // DialogDelegateView implementation.
     60   virtual View* GetContentsView() OVERRIDE { return contents_.get(); }
     61   virtual View* CreateExtraView() OVERRIDE { return extra_view_; }
     62   virtual View* CreateFootnoteView() OVERRIDE { return footnote_view_; }
     63   virtual int GetDialogButtons() const OVERRIDE { return dialog_buttons_; }
     64 
     65  protected:
     66   gfx::Rect GetUpdatedClientBounds() {
     67     client_view_->SizeToPreferredSize();
     68     client_view_->Layout();
     69     return client_view_->bounds();
     70   }
     71 
     72   // Makes sure that the content view is sized correctly. Width must be at least
     73   // the requested amount, but height should always match exactly.
     74   void CheckContentsIsSetToPreferredSize() {
     75     const gfx::Rect client_bounds = GetUpdatedClientBounds();
     76     const gfx::Size preferred_size = contents_->GetPreferredSize();
     77     EXPECT_EQ(preferred_size.height(), contents_->bounds().height());
     78     EXPECT_LE(preferred_size.width(), contents_->bounds().width());
     79     EXPECT_EQ(contents_->bounds().origin(), client_bounds.origin());
     80     EXPECT_EQ(contents_->bounds().right(), client_bounds.right());
     81   }
     82 
     83   // Sets the buttons to show in the dialog and refreshes the dialog.
     84   void SetDialogButtons(int dialog_buttons) {
     85     dialog_buttons_ = dialog_buttons;
     86     client_view_->UpdateDialogButtons();
     87   }
     88 
     89   // Sets the extra view.
     90   void SetExtraView(View* view) {
     91     DCHECK(!extra_view_);
     92     extra_view_ = view;
     93     client_view_->CreateExtraViews();
     94   }
     95 
     96   // Sets the footnote view.
     97   void SetFootnoteView(View* view) {
     98     DCHECK(!footnote_view_);
     99     footnote_view_ = view;
    100     client_view_->CreateExtraViews();
    101   }
    102 
    103   TestDialogClientView* client_view() { return client_view_.get(); }
    104 
    105  private:
    106   // The contents of the dialog.
    107   scoped_ptr<View> contents_;
    108   // The DialogClientView that's being tested.
    109   scoped_ptr<TestDialogClientView> client_view_;
    110   // The bitmask of buttons to show in the dialog.
    111   int dialog_buttons_;
    112   View* extra_view_;  // weak
    113   View* footnote_view_;  // weak
    114 
    115   DISALLOW_COPY_AND_ASSIGN(DialogClientViewTest);
    116 };
    117 
    118 TEST_F(DialogClientViewTest, UpdateButtons) {
    119   // This dialog should start with no buttons.
    120   EXPECT_EQ(GetDialogButtons(), ui::DIALOG_BUTTON_NONE);
    121   EXPECT_EQ(NULL, client_view()->ok_button());
    122   EXPECT_EQ(NULL, client_view()->cancel_button());
    123   const int height_without_buttons = GetUpdatedClientBounds().height();
    124 
    125   // Update to use both buttons.
    126   SetDialogButtons(ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL);
    127   EXPECT_TRUE(client_view()->ok_button()->is_default());
    128   EXPECT_FALSE(client_view()->cancel_button()->is_default());
    129   const int height_with_buttons = GetUpdatedClientBounds().height();
    130   EXPECT_GT(height_with_buttons, height_without_buttons);
    131 
    132   // Remove the dialog buttons.
    133   SetDialogButtons(ui::DIALOG_BUTTON_NONE);
    134   EXPECT_EQ(NULL, client_view()->ok_button());
    135   EXPECT_EQ(NULL, client_view()->cancel_button());
    136   EXPECT_EQ(GetUpdatedClientBounds().height(), height_without_buttons);
    137 
    138   // Reset with just an ok button.
    139   SetDialogButtons(ui::DIALOG_BUTTON_OK);
    140   EXPECT_TRUE(client_view()->ok_button()->is_default());
    141   EXPECT_EQ(NULL, client_view()->cancel_button());
    142   EXPECT_EQ(GetUpdatedClientBounds().height(), height_with_buttons);
    143 
    144   // Reset with just a cancel button.
    145   SetDialogButtons(ui::DIALOG_BUTTON_CANCEL);
    146   EXPECT_EQ(NULL, client_view()->ok_button());
    147   EXPECT_TRUE(client_view()->cancel_button()->is_default());
    148   EXPECT_EQ(GetUpdatedClientBounds().height(), height_with_buttons);
    149 }
    150 
    151 TEST_F(DialogClientViewTest, RemoveAndUpdateButtons) {
    152   // Removing buttons from another context should clear the local pointer.
    153   SetDialogButtons(ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL);
    154   delete client_view()->ok_button();
    155   EXPECT_EQ(NULL, client_view()->ok_button());
    156   delete client_view()->cancel_button();
    157   EXPECT_EQ(NULL, client_view()->cancel_button());
    158 
    159   // Updating should restore the requested buttons properly.
    160   SetDialogButtons(ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL);
    161   EXPECT_TRUE(client_view()->ok_button()->is_default());
    162   EXPECT_FALSE(client_view()->cancel_button()->is_default());
    163 }
    164 
    165 // Test that the contents view gets its preferred size in the basic dialog
    166 // configuration.
    167 TEST_F(DialogClientViewTest, ContentsSize) {
    168   CheckContentsIsSetToPreferredSize();
    169   EXPECT_EQ(GetContentsView()->bounds().bottom(),
    170             client_view()->bounds().bottom());
    171 }
    172 
    173 // Test the effect of the button strip on layout.
    174 TEST_F(DialogClientViewTest, LayoutWithButtons) {
    175   SetDialogButtons(ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL);
    176   CheckContentsIsSetToPreferredSize();
    177   EXPECT_LT(GetContentsView()->bounds().bottom(),
    178             client_view()->bounds().bottom());
    179   gfx::Size no_extra_view_size = client_view()->bounds().size();
    180 
    181   View* extra_view = new StaticSizedView(gfx::Size(200, 200));
    182   SetExtraView(extra_view);
    183   CheckContentsIsSetToPreferredSize();
    184   EXPECT_GT(client_view()->bounds().height(), no_extra_view_size.height());
    185   int width_of_extra_view = extra_view->bounds().width();
    186 
    187   // Visibility of extra view is respected.
    188   extra_view->SetVisible(false);
    189   CheckContentsIsSetToPreferredSize();
    190   EXPECT_EQ(no_extra_view_size.height(), client_view()->bounds().height());
    191   EXPECT_EQ(no_extra_view_size.width(), client_view()->bounds().width());
    192 
    193   // Try with a reduced-size dialog.
    194   extra_view->SetVisible(true);
    195   client_view()->SetBoundsRect(gfx::Rect(gfx::Point(0, 0), no_extra_view_size));
    196   client_view()->Layout();
    197   DCHECK_GT(width_of_extra_view, extra_view->bounds().width());
    198 }
    199 
    200 // Test the effect of the footnote view on layout.
    201 TEST_F(DialogClientViewTest, LayoutWithFootnote) {
    202   CheckContentsIsSetToPreferredSize();
    203   gfx::Size no_footnote_size = client_view()->bounds().size();
    204 
    205   View* footnote_view = new StaticSizedView(gfx::Size(200, 200));
    206   SetFootnoteView(footnote_view);
    207   CheckContentsIsSetToPreferredSize();
    208   EXPECT_GT(client_view()->bounds().height(), no_footnote_size.height());
    209   EXPECT_EQ(200, footnote_view->bounds().height());
    210   gfx::Size with_footnote_size = client_view()->bounds().size();
    211   EXPECT_EQ(with_footnote_size.width(), footnote_view->bounds().width());
    212 
    213   SetDialogButtons(ui::DIALOG_BUTTON_CANCEL);
    214   CheckContentsIsSetToPreferredSize();
    215   EXPECT_LE(with_footnote_size.height(), client_view()->bounds().height());
    216   EXPECT_LE(with_footnote_size.width(), client_view()->bounds().width());
    217   gfx::Size with_footnote_and_button_size = client_view()->bounds().size();
    218 
    219   SetDialogButtons(ui::DIALOG_BUTTON_NONE);
    220   footnote_view->SetVisible(false);
    221   CheckContentsIsSetToPreferredSize();
    222   EXPECT_EQ(no_footnote_size.height(), client_view()->bounds().height());
    223   EXPECT_EQ(no_footnote_size.width(), client_view()->bounds().width());
    224 }
    225 
    226 // Test that GetHeightForWidth is respected for the footnote view.
    227 TEST_F(DialogClientViewTest, LayoutWithFootnoteHeightForWidth) {
    228   CheckContentsIsSetToPreferredSize();
    229   gfx::Size no_footnote_size = client_view()->bounds().size();
    230 
    231   View* footnote_view = new ProportionallySizedView(3);
    232   SetFootnoteView(footnote_view);
    233   CheckContentsIsSetToPreferredSize();
    234   EXPECT_GT(client_view()->bounds().height(), no_footnote_size.height());
    235   EXPECT_EQ(footnote_view->bounds().width() * 3,
    236             footnote_view->bounds().height());
    237 }
    238 
    239 // Test that the DialogClientView's FocusManager is properly updated when the
    240 // DialogClientView belongs to a non top level widget and the widget is
    241 // reparented. The DialogClientView belongs to a non top level widget in the
    242 // case of constrained windows. The constrained window's widget is reparented
    243 // when a browser tab is dragged to a different browser window.
    244 TEST_F(DialogClientViewTest, FocusManager) {
    245   scoped_ptr<Widget> toplevel1(new Widget);
    246   Widget::InitParams toplevel1_params =
    247       CreateParams(Widget::InitParams::TYPE_WINDOW);
    248   toplevel1_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
    249   toplevel1->Init(toplevel1_params);
    250 
    251   scoped_ptr<Widget> toplevel2(new Widget);
    252   Widget::InitParams toplevel2_params =
    253       CreateParams(Widget::InitParams::TYPE_WINDOW);
    254   toplevel2_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
    255   toplevel2->Init(toplevel2_params);
    256 
    257   Widget* dialog = new Widget;
    258   Widget::InitParams dialog_params =
    259       CreateParams(Widget::InitParams::TYPE_WINDOW);
    260   dialog_params.child = true;
    261   dialog_params.delegate = new DialogDelegateView();
    262   dialog_params.parent = toplevel1->GetNativeView();
    263   dialog->Init(dialog_params);
    264 
    265   // Test that the FocusManager has been properly set when the DialogClientView
    266   // was parented to |dialog|.
    267   DialogClientView* client_view =
    268       static_cast<DialogClientView*>(dialog->client_view());
    269   EXPECT_EQ(toplevel1->GetFocusManager(), client_view->focus_manager_);
    270 
    271   // Test that the FocusManager is properly updated when the DialogClientView's
    272   // top level widget is changed.
    273   Widget::ReparentNativeView(dialog->GetNativeView(), NULL);
    274   EXPECT_EQ(NULL, client_view->focus_manager_);
    275   Widget::ReparentNativeView(dialog->GetNativeView(),
    276                              toplevel2->GetNativeView());
    277   EXPECT_EQ(toplevel2->GetFocusManager(), client_view->focus_manager_);
    278   Widget::ReparentNativeView(dialog->GetNativeView(),
    279                              toplevel1->GetNativeView());
    280   EXPECT_NE(toplevel1->GetFocusManager(), toplevel2->GetFocusManager());
    281   EXPECT_EQ(toplevel1->GetFocusManager(), client_view->focus_manager_);
    282 
    283   // Test that the FocusManager is properly cleared when the DialogClientView is
    284   // removed from |dialog| during the widget's destruction.
    285   client_view->set_owned_by_client();
    286   scoped_ptr<DialogClientView> owned_client_view(client_view);
    287   toplevel1->CloseNow();
    288   toplevel2->CloseNow();
    289   EXPECT_EQ(NULL, owned_client_view->focus_manager_);
    290 }
    291 
    292 }  // namespace views
    293