Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/ui/views/first_run_bubble.h" | 5 #include "chrome/browser/ui/views/first_run_bubble.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/utf_string_conversions.h" | 8 #include "base/utf_string_conversions.h" |
| 9 #include "chrome/browser/first_run/first_run.h" | 9 #include "chrome/browser/first_run/first_run.h" |
| 10 #include "chrome/browser/search_engines/util.h" | 10 #include "chrome/browser/search_engines/util.h" |
| 11 #include "chrome/browser/ui/browser.h" | 11 #include "chrome/browser/ui/browser.h" |
| 12 #include "chrome/browser/ui/browser_list.h" | 12 #include "chrome/browser/ui/browser_list.h" |
| 13 #include "chrome/browser/ui/browser_window.h" | 13 #include "chrome/browser/ui/browser_window.h" |
| 14 #include "content/browser/user_metrics.h" | 14 #include "content/browser/user_metrics.h" |
| 15 #include "grit/chromium_strings.h" | 15 #include "grit/chromium_strings.h" |
| 16 #include "grit/generated_resources.h" | 16 #include "grit/generated_resources.h" |
| 17 #include "grit/locale_settings.h" | 17 #include "grit/locale_settings.h" |
| 18 #include "grit/theme_resources_standard.h" | 18 #include "grit/theme_resources_standard.h" |
| 19 #include "ui/base/l10n/l10n_font_util.h" | 19 #include "ui/base/l10n/l10n_font_util.h" |
| 20 #include "ui/base/l10n/l10n_util.h" | 20 #include "ui/base/l10n/l10n_util.h" |
| 21 #include "ui/base/resource/resource_bundle.h" | 21 #include "ui/base/resource/resource_bundle.h" |
| 22 #include "views/controls/button/image_button.h" | 22 #include "views/controls/button/image_button.h" |
| 23 #include "views/controls/button/text_button.h" | |
| 24 #include "views/controls/label.h" | 23 #include "views/controls/label.h" |
| 25 #include "views/events/event.h" | 24 #include "views/events/event.h" |
| 26 #include "views/focus/focus_manager.h" | 25 #include "views/focus/focus_manager.h" |
| 26 #include "views/layout/fill_layout.h" | |
| 27 #include "views/layout/grid_layout.h" | |
| 27 #include "views/layout/layout_constants.h" | 28 #include "views/layout/layout_constants.h" |
| 29 #if defined(OS_WIN) && !defined(USE_AURA) | |
| 28 #include "views/widget/native_widget_win.h" | 30 #include "views/widget/native_widget_win.h" |
| 31 #endif | |
| 29 #include "views/widget/widget.h" | 32 #include "views/widget/widget.h" |
| 30 | 33 |
| 31 namespace { | 34 // FirstRunBubbleView -------------------------------------------------- |
| 32 | 35 |
| 33 // How much extra padding to put around our content over what the Bubble | 36 class FirstRunBubbleView : public views::View, |
|
msw
2011/11/03 20:25:38
It's very awesome that we've consolidated the firs
alicet1
2011/11/04 22:37:36
giving it a try.
| |
| 34 // provides. | 37 public views::ButtonListener, |
| 35 const int kBubblePadding = 4; | 38 public views::FocusChangeListener { |
| 36 | |
| 37 // How much extra padding to put around our content over what the Bubble | |
| 38 // provides in alternative OEM bubble. | |
| 39 const int kOEMBubblePadding = 4; | |
| 40 | |
| 41 // Padding between parts of strings on the same line (for instance, | |
| 42 // "New!" and "Search from the address bar!" | |
| 43 const int kStringSeparationPadding = 2; | |
| 44 | |
| 45 // Margin around close button. | |
| 46 const int kMarginRightOfCloseButton = 7; | |
| 47 | |
| 48 // The bubble's HWND is actually owned by the border widget, and it's the border | |
| 49 // widget that's owned by the frame window the bubble is anchored to. This | |
| 50 // function makes the two leaps necessary to go from the bubble contents HWND | |
| 51 // to the frame HWND. | |
| 52 HWND GetLogicalBubbleOwner(HWND bubble_hwnd) { | |
| 53 HWND border_widget_hwnd = GetWindow(bubble_hwnd, GW_OWNER); | |
| 54 return GetWindow(border_widget_hwnd, GW_OWNER); | |
| 55 } | |
| 56 | |
| 57 } // namespace | |
| 58 | |
| 59 // Base class for implementations of the client view which appears inside the | |
| 60 // first run bubble. It is a dialog-ish view, but is not a true dialog. | |
| 61 class FirstRunBubbleViewBase : public views::View, | |
| 62 public views::ButtonListener, | |
| 63 public views::FocusChangeListener { | |
| 64 public: | |
| 65 // Called by FirstRunBubble::Show to request focus for the proper button | |
| 66 // in the FirstRunBubbleView when it is shown. | |
| 67 virtual void BubbleShown() = 0; | |
| 68 }; | |
| 69 | |
| 70 // FirstRunBubbleView --------------------------------------------------------- | |
| 71 | |
| 72 class FirstRunBubbleView : public FirstRunBubbleViewBase { | |
| 73 public: | 39 public: |
| 74 FirstRunBubbleView(FirstRunBubble* bubble_window, Profile* profile); | 40 FirstRunBubbleView(FirstRunBubble* bubble_window, Profile* profile); |
| 75 | 41 |
| 42 // Initialize labels used in the first run bubble. | |
| 43 void InitContents(); | |
| 44 | |
| 76 private: | 45 private: |
| 77 virtual ~FirstRunBubbleView() {} | 46 virtual ~FirstRunBubbleView(); |
| 78 | 47 |
| 79 // FirstRunBubbleViewBase: | 48 // Overrides from ButtonListener: |
| 80 virtual void BubbleShown(); | 49 virtual void ButtonPressed(views::Button* sender, |
| 50 const views::Event& event) OVERRIDE; | |
| 81 | 51 |
| 82 // Overridden from View: | 52 // Implements views::FocusChangeListener |
| 83 virtual void ButtonPressed(views::Button* sender, const views::Event& event); | 53 void FocusWillChange(View* focused_before, View* focused_now); |
| 84 virtual void Layout(); | |
| 85 virtual gfx::Size GetPreferredSize(); | |
| 86 | |
| 87 // FocusChangeListener: | |
| 88 virtual void FocusWillChange(View* focused_before, View* focused_now); | |
| 89 | 54 |
| 90 FirstRunBubble* bubble_window_; | 55 FirstRunBubble* bubble_window_; |
| 56 Profile* profile_; | |
| 91 views::Label* label1_; | 57 views::Label* label1_; |
| 92 views::Label* label2_; | 58 views::Label* label2_; |
| 93 views::Label* label3_; | 59 views::Label* label3_; |
|
msw
2011/11/03 20:25:38
label3_ is no longer used, please remove it.
alicet1
2011/11/04 22:37:36
Done.
| |
| 94 views::NativeTextButton* change_button_; | 60 views::ImageButton* close_button_; |
| 95 views::NativeTextButton* keep_button_; | |
| 96 Profile* profile_; | |
| 97 | 61 |
| 98 DISALLOW_COPY_AND_ASSIGN(FirstRunBubbleView); | 62 DISALLOW_COPY_AND_ASSIGN(FirstRunBubbleView); |
| 99 }; | 63 }; |
| 100 | 64 |
| 101 FirstRunBubbleView::FirstRunBubbleView(FirstRunBubble* bubble_window, | 65 FirstRunBubbleView::FirstRunBubbleView(FirstRunBubble* bubble_window, |
| 102 Profile* profile) | 66 Profile* profile) |
| 103 : bubble_window_(bubble_window), | 67 : bubble_window_(bubble_window), |
| 68 profile_(profile), | |
| 104 label1_(NULL), | 69 label1_(NULL), |
| 105 label2_(NULL), | 70 label2_(NULL), |
| 106 label3_(NULL), | 71 label3_(NULL), |
| 107 keep_button_(NULL), | 72 close_button_(NULL) {} |
| 108 change_button_(NULL), | |
| 109 profile_(profile) { | |
| 110 const gfx::Font& font = | |
| 111 ResourceBundle::GetSharedInstance().GetFont(ResourceBundle::MediumFont); | |
| 112 | 73 |
| 113 label1_ = new views::Label(l10n_util::GetStringUTF16(IDS_FR_BUBBLE_TITLE)); | 74 void FirstRunBubbleView::InitContents() { |
|
msw
2011/11/03 20:25:38
Can you remove any string resources that are now u
alicet1
2011/11/04 22:37:36
I'll file a bug to clean when cleaning the gtk cas
| |
| 114 label1_->SetFont(font.DeriveFont(3, gfx::Font::BOLD)); | 75 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); |
| 115 label1_->SetBackgroundColor(Bubble::kBackgroundColor); | 76 const gfx::Font& original_font = rb.GetFont(ResourceBundle::MediumFont); |
| 77 const gfx::Font& derived_font = original_font.DeriveFont(2, gfx::Font::BOLD); | |
| 78 | |
| 79 label1_ = new views::Label(l10n_util::GetStringFUTF16( | |
| 80 IDS_FR_SE_BUBBLE_TITLE, | |
| 81 GetDefaultSearchEngineName(profile_))); | |
| 82 label1_->SetFont(derived_font); | |
| 116 label1_->SetHorizontalAlignment(views::Label::ALIGN_LEFT); | 83 label1_->SetHorizontalAlignment(views::Label::ALIGN_LEFT); |
| 117 AddChildView(label1_); | |
| 118 | |
| 119 gfx::Size ps = GetPreferredSize(); | |
| 120 | |
| 121 label2_ = new views::Label(l10n_util::GetStringUTF16(IDS_FR_BUBBLE_SUBTEXT)); | |
| 122 label2_->SetMultiLine(true); | |
| 123 label2_->SetFont(font); | |
| 124 label2_->SetBackgroundColor(Bubble::kBackgroundColor); | |
| 125 label2_->SetHorizontalAlignment(views::Label::ALIGN_LEFT); | |
| 126 label2_->SizeToFit(ps.width() - kBubblePadding * 2); | |
| 127 AddChildView(label2_); | |
| 128 | |
| 129 string16 question_str = l10n_util::GetStringFUTF16( | |
| 130 IDS_FR_BUBBLE_QUESTION, | |
| 131 GetDefaultSearchEngineName(profile)); | |
| 132 label3_ = new views::Label(question_str); | |
| 133 label3_->SetMultiLine(true); | |
| 134 label3_->SetFont(font); | |
| 135 label3_->SetBackgroundColor(Bubble::kBackgroundColor); | |
| 136 label3_->SetHorizontalAlignment(views::Label::ALIGN_LEFT); | |
| 137 label3_->SizeToFit(ps.width() - kBubblePadding * 2); | |
| 138 AddChildView(label3_); | |
| 139 | |
| 140 std::wstring keep_str = UTF16ToWide(l10n_util::GetStringFUTF16( | |
| 141 IDS_FR_BUBBLE_OK, | |
| 142 GetDefaultSearchEngineName(profile))); | |
| 143 keep_button_ = new views::NativeTextButton(this, keep_str); | |
| 144 keep_button_->SetIsDefault(true); | |
| 145 AddChildView(keep_button_); | |
| 146 | |
| 147 std::wstring change_str = | |
| 148 UTF16ToWide(l10n_util::GetStringUTF16(IDS_FR_BUBBLE_CHANGE)); | |
| 149 change_button_ = new views::NativeTextButton(this, change_str); | |
| 150 AddChildView(change_button_); | |
| 151 } | |
| 152 | |
| 153 void FirstRunBubbleView::BubbleShown() { | |
| 154 keep_button_->RequestFocus(); | |
| 155 } | |
| 156 | |
| 157 void FirstRunBubbleView::ButtonPressed(views::Button* sender, | |
| 158 const views::Event& event) { | |
| 159 UserMetrics::RecordAction(UserMetricsAction("FirstRunBubbleView_Clicked")); | |
| 160 bubble_window_->set_fade_away_on_close(true); | |
| 161 bubble_window_->Close(); | |
| 162 if (change_button_ == sender) { | |
| 163 UserMetrics::RecordAction( | |
| 164 UserMetricsAction("FirstRunBubbleView_ChangeButton")); | |
| 165 | |
| 166 Browser* browser = BrowserList::GetLastActiveWithProfile(profile_); | |
| 167 if (browser) { | |
| 168 browser->OpenSearchEngineOptionsDialog(); | |
| 169 } | |
| 170 } | |
| 171 } | |
| 172 | |
| 173 void FirstRunBubbleView::Layout() { | |
| 174 gfx::Size canvas = GetPreferredSize(); | |
| 175 | |
| 176 // The multiline business that follows is dirty hacks to get around | |
| 177 // bug 1325257. | |
| 178 label1_->SetMultiLine(false); | |
| 179 gfx::Size pref_size = label1_->GetPreferredSize(); | |
| 180 label1_->SetMultiLine(true); | |
| 181 label1_->SizeToFit(canvas.width() - kBubblePadding * 2); | |
| 182 label1_->SetBounds(kBubblePadding, kBubblePadding, | |
| 183 canvas.width() - kBubblePadding * 2, | |
| 184 pref_size.height()); | |
| 185 | |
| 186 int next_v_space = label1_->y() + pref_size.height() + | |
| 187 views::kRelatedControlSmallVerticalSpacing; | |
| 188 | |
| 189 pref_size = label2_->GetPreferredSize(); | |
| 190 label2_->SetBounds(kBubblePadding, next_v_space, | |
| 191 canvas.width() - kBubblePadding * 2, | |
| 192 pref_size.height()); | |
| 193 | |
| 194 next_v_space = label2_->y() + label2_->height() + | |
| 195 views::kPanelSubVerticalSpacing; | |
| 196 | |
| 197 pref_size = label3_->GetPreferredSize(); | |
| 198 label3_->SetBounds(kBubblePadding, next_v_space, | |
| 199 canvas.width() - kBubblePadding * 2, | |
| 200 pref_size.height()); | |
| 201 | |
| 202 pref_size = change_button_->GetPreferredSize(); | |
| 203 change_button_->SetBounds( | |
| 204 canvas.width() - pref_size.width() - kBubblePadding, | |
| 205 canvas.height() - pref_size.height() - views::kButtonVEdgeMargin, | |
| 206 pref_size.width(), pref_size.height()); | |
| 207 | |
| 208 pref_size = keep_button_->GetPreferredSize(); | |
| 209 keep_button_->SetBounds(change_button_->x() - pref_size.width() - | |
| 210 views::kRelatedButtonHSpacing, change_button_->y(), | |
| 211 pref_size.width(), pref_size.height()); | |
| 212 } | |
| 213 | |
| 214 gfx::Size FirstRunBubbleView::GetPreferredSize() { | |
| 215 return gfx::Size(views::Widget::GetLocalizedContentsSize( | |
| 216 IDS_FIRSTRUNBUBBLE_DIALOG_WIDTH_CHARS, | |
| 217 IDS_FIRSTRUNBUBBLE_DIALOG_HEIGHT_LINES)); | |
| 218 } | |
| 219 | |
| 220 void FirstRunBubbleView::FocusWillChange(View* focused_before, | |
| 221 View* focused_now) { | |
| 222 if (focused_before && | |
| 223 (focused_before->GetClassName() == | |
| 224 views::NativeTextButton::kViewClassName)) { | |
| 225 views::NativeTextButton* before = | |
| 226 static_cast<views::NativeTextButton*>(focused_before); | |
| 227 before->SetIsDefault(false); | |
| 228 } | |
| 229 if (focused_now && | |
| 230 (focused_now->GetClassName() == | |
| 231 views::NativeTextButton::kViewClassName)) { | |
| 232 views::NativeTextButton* after = | |
| 233 static_cast<views::NativeTextButton*>(focused_now); | |
| 234 after->SetIsDefault(true); | |
| 235 } | |
| 236 } | |
| 237 | |
| 238 // FirstRunOEMBubbleView ------------------------------------------------------ | |
| 239 | |
| 240 class FirstRunOEMBubbleView : public FirstRunBubbleViewBase { | |
| 241 public: | |
| 242 FirstRunOEMBubbleView(FirstRunBubble* bubble_window, Profile* profile); | |
| 243 | |
| 244 private: | |
| 245 virtual ~FirstRunOEMBubbleView() { } | |
| 246 | |
| 247 // FirstRunBubbleViewBase: | |
| 248 virtual void BubbleShown(); | |
| 249 | |
| 250 // Overridden from View: | |
| 251 virtual void ButtonPressed(views::Button* sender, const views::Event& event); | |
| 252 virtual void Layout(); | |
| 253 virtual gfx::Size GetPreferredSize(); | |
| 254 | |
| 255 // FocusChangeListener: | |
| 256 virtual void FocusWillChange(View* focused_before, View* focused_now); | |
| 257 | |
| 258 FirstRunBubble* bubble_window_; | |
| 259 views::Label* label1_; | |
| 260 views::Label* label2_; | |
| 261 views::Label* label3_; | |
| 262 views::ImageButton* close_button_; | |
| 263 Profile* profile_; | |
| 264 | |
| 265 DISALLOW_COPY_AND_ASSIGN(FirstRunOEMBubbleView); | |
| 266 }; | |
| 267 | |
| 268 FirstRunOEMBubbleView::FirstRunOEMBubbleView(FirstRunBubble* bubble_window, | |
| 269 Profile* profile) | |
| 270 : bubble_window_(bubble_window), | |
| 271 label1_(NULL), | |
| 272 label2_(NULL), | |
| 273 label3_(NULL), | |
| 274 close_button_(NULL), | |
| 275 profile_(profile) { | |
| 276 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); | |
| 277 const gfx::Font& font = rb.GetFont(ResourceBundle::MediumFont); | |
| 278 | |
| 279 label1_ = new views::Label( | |
| 280 l10n_util::GetStringUTF16(IDS_FR_OEM_BUBBLE_TITLE_1)); | |
| 281 label1_->SetFont(font.DeriveFont(3, gfx::Font::BOLD)); | |
| 282 label1_->SetBackgroundColor(Bubble::kBackgroundColor); | |
| 283 label1_->SetEnabledColor(SK_ColorRED); | |
| 284 label1_->SetHorizontalAlignment(views::Label::ALIGN_LEFT); | |
| 285 AddChildView(label1_); | |
| 286 | 84 |
| 287 label2_ = new views::Label( | 85 label2_ = new views::Label( |
| 288 l10n_util::GetStringUTF16(IDS_FR_OEM_BUBBLE_TITLE_2)); | 86 l10n_util::GetStringUTF16(IDS_FR_BUBBLE_SUBTEXT)); |
|
msw
2011/11/03 20:25:38
This should fit on the line above.
alicet1
2011/11/04 22:37:36
Done.
| |
| 289 label2_->SetFont(font.DeriveFont(3, gfx::Font::BOLD)); | 87 label2_->SetMultiLine(true); |
| 290 label2_->SetBackgroundColor(Bubble::kBackgroundColor); | 88 label2_->SetFont(original_font); |
| 291 label2_->SetHorizontalAlignment(views::Label::ALIGN_LEFT); | 89 label2_->SetHorizontalAlignment(views::Label::ALIGN_LEFT); |
| 292 AddChildView(label2_); | |
| 293 | |
| 294 gfx::Size ps = GetPreferredSize(); | |
| 295 | |
| 296 label3_ = new views::Label( | |
| 297 l10n_util::GetStringUTF16(IDS_FR_OEM_BUBBLE_SUBTEXT)); | |
| 298 label3_->SetMultiLine(true); | |
| 299 label3_->SetFont(font); | |
| 300 label3_->SetBackgroundColor(Bubble::kBackgroundColor); | |
| 301 label3_->SetHorizontalAlignment(views::Label::ALIGN_LEFT); | |
| 302 label3_->SizeToFit(ps.width() - kOEMBubblePadding * 2); | |
| 303 AddChildView(label3_); | |
| 304 | 90 |
| 305 close_button_ = new views::ImageButton(this); | 91 close_button_ = new views::ImageButton(this); |
| 306 close_button_->SetImage(views::CustomButton::BS_NORMAL, | 92 close_button_->SetImage(views::CustomButton::BS_NORMAL, |
| 307 rb.GetBitmapNamed(IDR_CLOSE_BAR)); | 93 rb.GetBitmapNamed(IDR_CLOSE_BAR)); |
| 308 close_button_->SetImage(views::CustomButton::BS_HOT, | 94 close_button_->SetImage(views::CustomButton::BS_HOT, |
| 309 rb.GetBitmapNamed(IDR_CLOSE_BAR_H)); | 95 rb.GetBitmapNamed(IDR_CLOSE_BAR_H)); |
| 310 close_button_->SetImage(views::CustomButton::BS_PUSHED, | 96 close_button_->SetImage(views::CustomButton::BS_PUSHED, |
| 311 rb.GetBitmapNamed(IDR_CLOSE_BAR_P)); | 97 rb.GetBitmapNamed(IDR_CLOSE_BAR_P)); |
| 98 gfx::Size sz = close_button_->GetPreferredSize(); | |
| 312 | 99 |
| 313 AddChildView(close_button_); | 100 views::GridLayout* layout = views::GridLayout::CreatePanel(this); |
| 101 SetLayoutManager(layout); | |
| 102 // TODO(alicet): fix this after padding change goes in. | |
| 103 layout->SetInsets(9, 7, 3, 7); | |
| 104 | |
| 105 views::ColumnSet* column_set = layout->AddColumnSet(0); | |
| 106 column_set->AddColumn(views::GridLayout::LEADING, | |
| 107 views::GridLayout::LEADING, 1, | |
| 108 views::GridLayout::USE_PREF, 0, 0); | |
| 109 column_set->AddColumn(views::GridLayout::TRAILING, views::GridLayout::FILL, 0, | |
| 110 views::GridLayout::USE_PREF, 0, 0); | |
| 111 | |
| 112 layout->StartRow(0, 0); | |
| 113 layout->AddView(label1_); | |
| 114 layout->AddView(close_button_, 1, 1, views::GridLayout::TRAILING, | |
| 115 views::GridLayout::LEADING); | |
| 116 layout->AddPaddingRow(0, views::kRelatedControlSmallVerticalSpacing); | |
| 117 | |
| 118 layout->StartRow(0, 0); | |
| 119 layout->AddView(label2_); | |
| 120 layout->AddPaddingRow(0, views::kRelatedControlSmallVerticalSpacing); | |
| 121 | |
| 122 bubble_window_->GetWidget()->GetFocusManager()->AddFocusChangeListener(this); | |
| 314 } | 123 } |
| 315 | 124 |
| 316 void FirstRunOEMBubbleView::BubbleShown() { | 125 void FirstRunBubbleView::ButtonPressed(views::Button* sender, |
| 317 RequestFocus(); | 126 const views::Event& event) { |
| 318 // No button in oem_bubble to request focus. | 127 UserMetrics::RecordAction( |
| 128 UserMetricsAction("FirstRunOEMBubbleView_Clicked")); | |
|
msw
2011/11/03 20:25:38
We should make sure we're recording the right metr
alicet1
2011/11/04 22:37:36
Interesting, I think this may be the only case we
| |
| 129 bubble_window_->GetWidget()->Close(); | |
| 319 } | 130 } |
| 320 | 131 |
| 321 void FirstRunOEMBubbleView::ButtonPressed(views::Button* sender, | 132 FirstRunBubbleView::~FirstRunBubbleView() { |
| 322 const views::Event& event) { | 133 if (GetFocusManager()) |
| 323 UserMetrics::RecordAction( | 134 GetFocusManager()->RemoveFocusChangeListener(this); |
| 324 UserMetricsAction("FirstRunOEMBubbleView_Clicked")); | |
| 325 bubble_window_->set_fade_away_on_close(true); | |
| 326 bubble_window_->Close(); | |
| 327 } | 135 } |
| 328 | 136 |
| 329 void FirstRunOEMBubbleView::Layout() { | 137 void FirstRunBubbleView::FocusWillChange(View* focused_before, |
|
msw
2011/11/03 20:25:38
This is unfortunately wrong, but luckily you can r
alicet1
2011/11/04 22:37:36
Done.
| |
| 330 gfx::Size canvas = GetPreferredSize(); | 138 View* focused_now) { |
| 331 | 139 // TODO(alicet): this should be in the DidChangeFocus() call |
| 332 // First, draw the close button on the far right. | 140 // when that is checked in. |
| 333 gfx::Size sz = close_button_->GetPreferredSize(); | 141 if (!Contains(focused_now)) { |
| 334 close_button_->SetBounds( | 142 bubble_window_->GetWidget()->Close(); |
| 335 canvas.width() - sz.width() - kMarginRightOfCloseButton, | 143 } |
| 336 kOEMBubblePadding, sz.width(), sz.height()); | |
| 337 | |
| 338 gfx::Size pref_size = label1_->GetPreferredSize(); | |
| 339 label1_->SetBounds(kOEMBubblePadding, kOEMBubblePadding, | |
| 340 pref_size.width() + kOEMBubblePadding * 2, | |
| 341 pref_size.height()); | |
| 342 | |
| 343 pref_size = label2_->GetPreferredSize(); | |
| 344 label2_->SetBounds( | |
| 345 kOEMBubblePadding * 2 + label1_->GetPreferredSize().width(), | |
| 346 kOEMBubblePadding, canvas.width() - kOEMBubblePadding * 2, | |
| 347 pref_size.height()); | |
| 348 | |
| 349 int next_v_space = | |
| 350 label1_->y() + pref_size.height() + | |
| 351 views::kRelatedControlSmallVerticalSpacing; | |
| 352 | |
| 353 pref_size = label3_->GetPreferredSize(); | |
| 354 label3_->SetBounds(kOEMBubblePadding, next_v_space, | |
| 355 canvas.width() - kOEMBubblePadding * 2, | |
| 356 pref_size.height()); | |
| 357 } | 144 } |
| 358 | 145 |
| 359 gfx::Size FirstRunOEMBubbleView::GetPreferredSize() { | |
| 360 // Calculate width based on font and text. | |
| 361 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); | |
| 362 const gfx::Font& font = rb.GetFont( | |
| 363 ResourceBundle::MediumFont).DeriveFont(3, gfx::Font::BOLD); | |
| 364 gfx::Size size = gfx::Size( | |
| 365 ui::GetLocalizedContentsWidthForFont( | |
| 366 IDS_FIRSTRUNOEMBUBBLE_DIALOG_WIDTH_CHARS, font), | |
| 367 ui::GetLocalizedContentsHeightForFont( | |
| 368 IDS_FIRSTRUNOEMBUBBLE_DIALOG_HEIGHT_LINES, font)); | |
| 369 | |
| 370 // WARNING: HACK. Vista and XP calculate font size differently; this means | |
| 371 // that a dialog box correctly proportioned for XP will appear too large in | |
| 372 // Vista. The correct thing to do is to change font size calculations in | |
| 373 // XP or Vista so that the length of a string is calculated properly. For | |
| 374 // now, we force Vista to show a correctly-sized box by taking account of | |
| 375 // the difference in font size calculation. The coefficient should not be | |
| 376 // stored in a variable because it's a hack and should go away. | |
| 377 if (views::NativeWidgetWin::IsAeroGlassEnabled()) { | |
| 378 size.set_width(static_cast<int>(size.width() * 0.85)); | |
| 379 size.set_height(static_cast<int>(size.height() * 0.85)); | |
| 380 } | |
| 381 return size; | |
| 382 } | |
| 383 | |
| 384 void FirstRunOEMBubbleView::FocusWillChange(View* focused_before, | |
| 385 View* focused_now) { | |
| 386 // No buttons in oem_bubble to register focus changes. | |
| 387 } | |
| 388 | |
| 389 // FirstRunMinimalBubbleView -------------------------------------------------- | |
| 390 // TODO(mirandac): combine FRBubbles more elegantly. http://crbug.com/41353 | |
| 391 | |
| 392 class FirstRunMinimalBubbleView : public FirstRunBubbleViewBase { | |
| 393 public: | |
| 394 FirstRunMinimalBubbleView(FirstRunBubble* bubble_window, Profile* profile); | |
| 395 | |
| 396 private: | |
| 397 virtual ~FirstRunMinimalBubbleView() { } | |
| 398 | |
| 399 // FirstRunBubbleViewBase: | |
| 400 virtual void BubbleShown(); | |
| 401 | |
| 402 // Overridden from View: | |
| 403 virtual void ButtonPressed(views::Button* sender, | |
| 404 const views::Event& event) { } | |
| 405 virtual void Layout(); | |
| 406 virtual gfx::Size GetPreferredSize(); | |
| 407 | |
| 408 // FocusChangeListener: | |
| 409 virtual void FocusWillChange(View* focused_before, View* focused_now); | |
| 410 | |
| 411 FirstRunBubble* bubble_window_; | |
| 412 Profile* profile_; | |
| 413 views::Label* label1_; | |
| 414 views::Label* label2_; | |
| 415 | |
| 416 DISALLOW_COPY_AND_ASSIGN(FirstRunMinimalBubbleView); | |
| 417 }; | |
| 418 | |
| 419 FirstRunMinimalBubbleView::FirstRunMinimalBubbleView( | |
| 420 FirstRunBubble* bubble_window, | |
| 421 Profile* profile) | |
| 422 : bubble_window_(bubble_window), | |
| 423 profile_(profile), | |
| 424 label1_(NULL), | |
| 425 label2_(NULL) { | |
| 426 const gfx::Font& font = | |
| 427 ResourceBundle::GetSharedInstance().GetFont(ResourceBundle::MediumFont); | |
| 428 | |
| 429 label1_ = new views::Label(l10n_util::GetStringFUTF16( | |
| 430 IDS_FR_SE_BUBBLE_TITLE, | |
| 431 GetDefaultSearchEngineName(profile_))); | |
| 432 label1_->SetFont(font.DeriveFont(3, gfx::Font::BOLD)); | |
| 433 label1_->SetBackgroundColor(Bubble::kBackgroundColor); | |
| 434 label1_->SetHorizontalAlignment(views::Label::ALIGN_LEFT); | |
| 435 AddChildView(label1_); | |
| 436 | |
| 437 gfx::Size ps = GetPreferredSize(); | |
| 438 | |
| 439 label2_ = new views::Label( | |
| 440 l10n_util::GetStringUTF16(IDS_FR_BUBBLE_SUBTEXT)); | |
| 441 label2_->SetMultiLine(true); | |
| 442 label2_->SetFont(font); | |
| 443 label2_->SetBackgroundColor(Bubble::kBackgroundColor); | |
| 444 label2_->SetHorizontalAlignment(views::Label::ALIGN_LEFT); | |
| 445 label2_->SizeToFit(ps.width() - kBubblePadding * 2); | |
| 446 AddChildView(label2_); | |
| 447 } | |
| 448 | |
| 449 void FirstRunMinimalBubbleView::BubbleShown() { | |
| 450 RequestFocus(); | |
| 451 } | |
| 452 | |
| 453 void FirstRunMinimalBubbleView::Layout() { | |
| 454 gfx::Size canvas = GetPreferredSize(); | |
| 455 | |
| 456 // See comments in FirstRunOEMBubbleView::Layout explaining this hack. | |
| 457 label1_->SetMultiLine(false); | |
| 458 gfx::Size pref_size = label1_->GetPreferredSize(); | |
| 459 label1_->SetMultiLine(true); | |
| 460 label1_->SizeToFit(canvas.width() - kBubblePadding * 2); | |
| 461 label1_->SetBounds(kBubblePadding, kBubblePadding, | |
| 462 canvas.width() - kBubblePadding * 2, | |
| 463 pref_size.height()); | |
| 464 | |
| 465 int next_v_space = label1_->y() + pref_size.height() + | |
| 466 views::kRelatedControlSmallVerticalSpacing; | |
| 467 | |
| 468 pref_size = label2_->GetPreferredSize(); | |
| 469 label2_->SetBounds(kBubblePadding, next_v_space, | |
| 470 canvas.width() - kBubblePadding * 2, | |
| 471 pref_size.height()); | |
| 472 } | |
| 473 | |
| 474 gfx::Size FirstRunMinimalBubbleView::GetPreferredSize() { | |
| 475 return gfx::Size(views::Widget::GetLocalizedContentsSize( | |
| 476 IDS_FIRSTRUN_MINIMAL_BUBBLE_DIALOG_WIDTH_CHARS, | |
| 477 IDS_FIRSTRUN_MINIMAL_BUBBLE_DIALOG_HEIGHT_LINES)); | |
| 478 } | |
| 479 | |
| 480 void FirstRunMinimalBubbleView::FocusWillChange(View* focused_before, | |
| 481 View* focused_now) { | |
| 482 // No buttons in minimal bubble to register focus changes. | |
| 483 } | |
| 484 | |
| 485 | |
| 486 // FirstRunBubble ------------------------------------------------------------- | 146 // FirstRunBubble ------------------------------------------------------------- |
| 487 | 147 |
| 488 // static | 148 // static |
| 489 FirstRunBubble* FirstRunBubble::Show( | 149 FirstRunBubble* FirstRunBubble::Show( |
| 490 Profile* profile, | 150 Profile* profile, |
| 491 views::Widget* parent, | 151 views::Widget* parent, |
| 492 const gfx::Rect& position_relative_to, | 152 const gfx::Rect& position_relative_to, |
| 493 views::BubbleBorder::ArrowLocation arrow_location, | 153 views::BubbleBorder::ArrowLocation arrow_location) { |
| 494 FirstRun::BubbleType bubble_type) { | 154 FirstRunBubble* delegate = |
| 495 FirstRunBubble* bubble = new FirstRunBubble(); | 155 new FirstRunBubble(profile, |
| 496 FirstRunBubbleViewBase* view = NULL; | 156 parent, |
| 497 | 157 position_relative_to, |
| 498 switch (bubble_type) { | 158 arrow_location); |
| 499 case FirstRun::OEM_BUBBLE: | 159 views::BubbleDelegateView::CreateBubble(delegate, parent); |
| 500 view = new FirstRunOEMBubbleView(bubble, profile); | 160 delegate->StartFade(true); |
| 501 break; | 161 return delegate; |
| 502 case FirstRun::LARGE_BUBBLE: | |
| 503 view = new FirstRunBubbleView(bubble, profile); | |
| 504 break; | |
| 505 case FirstRun::MINIMAL_BUBBLE: | |
| 506 view = new FirstRunMinimalBubbleView(bubble, profile); | |
| 507 break; | |
| 508 default: | |
| 509 NOTREACHED(); | |
| 510 } | |
| 511 bubble->set_view(view); | |
| 512 bubble->InitBubble( | |
| 513 parent, position_relative_to, arrow_location, view, bubble); | |
| 514 bubble->GetWidget()->GetFocusManager()->AddFocusChangeListener(view); | |
| 515 view->BubbleShown(); | |
| 516 return bubble; | |
| 517 } | 162 } |
| 518 | 163 |
| 519 FirstRunBubble::FirstRunBubble() | 164 void FirstRunBubble::Init() { |
| 520 : has_been_activated_(false), | 165 SetLayoutManager(new views::FillLayout()); |
| 521 ALLOW_THIS_IN_INITIALIZER_LIST(enable_window_method_factory_(this)), | 166 view = new FirstRunBubbleView(this, profile_); |
| 522 view_(NULL) { | 167 view->InitContents(); |
| 168 AddChildView(view); | |
| 169 } | |
| 170 | |
| 171 FirstRunBubble::FirstRunBubble( | |
| 172 Profile* profile, | |
| 173 views::Widget* parent, | |
| 174 const gfx::Rect& position_relative_to, | |
| 175 views::BubbleBorder::ArrowLocation arrow_location) | |
| 176 : views::BubbleDelegateView(position_relative_to.origin(), | |
| 177 arrow_location, | |
| 178 SK_ColorWHITE), | |
| 179 profile_(profile), | |
| 180 parent_(parent), | |
| 181 has_been_activated_(false), | |
| 182 ALLOW_THIS_IN_INITIALIZER_LIST(enable_window_method_factory_(this)) { | |
| 523 } | 183 } |
| 524 | 184 |
| 525 FirstRunBubble::~FirstRunBubble() { | 185 FirstRunBubble::~FirstRunBubble() { |
| 526 enable_window_method_factory_.InvalidateWeakPtrs(); | 186 enable_window_method_factory_.InvalidateWeakPtrs(); |
| 527 GetWidget()->GetFocusManager()->RemoveFocusChangeListener(view_); | |
| 528 } | 187 } |
| 529 | 188 |
| 189 #if defined(OS_WIN) && !defined(USE_AURA) | |
| 190 // TODO(alicet): do I still need this block. Must check on glass-frame mode. | |
|
msw
2011/11/03 20:25:38
It looks like this code is meant to prevent the bu
Miranda Callahan
2011/11/03 20:59:39
Yes, that's indeed what's happening; on Windows, t
Miranda Callahan
2011/11/03 21:04:07
Please see this CL, and accompanying comments for
msw
2011/11/03 21:46:24
Okay, if that's the case and we still have this my
alicet1
2011/11/04 22:37:36
ok, I'll work on that.
| |
| 530 void FirstRunBubble::EnableParent() { | 191 void FirstRunBubble::EnableParent() { |
| 531 ::EnableWindow(GetParent(), true); | 192 ::EnableWindow(GetParent(), true); |
| 532 // The EnableWindow() call above causes the parent to become active, which | 193 // The EnableWindow() call above causes the parent to become active, which |
| 533 // resets the flag set by Bubble's call to DisableInactiveRendering(), so we | 194 // resets the flag set by Bubble's call to DisableInactiveRendering(), so we |
| 534 // have to call it again before activating the bubble to prevent the parent | 195 // have to call it again before activating the bubble to prevent the parent |
| 535 // window from rendering inactive. | 196 // window from rendering inactive. |
| 536 // TODO(beng): this only works in custom-frame mode, not glass-frame mode. | 197 if (parent_) |
| 537 HWND bubble_owner = GetLogicalBubbleOwner(GetNativeView()); | 198 parent_->DisableInactiveRendering(); |
| 538 views::Widget* parent = views::Widget::GetWidgetForNativeView(bubble_owner); | |
| 539 if (parent) | |
| 540 parent->DisableInactiveRendering(); | |
| 541 // Reactivate the FirstRunBubble so it responds to OnActivate messages. | 199 // Reactivate the FirstRunBubble so it responds to OnActivate messages. |
| 542 SetWindowPos(GetParent(), 0, 0, 0, 0, | 200 SetWindowPos(GetParent(), 0, 0, 0, 0, |
| 543 SWP_NOSIZE | SWP_NOMOVE | SWP_NOREDRAW | SWP_SHOWWINDOW); | 201 SWP_NOSIZE | SWP_NOMOVE | SWP_NOREDRAW | SWP_SHOWWINDOW); |
| 544 } | 202 } |
| 545 | 203 |
| 546 #if defined(OS_WIN) && !defined(USE_AURA) | |
| 547 void FirstRunBubble::OnActivate(UINT action, BOOL minimized, HWND window) { | 204 void FirstRunBubble::OnActivate(UINT action, BOOL minimized, HWND window) { |
| 548 // Keep the bubble around for kLingerTime milliseconds, to prevent accidental | 205 // Keep the bubble around for kLingerTime milliseconds, to prevent accidental |
| 549 // closure. | 206 // closure. |
| 550 const int kLingerTime = 3000; | 207 const int kLingerTime = 3000; |
| 551 | 208 |
| 552 // We might get re-enabled right before we are closed (sequence is: we get | 209 // We might get re-enabled right before we are closed (sequence is: we get |
| 553 // deactivated, we call close, before we are actually closed we get | 210 // deactivated, we call close, before we are actually closed we get |
| 554 // reactivated). Don't do the disabling of the parent in such cases. | 211 // reactivated). Don't do the disabling of the parent in such cases. |
| 555 if (action == WA_ACTIVE && !has_been_activated_) { | 212 if (action == WA_ACTIVE && !has_been_activated_) { |
| 556 has_been_activated_ = true; | 213 has_been_activated_ = true; |
| 557 | 214 |
| 558 ::EnableWindow(GetParent(), false); | 215 ::EnableWindow(GetParent(), false); |
| 559 | 216 |
| 560 MessageLoop::current()->PostDelayedTask( | 217 MessageLoop::current()->PostDelayedTask( |
| 561 FROM_HERE, | 218 FROM_HERE, |
| 562 base::Bind(&FirstRunBubble::EnableParent, | 219 base::Bind(&FirstRunBubble::EnableParent, |
| 563 enable_window_method_factory_.GetWeakPtr()), | 220 enable_window_method_factory_.GetWeakPtr()), |
| 564 kLingerTime); | 221 kLingerTime); |
| 565 return; | 222 return; |
| 566 } | 223 } |
| 567 | 224 |
| 568 // Keep window from automatically closing until kLingerTime has passed. | 225 // Keep window from automatically closing until kLingerTime has passed. |
| 569 if (::IsWindowEnabled(GetParent())) | 226 if (::IsWindowEnabled(GetParent())) |
| 570 Bubble::OnActivate(action, minimized, window); | 227 Bubble::OnActivate(action, minimized, window); |
| 571 } | 228 } |
| 572 #endif | 229 #endif |
| 573 | 230 |
| 574 void FirstRunBubble::BubbleClosing(Bubble* bubble, bool closed_by_escape) { | 231 void FirstRunBubble::WindowClosing() { |
| 575 // Make sure our parent window is re-enabled. | 232 // Make sure our parent window is re-enabled. |
| 576 if (!IsWindowEnabled(GetParent())) | 233 if (parent_ && parent_->GetNativeView()) |
| 577 ::EnableWindow(GetParent(), true); | 234 GetFocusManager()->FocusNativeView(parent_->GetNativeView()); |
|
Ben Goodger (Google)
2011/11/03 20:14:07
Not your fault, just an observation: the comment h
msw
2011/11/03 20:25:38
This also shouldn't be necessary, or if it is, it'
alicet1
2011/11/04 22:37:36
removed.
| |
| 578 } | 235 } |
| OLD | NEW |