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 "testing/gtest/include/gtest/gtest.h" 8 #include "ui/base/ui_base_types.h" 9 #include "ui/views/controls/button/label_button.h" 10 #include "ui/views/test/test_views.h" 11 #include "ui/views/window/dialog_client_view.h" 12 #include "ui/views/window/dialog_delegate.h" 13 14 namespace views { 15 16 class TestDialogClientView : public DialogClientView { 17 public: 18 TestDialogClientView(View* contents_view, 19 DialogDelegate* dialog_delegate) 20 : DialogClientView(contents_view), 21 dialog_(dialog_delegate) {} 22 virtual ~TestDialogClientView() {} 23 24 // DialogClientView implementation. 25 virtual DialogDelegate* GetDialogDelegate() const OVERRIDE { return dialog_; } 26 27 View* GetContentsView() { return contents_view(); } 28 29 void CreateExtraViews() { 30 CreateExtraView(); 31 CreateFootnoteView(); 32 } 33 34 private: 35 DialogDelegate* dialog_; 36 37 DISALLOW_COPY_AND_ASSIGN(TestDialogClientView); 38 }; 39 40 class DialogClientViewTest : public testing::Test, 41 public DialogDelegateView { 42 public: 43 DialogClientViewTest() 44 : dialog_buttons_(ui::DIALOG_BUTTON_NONE), 45 extra_view_(NULL), 46 footnote_view_(NULL) {} 47 virtual ~DialogClientViewTest() {} 48 49 // testing::Test implementation. 50 virtual void SetUp() OVERRIDE { 51 dialog_buttons_ = ui::DIALOG_BUTTON_NONE; 52 contents_.reset(new StaticSizedView(gfx::Size(100, 200))); 53 client_view_.reset(new TestDialogClientView(contents_.get(), this)); 54 } 55 56 // DialogDelegateView implementation. 57 virtual View* GetContentsView() OVERRIDE { return contents_.get(); } 58 virtual View* CreateExtraView() OVERRIDE { return extra_view_; } 59 virtual View* CreateFootnoteView() OVERRIDE { return footnote_view_; } 60 virtual int GetDialogButtons() const OVERRIDE { return dialog_buttons_; } 61 62 protected: 63 gfx::Rect GetUpdatedClientBounds() { 64 client_view_->SizeToPreferredSize(); 65 client_view_->Layout(); 66 return client_view_->bounds(); 67 } 68 69 // Makes sure that the content view is sized correctly. Width must be at least 70 // the requested amount, but height should always match exactly. 71 void CheckContentsIsSetToPreferredSize() { 72 const gfx::Rect client_bounds = GetUpdatedClientBounds(); 73 const gfx::Size preferred_size = contents_->GetPreferredSize(); 74 EXPECT_EQ(preferred_size.height(), contents_->bounds().height()); 75 EXPECT_LE(preferred_size.width(), contents_->bounds().width()); 76 EXPECT_EQ(contents_->bounds().origin(), client_bounds.origin()); 77 EXPECT_EQ(contents_->bounds().right(), client_bounds.right()); 78 } 79 80 // Sets the buttons to show in the dialog and refreshes the dialog. 81 void SetDialogButtons(int dialog_buttons) { 82 dialog_buttons_ = dialog_buttons; 83 client_view_->UpdateDialogButtons(); 84 } 85 86 // Sets the extra view. 87 void SetExtraView(View* view) { 88 DCHECK(!extra_view_); 89 extra_view_ = view; 90 client_view_->CreateExtraViews(); 91 } 92 93 // Sets the footnote view. 94 void SetFootnoteView(View* view) { 95 DCHECK(!footnote_view_); 96 footnote_view_ = view; 97 client_view_->CreateExtraViews(); 98 } 99 100 TestDialogClientView* client_view() { return client_view_.get(); } 101 102 private: 103 // The contents of the dialog. 104 scoped_ptr<View> contents_; 105 // The DialogClientView that's being tested. 106 scoped_ptr<TestDialogClientView> client_view_; 107 // The bitmask of buttons to show in the dialog. 108 int dialog_buttons_; 109 View* extra_view_; // weak 110 View* footnote_view_; // weak 111 112 DISALLOW_COPY_AND_ASSIGN(DialogClientViewTest); 113 }; 114 115 TEST_F(DialogClientViewTest, UpdateButtons) { 116 // This dialog should start with no buttons. 117 EXPECT_EQ(GetDialogButtons(), ui::DIALOG_BUTTON_NONE); 118 EXPECT_EQ(NULL, client_view()->ok_button()); 119 EXPECT_EQ(NULL, client_view()->cancel_button()); 120 const int height_without_buttons = GetUpdatedClientBounds().height(); 121 122 // Update to use both buttons. 123 SetDialogButtons(ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL); 124 EXPECT_TRUE(client_view()->ok_button()->is_default()); 125 EXPECT_FALSE(client_view()->cancel_button()->is_default()); 126 const int height_with_buttons = GetUpdatedClientBounds().height(); 127 EXPECT_GT(height_with_buttons, height_without_buttons); 128 129 // Remove the dialog buttons. 130 SetDialogButtons(ui::DIALOG_BUTTON_NONE); 131 EXPECT_EQ(NULL, client_view()->ok_button()); 132 EXPECT_EQ(NULL, client_view()->cancel_button()); 133 EXPECT_EQ(GetUpdatedClientBounds().height(), height_without_buttons); 134 135 // Reset with just an ok button. 136 SetDialogButtons(ui::DIALOG_BUTTON_OK); 137 EXPECT_TRUE(client_view()->ok_button()->is_default()); 138 EXPECT_EQ(NULL, client_view()->cancel_button()); 139 EXPECT_EQ(GetUpdatedClientBounds().height(), height_with_buttons); 140 141 // Reset with just a cancel button. 142 SetDialogButtons(ui::DIALOG_BUTTON_CANCEL); 143 EXPECT_EQ(NULL, client_view()->ok_button()); 144 EXPECT_TRUE(client_view()->cancel_button()->is_default()); 145 EXPECT_EQ(GetUpdatedClientBounds().height(), height_with_buttons); 146 } 147 148 TEST_F(DialogClientViewTest, RemoveAndUpdateButtons) { 149 // Removing buttons from another context should clear the local pointer. 150 SetDialogButtons(ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL); 151 delete client_view()->ok_button(); 152 EXPECT_EQ(NULL, client_view()->ok_button()); 153 delete client_view()->cancel_button(); 154 EXPECT_EQ(NULL, client_view()->cancel_button()); 155 156 // Updating should restore the requested buttons properly. 157 SetDialogButtons(ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL); 158 EXPECT_TRUE(client_view()->ok_button()->is_default()); 159 EXPECT_FALSE(client_view()->cancel_button()->is_default()); 160 } 161 162 // Test that the contents view gets its preferred size in the basic dialog 163 // configuration. 164 TEST_F(DialogClientViewTest, ContentsSize) { 165 CheckContentsIsSetToPreferredSize(); 166 EXPECT_EQ(GetContentsView()->bounds().bottom(), 167 client_view()->bounds().bottom()); 168 } 169 170 // Test the effect of the button strip on layout. 171 TEST_F(DialogClientViewTest, LayoutWithButtons) { 172 SetDialogButtons(ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL); 173 CheckContentsIsSetToPreferredSize(); 174 EXPECT_LT(GetContentsView()->bounds().bottom(), 175 client_view()->bounds().bottom()); 176 gfx::Size no_extra_view_size = client_view()->bounds().size(); 177 178 View* extra_view = new StaticSizedView(gfx::Size(200, 200)); 179 SetExtraView(extra_view); 180 CheckContentsIsSetToPreferredSize(); 181 EXPECT_GT(client_view()->bounds().height(), no_extra_view_size.height()); 182 int width_of_extra_view = extra_view->bounds().width(); 183 184 // Visibility of extra view is respected. 185 extra_view->SetVisible(false); 186 CheckContentsIsSetToPreferredSize(); 187 EXPECT_EQ(no_extra_view_size.height(), client_view()->bounds().height()); 188 EXPECT_EQ(no_extra_view_size.width(), client_view()->bounds().width()); 189 190 // Try with a reduced-size dialog. 191 extra_view->SetVisible(true); 192 client_view()->SetBoundsRect(gfx::Rect(gfx::Point(0, 0), no_extra_view_size)); 193 client_view()->Layout(); 194 DCHECK_GT(width_of_extra_view, extra_view->bounds().width()); 195 } 196 197 // Test the effect of the footnote view on layout. 198 TEST_F(DialogClientViewTest, LayoutWithFootnote) { 199 CheckContentsIsSetToPreferredSize(); 200 gfx::Size no_footnote_size = client_view()->bounds().size(); 201 202 View* footnote_view = new StaticSizedView(gfx::Size(200, 200)); 203 SetFootnoteView(footnote_view); 204 CheckContentsIsSetToPreferredSize(); 205 EXPECT_GT(client_view()->bounds().height(), no_footnote_size.height()); 206 EXPECT_EQ(200, footnote_view->bounds().height()); 207 gfx::Size with_footnote_size = client_view()->bounds().size(); 208 EXPECT_EQ(with_footnote_size.width(), footnote_view->bounds().width()); 209 210 SetDialogButtons(ui::DIALOG_BUTTON_CANCEL); 211 CheckContentsIsSetToPreferredSize(); 212 EXPECT_LE(with_footnote_size.height(), client_view()->bounds().height()); 213 EXPECT_LE(with_footnote_size.width(), client_view()->bounds().width()); 214 gfx::Size with_footnote_and_button_size = client_view()->bounds().size(); 215 216 SetDialogButtons(ui::DIALOG_BUTTON_NONE); 217 footnote_view->SetVisible(false); 218 CheckContentsIsSetToPreferredSize(); 219 EXPECT_EQ(no_footnote_size.height(), client_view()->bounds().height()); 220 EXPECT_EQ(no_footnote_size.width(), client_view()->bounds().width()); 221 } 222 223 // Test that GetHeightForWidth is respected for the footnote view. 224 TEST_F(DialogClientViewTest, LayoutWithFootnoteHeightForWidth) { 225 CheckContentsIsSetToPreferredSize(); 226 gfx::Size no_footnote_size = client_view()->bounds().size(); 227 228 View* footnote_view = new ProportionallySizedView(3); 229 SetFootnoteView(footnote_view); 230 CheckContentsIsSetToPreferredSize(); 231 EXPECT_GT(client_view()->bounds().height(), no_footnote_size.height()); 232 EXPECT_EQ(footnote_view->bounds().width() * 3, 233 footnote_view->bounds().height()); 234 } 235 236 } // namespace views 237