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