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, |
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 // Overrides from views::FocusChangeListener |
83 virtual void ButtonPressed(views::Button* sender, const views::Event& event); | 53 void FocusWillChange(View* focused_before, View* focused_now); |
Miranda Callahan
2011/11/02 15:36:14
should also have OVERRIDE.
alicet1
2011/11/03 18:21:51
oops. sorry, it's an implementation of this interf
| |
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_; |
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() { |
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)); |
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, 10, 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); | |
314 } | 121 } |
315 | 122 |
316 void FirstRunOEMBubbleView::BubbleShown() { | 123 void FirstRunBubbleView::ButtonPressed(views::Button* sender, |
317 RequestFocus(); | 124 const views::Event& event) { |
318 // No button in oem_bubble to request focus. | 125 UserMetrics::RecordAction( |
126 UserMetricsAction("FirstRunOEMBubbleView_Clicked")); | |
127 bubble_window_->GetWidget()->Close(); | |
319 } | 128 } |
320 | 129 |
321 void FirstRunOEMBubbleView::ButtonPressed(views::Button* sender, | 130 FirstRunBubbleView::~FirstRunBubbleView() {} |
322 const views::Event& event) { | 131 |
323 UserMetrics::RecordAction( | 132 void FirstRunBubbleView::FocusWillChange(View* focused_before, |
324 UserMetricsAction("FirstRunOEMBubbleView_Clicked")); | 133 View* focused_now) { |
325 bubble_window_->set_fade_away_on_close(true); | 134 // TODO(alicet): this should be in the DidChangeFocus() call |
326 bubble_window_->Close(); | 135 // when that is checked in. |
136 if (!Contains(focused_now)) { | |
137 bubble_window_->GetWidget()->Close(); | |
138 } | |
327 } | 139 } |
328 | 140 |
329 void FirstRunOEMBubbleView::Layout() { | |
330 gfx::Size canvas = GetPreferredSize(); | |
331 | |
332 // First, draw the close button on the far right. | |
333 gfx::Size sz = close_button_->GetPreferredSize(); | |
334 close_button_->SetBounds( | |
335 canvas.width() - sz.width() - kMarginRightOfCloseButton, | |
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 } | |
358 | |
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 ------------------------------------------------------------- | 141 // FirstRunBubble ------------------------------------------------------------- |
487 | 142 |
488 // static | 143 // static |
489 FirstRunBubble* FirstRunBubble::Show( | 144 FirstRunBubble* FirstRunBubble::Show( |
490 Profile* profile, | 145 Profile* profile, |
491 views::Widget* parent, | 146 views::Widget* parent, |
492 const gfx::Rect& position_relative_to, | 147 const gfx::Rect& position_relative_to, |
493 views::BubbleBorder::ArrowLocation arrow_location, | 148 views::BubbleBorder::ArrowLocation arrow_location) { |
494 FirstRun::BubbleType bubble_type) { | 149 FirstRunBubble* delegate = |
495 FirstRunBubble* bubble = new FirstRunBubble(); | 150 new FirstRunBubble(profile, |
496 FirstRunBubbleViewBase* view = NULL; | 151 parent, |
497 | 152 position_relative_to, |
498 switch (bubble_type) { | 153 arrow_location); |
499 case FirstRun::OEM_BUBBLE: | 154 views::BubbleDelegateView::CreateBubble(delegate, parent); |
500 view = new FirstRunOEMBubbleView(bubble, profile); | 155 delegate->StartFade(true); |
501 break; | 156 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 } | 157 } |
518 | 158 |
519 FirstRunBubble::FirstRunBubble() | 159 void FirstRunBubble::Init() { |
520 : has_been_activated_(false), | 160 SetLayoutManager(new views::FillLayout()); |
521 ALLOW_THIS_IN_INITIALIZER_LIST(enable_window_method_factory_(this)), | 161 view_ = new FirstRunBubbleView(this, profile_); |
522 view_(NULL) { | 162 view_->InitContents(); |
163 AddChildView(view_); | |
164 } | |
165 | |
166 FirstRunBubble::FirstRunBubble( | |
167 Profile* profile, | |
168 views::Widget* parent, | |
169 const gfx::Rect& position_relative_to, | |
170 views::BubbleBorder::ArrowLocation arrow_location) | |
171 : views::BubbleDelegateView(position_relative_to.origin(), | |
172 arrow_location, | |
173 SK_ColorWHITE), | |
174 profile_(profile), | |
175 parent_(parent), | |
176 has_been_activated_(false), | |
177 ALLOW_THIS_IN_INITIALIZER_LIST(enable_window_method_factory_(this)) { | |
523 } | 178 } |
524 | 179 |
525 FirstRunBubble::~FirstRunBubble() { | 180 FirstRunBubble::~FirstRunBubble() { |
526 enable_window_method_factory_.InvalidateWeakPtrs(); | 181 enable_window_method_factory_.InvalidateWeakPtrs(); |
527 GetWidget()->GetFocusManager()->RemoveFocusChangeListener(view_); | |
528 } | 182 } |
529 | 183 |
184 #if defined(OS_WIN) && !defined(USE_AURA) | |
185 // TODO(alicet): do I still need this block? | |
530 void FirstRunBubble::EnableParent() { | 186 void FirstRunBubble::EnableParent() { |
531 ::EnableWindow(GetParent(), true); | 187 ::EnableWindow(GetParent(), true); |
532 // The EnableWindow() call above causes the parent to become active, which | 188 // The EnableWindow() call above causes the parent to become active, which |
533 // resets the flag set by Bubble's call to DisableInactiveRendering(), so we | 189 // 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 | 190 // have to call it again before activating the bubble to prevent the parent |
535 // window from rendering inactive. | 191 // window from rendering inactive. |
536 // TODO(beng): this only works in custom-frame mode, not glass-frame mode. | 192 // TODO(beng): this only works in custom-frame mode, not glass-frame mode. |
Miranda Callahan
2011/11/02 15:36:14
Is this TODO still valid, or did it refer to the G
alicet1
2011/11/03 18:21:51
ah right, this is left there so that I remember to
| |
537 HWND bubble_owner = GetLogicalBubbleOwner(GetNativeView()); | 193 if (parent_) |
538 views::Widget* parent = views::Widget::GetWidgetForNativeView(bubble_owner); | 194 parent_->DisableInactiveRendering(); |
539 if (parent) | |
540 parent->DisableInactiveRendering(); | |
541 // Reactivate the FirstRunBubble so it responds to OnActivate messages. | 195 // Reactivate the FirstRunBubble so it responds to OnActivate messages. |
542 SetWindowPos(GetParent(), 0, 0, 0, 0, | 196 SetWindowPos(GetParent(), 0, 0, 0, 0, |
543 SWP_NOSIZE | SWP_NOMOVE | SWP_NOREDRAW | SWP_SHOWWINDOW); | 197 SWP_NOSIZE | SWP_NOMOVE | SWP_NOREDRAW | SWP_SHOWWINDOW); |
544 } | 198 } |
545 | 199 |
546 #if defined(OS_WIN) && !defined(USE_AURA) | |
547 void FirstRunBubble::OnActivate(UINT action, BOOL minimized, HWND window) { | 200 void FirstRunBubble::OnActivate(UINT action, BOOL minimized, HWND window) { |
548 // Keep the bubble around for kLingerTime milliseconds, to prevent accidental | 201 // Keep the bubble around for kLingerTime milliseconds, to prevent accidental |
549 // closure. | 202 // closure. |
550 const int kLingerTime = 3000; | 203 const int kLingerTime = 3000; |
551 | 204 |
552 // We might get re-enabled right before we are closed (sequence is: we get | 205 // 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 | 206 // deactivated, we call close, before we are actually closed we get |
554 // reactivated). Don't do the disabling of the parent in such cases. | 207 // reactivated). Don't do the disabling of the parent in such cases. |
555 if (action == WA_ACTIVE && !has_been_activated_) { | 208 if (action == WA_ACTIVE && !has_been_activated_) { |
556 has_been_activated_ = true; | 209 has_been_activated_ = true; |
557 | 210 |
558 ::EnableWindow(GetParent(), false); | 211 ::EnableWindow(GetParent(), false); |
559 | 212 |
560 MessageLoop::current()->PostDelayedTask( | 213 MessageLoop::current()->PostDelayedTask( |
561 FROM_HERE, | 214 FROM_HERE, |
562 base::Bind(&FirstRunBubble::EnableParent, | 215 base::Bind(&FirstRunBubble::EnableParent, |
563 enable_window_method_factory_.GetWeakPtr()), | 216 enable_window_method_factory_.GetWeakPtr()), |
564 kLingerTime); | 217 kLingerTime); |
565 return; | 218 return; |
566 } | 219 } |
567 | 220 |
568 // Keep window from automatically closing until kLingerTime has passed. | 221 // Keep window from automatically closing until kLingerTime has passed. |
569 if (::IsWindowEnabled(GetParent())) | 222 if (::IsWindowEnabled(GetParent())) |
570 Bubble::OnActivate(action, minimized, window); | 223 Bubble::OnActivate(action, minimized, window); |
571 } | 224 } |
572 #endif | 225 #endif |
573 | 226 |
574 void FirstRunBubble::BubbleClosing(Bubble* bubble, bool closed_by_escape) { | 227 void FirstRunBubble::WindowClosing() { |
575 // Make sure our parent window is re-enabled. | 228 // Make sure our parent window is re-enabled. |
576 if (!IsWindowEnabled(GetParent())) | 229 if (parent_ && parent_->GetNativeView()) |
577 ::EnableWindow(GetParent(), true); | 230 GetFocusManager()->FocusNativeView(parent_->GetNativeView()); |
578 } | 231 } |
OLD | NEW |