OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 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 "ui/message_center/views/message_center_bubble.h" | 5 #include "ui/message_center/views/message_center_bubble.h" |
6 | 6 |
| 7 #include <map> |
| 8 |
7 #include "grit/ui_strings.h" | 9 #include "grit/ui_strings.h" |
8 #include "third_party/skia/include/core/SkPaint.h" | 10 #include "third_party/skia/include/core/SkPaint.h" |
9 #include "ui/base/l10n/l10n_util.h" | 11 #include "ui/base/l10n/l10n_util.h" |
10 #include "ui/base/resource/resource_bundle.h" | 12 #include "ui/base/resource/resource_bundle.h" |
11 #include "ui/gfx/canvas.h" | 13 #include "ui/gfx/canvas.h" |
12 #include "ui/gfx/insets.h" | 14 #include "ui/gfx/insets.h" |
13 #include "ui/gfx/point.h" | 15 #include "ui/gfx/point.h" |
14 #include "ui/gfx/rect.h" | 16 #include "ui/gfx/rect.h" |
15 #include "ui/gfx/size.h" | 17 #include "ui/gfx/size.h" |
16 #include "ui/gfx/text_constants.h" | 18 #include "ui/gfx/text_constants.h" |
(...skipping 25 matching lines...) Expand all Loading... |
42 const SkColor kFooterDelimiterColor = SkColorSetRGB(0xcc, 0xcc, 0xcc); | 44 const SkColor kFooterDelimiterColor = SkColorSetRGB(0xcc, 0xcc, 0xcc); |
43 const SkColor kFooterTextColor = SkColorSetRGB(0x80, 0x80, 0x80); | 45 const SkColor kFooterTextColor = SkColorSetRGB(0x80, 0x80, 0x80); |
44 const SkColor kButtonTextHighlightColor = SkColorSetRGB(0x32, 0x32, 0x32); | 46 const SkColor kButtonTextHighlightColor = SkColorSetRGB(0x32, 0x32, 0x32); |
45 const SkColor kButtonTextHoverColor = SkColorSetRGB(0x32, 0x32, 0x32); | 47 const SkColor kButtonTextHoverColor = SkColorSetRGB(0x32, 0x32, 0x32); |
46 // The focus color and focus-border logic is copied from ash tray. | 48 // The focus color and focus-border logic is copied from ash tray. |
47 // TODO(mukai): unite those implementations. | 49 // TODO(mukai): unite those implementations. |
48 const SkColor kFocusBorderColor = SkColorSetRGB(0x40, 0x80, 0xfa); | 50 const SkColor kFocusBorderColor = SkColorSetRGB(0x40, 0x80, 0xfa); |
49 | 51 |
50 class WebNotificationButtonViewBase : public views::View { | 52 class WebNotificationButtonViewBase : public views::View { |
51 public: | 53 public: |
52 WebNotificationButtonViewBase(NotificationList::Delegate* list_delegate) | 54 WebNotificationButtonViewBase(NotificationChangeObserver* observer) |
53 : list_delegate_(list_delegate), | 55 : observer_(observer), |
54 close_all_button_(NULL) {} | 56 close_all_button_(NULL) {} |
55 | 57 |
56 void SetCloseAllVisible(bool visible) { | 58 void SetCloseAllVisible(bool visible) { |
57 if (close_all_button_) | 59 if (close_all_button_) |
58 close_all_button_->SetVisible(visible); | 60 close_all_button_->SetVisible(visible); |
59 } | 61 } |
60 | 62 |
61 void set_close_all_button(views::Button* button) { | 63 void set_close_all_button(views::Button* button) { |
62 close_all_button_ = button; | 64 close_all_button_ = button; |
63 } | 65 } |
64 | 66 |
65 protected: | 67 protected: |
66 NotificationList::Delegate* list_delegate() { return list_delegate_; } | 68 NotificationChangeObserver* observer() { return observer_; } |
67 views::Button* close_all_button() { return close_all_button_; } | 69 views::Button* close_all_button() { return close_all_button_; } |
68 | 70 |
69 private: | 71 private: |
70 NotificationList::Delegate* list_delegate_; | 72 NotificationChangeObserver* observer_; // Weak reference. |
71 views::Button* close_all_button_; | 73 views::Button* close_all_button_; |
72 | 74 |
73 DISALLOW_COPY_AND_ASSIGN(WebNotificationButtonViewBase); | 75 DISALLOW_COPY_AND_ASSIGN(WebNotificationButtonViewBase); |
74 }; | 76 }; |
75 | 77 |
76 // The view for the buttons at the bottom of the web notification tray. | 78 // The view for the buttons at the bottom of the web notification tray. |
77 class WebNotificationButtonView : public WebNotificationButtonViewBase, | 79 class WebNotificationButtonView : public WebNotificationButtonViewBase, |
78 public views::ButtonListener { | 80 public views::ButtonListener { |
79 public: | 81 public: |
80 explicit WebNotificationButtonView(NotificationList::Delegate* list_delegate) | 82 explicit WebNotificationButtonView(NotificationChangeObserver* observer) |
81 : WebNotificationButtonViewBase(list_delegate) { | 83 : WebNotificationButtonViewBase(observer) { |
82 set_background(views::Background::CreateBackgroundPainter( | 84 set_background(views::Background::CreateBackgroundPainter( |
83 true, | 85 true, |
84 views::Painter::CreateVerticalGradient( | 86 views::Painter::CreateVerticalGradient( |
85 MessageBubbleBase::kHeaderBackgroundColorLight, | 87 MessageBubbleBase::kHeaderBackgroundColorLight, |
86 MessageBubbleBase::kHeaderBackgroundColorDark))); | 88 MessageBubbleBase::kHeaderBackgroundColorDark))); |
87 set_border(views::Border::CreateSolidSidedBorder( | 89 set_border(views::Border::CreateSolidSidedBorder( |
88 2, 0, 0, 0, kBorderDarkColor)); | 90 2, 0, 0, 0, kBorderDarkColor)); |
89 | 91 |
90 views::GridLayout* layout = new views::GridLayout(this); | 92 views::GridLayout* layout = new views::GridLayout(this); |
91 SetLayoutManager(layout); | 93 SetLayoutManager(layout); |
(...skipping 12 matching lines...) Expand all Loading... |
104 close_all_button->set_request_focus_on_press(false); | 106 close_all_button->set_request_focus_on_press(false); |
105 | 107 |
106 layout->AddPaddingRow(0, 4); | 108 layout->AddPaddingRow(0, 4); |
107 layout->StartRow(0, 0); | 109 layout->StartRow(0, 0); |
108 layout->AddView(close_all_button); | 110 layout->AddView(close_all_button); |
109 set_close_all_button(close_all_button); | 111 set_close_all_button(close_all_button); |
110 } | 112 } |
111 | 113 |
112 virtual ~WebNotificationButtonView() {} | 114 virtual ~WebNotificationButtonView() {} |
113 | 115 |
114 // Overridden from ButtonListener. | 116 // Overridden from views::ButtonListener: |
115 virtual void ButtonPressed(views::Button* sender, | 117 virtual void ButtonPressed(views::Button* sender, |
116 const ui::Event& event) OVERRIDE { | 118 const ui::Event& event) OVERRIDE { |
117 if (sender == close_all_button()) | 119 if (sender == close_all_button()) |
118 list_delegate()->SendRemoveAllNotifications(true); // Action by user. | 120 observer()->OnRemoveAllNotifications(true); // Action by user. |
119 } | 121 } |
120 | 122 |
121 private: | 123 private: |
122 DISALLOW_COPY_AND_ASSIGN(WebNotificationButtonView); | 124 DISALLOW_COPY_AND_ASSIGN(WebNotificationButtonView); |
123 }; | 125 }; |
124 | 126 |
125 class WebNotificationButton : public views::TextButton { | 127 class WebNotificationButton : public views::TextButton { |
126 public: | 128 public: |
127 WebNotificationButton(views::ButtonListener* listener, const string16& text) | 129 WebNotificationButton(views::ButtonListener* listener, const string16& text) |
128 : views::TextButton(listener, text) { | 130 : views::TextButton(listener, text) { |
129 set_border(views::Border::CreateEmptyBorder(0, 16, 0, 16)); | 131 set_border(views::Border::CreateEmptyBorder(0, 16, 0, 16)); |
130 set_min_height(kFooterHeight); | 132 set_min_height(kFooterHeight); |
131 SetEnabledColor(kFooterTextColor); | 133 SetEnabledColor(kFooterTextColor); |
132 SetHighlightColor(kButtonTextHighlightColor); | 134 SetHighlightColor(kButtonTextHighlightColor); |
133 SetHoverColor(kButtonTextHoverColor); | 135 SetHoverColor(kButtonTextHoverColor); |
134 } | 136 } |
135 | 137 |
136 protected: | 138 protected: |
137 // views::View overrides: | 139 // Overridden from views::View: |
138 virtual gfx::Size GetPreferredSize() OVERRIDE { | 140 virtual gfx::Size GetPreferredSize() OVERRIDE { |
139 // Returns an empty size when invisible, to trim its space in the parent's | 141 // Returns an empty size when invisible, to trim its space in the parent's |
140 // GridLayout. | 142 // GridLayout. |
141 if (!visible()) | 143 if (!visible()) |
142 return gfx::Size(); | 144 return gfx::Size(); |
143 return views::TextButton::GetPreferredSize(); | 145 return views::TextButton::GetPreferredSize(); |
144 } | 146 } |
145 | 147 |
146 virtual void OnPaintBorder(gfx::Canvas* canvas) OVERRIDE { | 148 virtual void OnPaintBorder(gfx::Canvas* canvas) OVERRIDE { |
147 // Just paint the left border. | 149 // Just paint the left border. |
148 canvas->DrawLine(gfx::Point(0, 0), gfx::Point(0, height()), | 150 canvas->DrawLine(gfx::Point(0, 0), gfx::Point(0, height()), |
149 kFooterDelimiterColor); | 151 kFooterDelimiterColor); |
150 } | 152 } |
151 | 153 |
152 virtual void OnPaintFocusBorder(gfx::Canvas* canvas) OVERRIDE { | 154 virtual void OnPaintFocusBorder(gfx::Canvas* canvas) OVERRIDE { |
153 if (HasFocus() && (focusable() || IsAccessibilityFocusable())) { | 155 if (HasFocus() && (focusable() || IsAccessibilityFocusable())) { |
154 canvas->DrawRect(gfx::Rect(2, 1, width() - 4, height() - 3), | 156 canvas->DrawRect(gfx::Rect(2, 1, width() - 4, height() - 3), |
155 kFocusBorderColor); | 157 kFocusBorderColor); |
156 } | 158 } |
157 } | 159 } |
158 | 160 |
159 DISALLOW_COPY_AND_ASSIGN(WebNotificationButton); | 161 DISALLOW_COPY_AND_ASSIGN(WebNotificationButton); |
160 }; | 162 }; |
161 | 163 |
162 // TODO(mukai): remove the trailing '2' when the kEnableNewMessageCenterBubble | 164 // TODO(mukai): remove the trailing '2' when the kEnableNewMessageCenterBubble |
163 // flag disappears. | 165 // flag disappears. |
164 class WebNotificationButtonView2 : public WebNotificationButtonViewBase, | 166 class WebNotificationButtonView2 : public WebNotificationButtonViewBase, |
165 public views::ButtonListener { | 167 public views::ButtonListener { |
166 public: | 168 public: |
167 explicit WebNotificationButtonView2(NotificationList::Delegate* list_delegate) | 169 explicit WebNotificationButtonView2(NotificationChangeObserver* observer) |
168 : WebNotificationButtonViewBase(list_delegate) { | 170 : WebNotificationButtonViewBase(observer) { |
169 set_background(views::Background::CreateSolidBackground( | 171 set_background(views::Background::CreateSolidBackground( |
170 kMessageCenterBackgroundColor)); | 172 kMessageCenterBackgroundColor)); |
171 set_border(views::Border::CreateSolidSidedBorder( | 173 set_border(views::Border::CreateSolidSidedBorder( |
172 1, 0, 0, 0, kFooterDelimiterColor)); | 174 1, 0, 0, 0, kFooterDelimiterColor)); |
173 | 175 |
174 | 176 |
175 notification_label_ = new views::Label(l10n_util::GetStringUTF16( | 177 notification_label_ = new views::Label(l10n_util::GetStringUTF16( |
176 IDS_MESSAGE_CENTER_FOOTER_TITLE)); | 178 IDS_MESSAGE_CENTER_FOOTER_TITLE)); |
177 notification_label_->SetHorizontalAlignment(gfx::ALIGN_LEFT); | 179 notification_label_->SetHorizontalAlignment(gfx::ALIGN_LEFT); |
178 notification_label_->SetElideBehavior(views::Label::ELIDE_AT_END); | 180 notification_label_->SetElideBehavior(views::Label::ELIDE_AT_END); |
(...skipping 20 matching lines...) Expand all Loading... |
199 column->AddColumn(views::GridLayout::LEADING, views::GridLayout::FILL, | 201 column->AddColumn(views::GridLayout::LEADING, views::GridLayout::FILL, |
200 0, views::GridLayout::USE_PREF, 0, 0); | 202 0, views::GridLayout::USE_PREF, 0, 0); |
201 layout->StartRow(0, 0); | 203 layout->StartRow(0, 0); |
202 layout->AddView(notification_label_); | 204 layout->AddView(notification_label_); |
203 layout->AddView(settings_button_); | 205 layout->AddView(settings_button_); |
204 layout->AddView(close_all_button); | 206 layout->AddView(close_all_button); |
205 set_close_all_button(close_all_button); | 207 set_close_all_button(close_all_button); |
206 } | 208 } |
207 | 209 |
208 private: | 210 private: |
209 // views::ButtonListener overrides: | 211 // Overridden from views::ButtonListener: |
210 virtual void ButtonPressed(views::Button* sender, | 212 virtual void ButtonPressed(views::Button* sender, |
211 const ui::Event& event) OVERRIDE { | 213 const ui::Event& event) OVERRIDE { |
212 if (sender == close_all_button()) | 214 if (sender == close_all_button()) |
213 list_delegate()->SendRemoveAllNotifications(true); // Action by user. | 215 observer()->OnRemoveAllNotifications(true); // Action by user. |
214 else if (sender == settings_button_) | 216 else if (sender == settings_button_) |
215 list_delegate()->ShowNotificationSettingsDialog( | 217 observer()->OnShowNotificationSettingsDialog( |
216 GetWidget()->GetNativeView()); | 218 GetWidget()->GetNativeView()); |
217 else | 219 else |
218 NOTREACHED(); | 220 NOTREACHED(); |
219 } | 221 } |
220 | 222 |
221 views::Label* notification_label_; | 223 views::Label* notification_label_; |
222 views::Button* settings_button_; | 224 views::Button* settings_button_; |
223 | 225 |
224 DISALLOW_COPY_AND_ASSIGN(WebNotificationButtonView2); | 226 DISALLOW_COPY_AND_ASSIGN(WebNotificationButtonView2); |
225 }; | 227 }; |
226 | 228 |
227 // A custom scroll-view that has a specified size. | 229 // A custom scroll view whose height has a minimum and maximum value and whose |
228 class FixedSizedScrollView : public views::ScrollView { | 230 // scroll bar disappears when not needed. |
| 231 class BoundedScrollView : public views::ScrollView { |
229 public: | 232 public: |
230 FixedSizedScrollView() { | 233 BoundedScrollView(int min_height, int max_height) |
| 234 : min_height_(min_height), |
| 235 max_height_(max_height) { |
231 set_notify_enter_exit_on_child(true); | 236 set_notify_enter_exit_on_child(true); |
232 if (IsRichNotificationEnabled()) { | 237 if (IsRichNotificationEnabled()) { |
233 set_background(views::Background::CreateSolidBackground( | 238 set_background(views::Background::CreateSolidBackground( |
234 kMessageCenterBackgroundColor)); | 239 kMessageCenterBackgroundColor)); |
235 } | 240 } |
236 } | 241 } |
237 | 242 |
238 virtual ~FixedSizedScrollView() {} | 243 virtual ~BoundedScrollView() {} |
239 | 244 |
240 void SetFixedSize(const gfx::Size& size) { | 245 // Overridden from views::View: |
241 if (fixed_size_ == size) | |
242 return; | |
243 fixed_size_ = size; | |
244 PreferredSizeChanged(); | |
245 } | |
246 | |
247 // views::View overrides. | |
248 virtual gfx::Size GetPreferredSize() OVERRIDE { | 246 virtual gfx::Size GetPreferredSize() OVERRIDE { |
249 gfx::Size size = fixed_size_.IsEmpty() ? | 247 gfx::Size size = contents()->GetPreferredSize(); |
250 contents()->GetPreferredSize() : fixed_size_; | 248 size.ClampToMin(gfx::Size(size.width(), min_height_)); |
| 249 size.ClampToMax(gfx::Size(size.width(), max_height_)); |
251 gfx::Insets insets = GetInsets(); | 250 gfx::Insets insets = GetInsets(); |
252 size.Enlarge(insets.width(), insets.height()); | 251 size.Enlarge(insets.width(), insets.height()); |
253 return size; | 252 return size; |
254 } | 253 } |
255 | 254 |
256 virtual void Layout() OVERRIDE { | 255 virtual void Layout() OVERRIDE { |
257 gfx::Rect bounds = gfx::Rect(contents()->GetPreferredSize()); | 256 // Lay out the view as if it will have a scroll bar. |
258 bounds.set_width(std::max(0, width() - GetScrollBarWidth())); | 257 gfx::Rect content_bounds = gfx::Rect(contents()->GetPreferredSize()); |
259 contents()->SetBoundsRect(bounds); | 258 content_bounds.set_width(std::max(0, width() - GetScrollBarWidth())); |
| 259 contents()->SetBoundsRect(content_bounds); |
| 260 views::ScrollView::Layout(); |
260 | 261 |
261 views::ScrollView::Layout(); | 262 // But use the scroll bar space if no scroll bar is needed. |
262 if (!vertical_scroll_bar()->visible()) { | 263 if (!vertical_scroll_bar()->visible()) { |
263 gfx::Rect bounds = contents()->bounds(); | 264 content_bounds = contents()->bounds(); |
264 bounds.set_width(bounds.width() + GetScrollBarWidth()); | 265 content_bounds.set_width(content_bounds.width() + GetScrollBarWidth()); |
265 contents()->SetBoundsRect(bounds); | 266 contents()->SetBoundsRect(content_bounds); |
266 } | 267 } |
267 } | 268 } |
268 | 269 |
269 virtual void OnBoundsChanged(const gfx::Rect& previous_bounds) OVERRIDE { | 270 virtual void OnBoundsChanged(const gfx::Rect& previous_bounds) OVERRIDE { |
270 gfx::Rect bounds = gfx::Rect(contents()->GetPreferredSize()); | 271 // Make sure any content resizing takes into account the scroll bar. |
271 bounds.set_width(std::max(0, width() - GetScrollBarWidth())); | 272 gfx::Rect content_bounds = gfx::Rect(contents()->GetPreferredSize()); |
272 contents()->SetBoundsRect(bounds); | 273 content_bounds.set_width(std::max(0, width() - GetScrollBarWidth())); |
| 274 contents()->SetBoundsRect(content_bounds); |
273 } | 275 } |
274 | 276 |
275 private: | 277 private: |
276 gfx::Size fixed_size_; | 278 int min_height_; |
| 279 int max_height_; |
277 | 280 |
278 DISALLOW_COPY_AND_ASSIGN(FixedSizedScrollView); | 281 DISALLOW_COPY_AND_ASSIGN(BoundedScrollView); |
279 }; | 282 }; |
280 | 283 |
281 // Container for the messages. | 284 // Displays a list of messages. |
282 class ScrollContentView : public views::View { | 285 class MessageListView : public views::View { |
283 public: | 286 public: |
284 ScrollContentView() { | 287 MessageListView() { |
285 if (IsRichNotificationEnabled()) { | 288 if (IsRichNotificationEnabled()) { |
286 // Set the margin to 0 for the layout. BoxLayout assumes the same margin | 289 // Set the margin to 0 for the layout. BoxLayout assumes the same margin |
287 // for top and bottom, but the bottom margin here should be smaller | 290 // for top and bottom, but the bottom margin here should be smaller |
288 // because of the shadow of message view. Use an empty border instead | 291 // because of the shadow of message view. Use an empty border instead |
289 // to provide this margin. | 292 // to provide this margin. |
290 gfx::Insets shadow_insets = MessageView::GetShadowInsets(); | 293 gfx::Insets shadow_insets = MessageView::GetShadowInsets(); |
291 SetLayoutManager( | 294 SetLayoutManager( |
292 new views::BoxLayout(views::BoxLayout::kVertical, | 295 new views::BoxLayout(views::BoxLayout::kVertical, |
293 0, | 296 0, |
294 0, | 297 0, |
295 kMarginBetweenItems - shadow_insets.bottom())); | 298 kMarginBetweenItems - shadow_insets.bottom())); |
296 set_background(views::Background::CreateSolidBackground( | 299 set_background(views::Background::CreateSolidBackground( |
297 kMessageCenterBackgroundColor)); | 300 kMessageCenterBackgroundColor)); |
298 set_border(views::Border::CreateEmptyBorder( | 301 set_border(views::Border::CreateEmptyBorder( |
299 kMarginBetweenItems - shadow_insets.top(), /* top */ | 302 kMarginBetweenItems - shadow_insets.top(), /* top */ |
300 kMarginBetweenItems - shadow_insets.left(), /* left */ | 303 kMarginBetweenItems - shadow_insets.left(), /* left */ |
301 0, /* bottom */ | 304 0, /* bottom */ |
302 kMarginBetweenItems - shadow_insets.right() /* right */ )); | 305 kMarginBetweenItems - shadow_insets.right() /* right */ )); |
303 } else { | 306 } else { |
304 views::BoxLayout* layout = | 307 views::BoxLayout* layout = |
305 new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 1); | 308 new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 1); |
306 layout->set_spread_blank_space(true); | 309 layout->set_spread_blank_space(true); |
307 SetLayoutManager(layout); | 310 SetLayoutManager(layout); |
308 } | 311 } |
309 } | 312 } |
310 | 313 |
311 virtual ~ScrollContentView() { | 314 virtual ~MessageListView() { |
312 } | 315 } |
313 | 316 |
314 virtual gfx::Size GetPreferredSize() OVERRIDE { | |
315 if (!preferred_size_.IsEmpty()) | |
316 return preferred_size_; | |
317 return views::View::GetPreferredSize(); | |
318 } | |
319 | |
320 void set_preferred_size(const gfx::Size& size) { preferred_size_ = size; } | |
321 | |
322 private: | 317 private: |
323 gfx::Size preferred_size_; | 318 DISALLOW_COPY_AND_ASSIGN(MessageListView); |
324 DISALLOW_COPY_AND_ASSIGN(ScrollContentView); | |
325 }; | 319 }; |
326 | 320 |
327 } // namespace | 321 } // namespace |
328 | 322 |
329 // Message Center contents. | 323 // View that displays the whole message center. |
330 class MessageCenterContentsView : public views::View { | 324 class MessageCenterView : public views::View { |
331 public: | 325 public: |
332 explicit MessageCenterContentsView(MessageCenterBubble* bubble, | 326 MessageCenterView(MessageCenterBubble* bubble) : bubble_(bubble) { |
333 NotificationList::Delegate* list_delegate) | |
334 : list_delegate_(list_delegate), | |
335 bubble_(bubble) { | |
336 int between_child = IsRichNotificationEnabled() ? 0 : 1; | 327 int between_child = IsRichNotificationEnabled() ? 0 : 1; |
337 SetLayoutManager( | 328 SetLayoutManager( |
338 new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, between_child)); | 329 new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, between_child)); |
339 | 330 |
340 scroll_content_ = new ScrollContentView; | 331 |
341 scroller_ = new FixedSizedScrollView; | 332 if (IsRichNotificationEnabled()) |
342 scroller_->SetContents(scroll_content_); | 333 button_view_ = new WebNotificationButtonView2(bubble_); |
343 AddChildView(scroller_); | 334 else |
| 335 button_view_ = new WebNotificationButtonView(bubble_); |
| 336 |
| 337 const int button_height = button_view_->GetPreferredSize().height(); |
| 338 const int min_height = kMessageBubbleBaseMinHeight - button_height; |
| 339 const int max_height = bubble_->max_height() - button_height; |
| 340 scroller_ = new BoundedScrollView(min_height, max_height); |
344 | 341 |
345 if (get_use_acceleration_when_possible()) { | 342 if (get_use_acceleration_when_possible()) { |
346 scroller_->SetPaintToLayer(true); | 343 scroller_->SetPaintToLayer(true); |
347 scroller_->SetFillsBoundsOpaquely(false); | 344 scroller_->SetFillsBoundsOpaquely(false); |
348 scroller_->layer()->SetMasksToBounds(true); | 345 scroller_->layer()->SetMasksToBounds(true); |
349 } | 346 } |
350 | 347 |
351 if (IsRichNotificationEnabled()) | 348 message_list_view_ = new MessageListView(); |
352 button_view_ = new WebNotificationButtonView2(list_delegate); | 349 scroller_->SetContents(message_list_view_); |
353 else | 350 |
354 button_view_ = new WebNotificationButtonView(list_delegate); | 351 AddChildView(scroller_); |
355 AddChildView(button_view_); | 352 AddChildView(button_view_); |
356 } | 353 } |
357 | 354 |
358 void FocusContents() { | 355 void FocusContents() { |
359 } | 356 } |
360 | 357 |
361 void Update(const NotificationList::Notifications& notifications) { | 358 void UpdateAllNotifications( |
362 scroll_content_->RemoveAllChildViews(true); | 359 const NotificationList::Notifications& notifications) { |
363 scroll_content_->set_preferred_size(gfx::Size()); | 360 RemoveAllNotifications(); |
364 size_t num_children = 0; | |
365 for (NotificationList::Notifications::const_iterator iter = | 361 for (NotificationList::Notifications::const_iterator iter = |
366 notifications.begin(); iter != notifications.end(); ++iter) { | 362 notifications.begin(); iter != notifications.end(); ++iter) { |
367 MessageView* view = NotificationView::Create(*(*iter), list_delegate_); | 363 AddNotification(*(*iter)); |
368 view->set_scroller(scroller_); | 364 if (message_views_.size() >= |
369 scroll_content_->AddChildView(view); | |
370 if (++num_children >= | |
371 NotificationList::kMaxVisibleMessageCenterNotifications) { | 365 NotificationList::kMaxVisibleMessageCenterNotifications) { |
372 break; | 366 break; |
373 } | 367 } |
374 } | 368 } |
375 if (num_children == 0) { | 369 if (message_views_.empty()) { |
376 views::Label* label = new views::Label(l10n_util::GetStringUTF16( | 370 views::Label* label = new views::Label(l10n_util::GetStringUTF16( |
377 IDS_MESSAGE_CENTER_NO_MESSAGES)); | 371 IDS_MESSAGE_CENTER_NO_MESSAGES)); |
378 label->SetFont(label->font().DeriveFont(1)); | 372 label->SetFont(label->font().DeriveFont(1)); |
379 label->SetEnabledColor(SK_ColorGRAY); | 373 label->SetEnabledColor(SK_ColorGRAY); |
380 // Set transparent background to ensure that subpixel rendering | 374 // Set transparent background to ensure that subpixel rendering |
381 // is disabled. See crbug.com/169056 | 375 // is disabled. See crbug.com/169056 |
382 label->SetBackgroundColor(kTransparentColor); | 376 label->SetBackgroundColor(kTransparentColor); |
383 scroll_content_->AddChildView(label); | 377 message_list_view_->AddChildView(label); |
384 button_view_->SetCloseAllVisible(false); | 378 button_view_->SetCloseAllVisible(false); |
385 scroller_->set_focusable(false); | 379 scroller_->set_focusable(false); |
386 } else { | 380 } else { |
387 button_view_->SetCloseAllVisible(true); | 381 button_view_->SetCloseAllVisible(true); |
388 scroller_->set_focusable(true); | 382 scroller_->set_focusable(true); |
389 } | 383 } |
390 SizeScrollContent(); | |
391 Layout(); | 384 Layout(); |
392 if (GetWidget()) | 385 } |
393 GetWidget()->GetRootView()->SchedulePaint(); | 386 |
| 387 void UpdateOneNotification(const Notification& notification) { |
| 388 // Update the corresponding message view if there is one and explicitly |
| 389 // update this view's layout as this is not automatic in spite of the |
| 390 // updated view's likely size change because ScrollView's Viewport breaks |
| 391 // the ChildPreferredSizeChange() chain. |
| 392 MessageView* view = message_views_[notification.id()]; |
| 393 if (view) { |
| 394 view->Update(notification); |
| 395 Layout(); |
| 396 } |
394 } | 397 } |
395 | 398 |
396 size_t NumMessageViews() const { | 399 size_t NumMessageViews() const { |
397 return scroll_content_->child_count(); | 400 return message_list_view_->child_count(); |
| 401 } |
| 402 |
| 403 protected: |
| 404 // Overridden from views::View: |
| 405 virtual void Layout() OVERRIDE { |
| 406 scroller_->SizeToPreferredSize(); |
| 407 views::View::Layout(); |
| 408 if (GetWidget()) |
| 409 GetWidget()->GetRootView()->SchedulePaint(); |
| 410 bubble_->bubble_view()->UpdateBubble(); |
398 } | 411 } |
399 | 412 |
400 private: | 413 private: |
401 void SizeScrollContent() { | 414 |
402 gfx::Size scroll_size = scroll_content_->GetPreferredSize(); | 415 void RemoveAllNotifications() { |
403 const int button_height = button_view_->GetPreferredSize().height(); | 416 message_views_.clear(); |
404 const int min_height = kMessageBubbleBaseMinHeight - button_height; | 417 message_list_view_->RemoveAllChildViews(true); |
405 const int max_height = bubble_->max_height() - button_height; | |
406 int scroll_height = std::min(std::max( | |
407 scroll_size.height(), min_height), max_height); | |
408 scroll_size.set_height(scroll_height); | |
409 if (scroll_height == min_height) | |
410 scroll_content_->set_preferred_size(scroll_size); | |
411 else | |
412 scroll_content_->set_preferred_size(gfx::Size()); | |
413 scroller_->SetFixedSize(scroll_size); | |
414 scroller_->SizeToPreferredSize(); | |
415 scroll_content_->InvalidateLayout(); | |
416 } | 418 } |
417 | 419 |
418 NotificationList::Delegate* list_delegate_; | 420 void AddNotification(const Notification& notification) { |
419 FixedSizedScrollView* scroller_; | 421 // Always expand the first (topmost) notification. |
420 ScrollContentView* scroll_content_; | 422 bool expand = (notification.is_expanded() || message_views_.empty()); |
| 423 MessageView* view = NotificationView::Create(notification, bubble_, expand); |
| 424 view->set_scroller(scroller_); |
| 425 message_views_[notification.id()] = view; |
| 426 message_list_view_->AddChildView(view); |
| 427 } |
| 428 |
| 429 MessageCenterBubble* bubble_; // Weak reference. |
| 430 std::map<std::string,MessageView*> message_views_; |
| 431 BoundedScrollView* scroller_; |
| 432 MessageListView* message_list_view_; |
421 WebNotificationButtonViewBase* button_view_; | 433 WebNotificationButtonViewBase* button_view_; |
422 MessageCenterBubble* bubble_; | |
423 | 434 |
424 DISALLOW_COPY_AND_ASSIGN(MessageCenterContentsView); | 435 DISALLOW_COPY_AND_ASSIGN(MessageCenterView); |
425 }; | 436 }; |
426 | 437 |
427 // Message Center Bubble. | 438 // Message Center Bubble. |
428 MessageCenterBubble::MessageCenterBubble(NotificationList::Delegate* delegate) | 439 MessageCenterBubble::MessageCenterBubble(MessageCenter* message_center) |
429 : MessageBubbleBase(delegate), | 440 : MessageBubbleBase(message_center), |
430 contents_view_(NULL) { | 441 contents_view_(NULL) { |
431 } | 442 } |
432 | 443 |
433 MessageCenterBubble::~MessageCenterBubble() {} | 444 MessageCenterBubble::~MessageCenterBubble() {} |
434 | 445 |
435 views::TrayBubbleView::InitParams MessageCenterBubble::GetInitParams( | 446 views::TrayBubbleView::InitParams MessageCenterBubble::GetInitParams( |
436 views::TrayBubbleView::AnchorAlignment anchor_alignment) { | 447 views::TrayBubbleView::AnchorAlignment anchor_alignment) { |
437 views::TrayBubbleView::InitParams init_params = | 448 views::TrayBubbleView::InitParams init_params = |
438 GetDefaultInitParams(anchor_alignment); | 449 GetDefaultInitParams(anchor_alignment); |
439 if (IsRichNotificationEnabled()) { | 450 if (IsRichNotificationEnabled()) { |
440 init_params.min_width += kMarginBetweenItems * 2; | 451 init_params.min_width += kMarginBetweenItems * 2; |
441 init_params.max_width += kMarginBetweenItems * 2; | 452 init_params.max_width += kMarginBetweenItems * 2; |
442 } | 453 } |
443 init_params.max_height = max_height(); | 454 init_params.max_height = max_height(); |
444 init_params.can_activate = true; | 455 init_params.can_activate = true; |
445 return init_params; | 456 return init_params; |
446 } | 457 } |
447 | 458 |
448 void MessageCenterBubble::InitializeContents( | 459 void MessageCenterBubble::InitializeContents( |
449 views::TrayBubbleView* new_bubble_view) { | 460 views::TrayBubbleView* new_bubble_view) { |
450 set_bubble_view(new_bubble_view); | 461 set_bubble_view(new_bubble_view); |
451 contents_view_ = new MessageCenterContentsView(this, list_delegate()); | 462 contents_view_ = new MessageCenterView(this); |
452 bubble_view()->AddChildView(contents_view_); | 463 bubble_view()->AddChildView(contents_view_); |
453 // Resize the content of the bubble view to the given bubble size. This is | 464 // Resize the content of the bubble view to the given bubble size. This is |
454 // necessary in case of the bubble border forcing a bigger size then the | 465 // necessary in case of the bubble border forcing a bigger size then the |
455 // |new_bubble_view| actually wants. See crbug.com/169390. | 466 // |new_bubble_view| actually wants. See crbug.com/169390. |
456 bubble_view()->Layout(); | 467 bubble_view()->Layout(); |
457 UpdateBubbleView(); | 468 UpdateBubbleView(); |
458 contents_view_->FocusContents(); | 469 contents_view_->FocusContents(); |
459 } | 470 } |
460 | 471 |
461 void MessageCenterBubble::OnBubbleViewDestroyed() { | 472 void MessageCenterBubble::OnBubbleViewDestroyed() { |
462 contents_view_ = NULL; | 473 contents_view_ = NULL; |
463 } | 474 } |
464 | 475 |
465 void MessageCenterBubble::UpdateBubbleView() { | 476 void MessageCenterBubble::UpdateBubbleView() { |
466 if (!bubble_view()) | 477 if (!bubble_view()) |
467 return; // Could get called after view is closed | 478 return; // Could get called after view is closed |
468 const NotificationList::Notifications& notifications = | 479 const NotificationList::Notifications& notifications = |
469 list_delegate()->GetNotificationList()->GetNotifications(); | 480 message_center()->notification_list()->GetNotifications(); |
470 contents_view_->Update(notifications); | 481 contents_view_->UpdateAllNotifications(notifications); |
471 bubble_view()->Show(); | 482 bubble_view()->Show(); |
472 bubble_view()->UpdateBubble(); | 483 bubble_view()->UpdateBubble(); |
473 } | 484 } |
474 | 485 |
475 void MessageCenterBubble::OnMouseEnteredView() { | 486 void MessageCenterBubble::OnMouseEnteredView() { |
476 } | 487 } |
477 | 488 |
478 void MessageCenterBubble::OnMouseExitedView() { | 489 void MessageCenterBubble::OnMouseExitedView() { |
479 } | 490 } |
480 | 491 |
| 492 void MessageCenterBubble::OnRemoveNotification(const std::string& id, |
| 493 bool by_user) { |
| 494 message_center()->OnRemoveNotification(id, by_user); |
| 495 } |
| 496 |
| 497 void MessageCenterBubble::OnRemoveAllNotifications(bool by_user) { |
| 498 message_center()->OnRemoveAllNotifications(by_user); |
| 499 } |
| 500 |
| 501 void MessageCenterBubble::OnDisableNotificationsByExtension( |
| 502 const std::string& id) { |
| 503 message_center()->OnDisableNotificationsByExtension(id); |
| 504 } |
| 505 |
| 506 void MessageCenterBubble::OnDisableNotificationsByUrl(const std::string& id) { |
| 507 message_center()->OnDisableNotificationsByUrl(id); |
| 508 } |
| 509 |
| 510 void MessageCenterBubble::OnShowNotificationSettings(const std::string& id) { |
| 511 message_center()->OnShowNotificationSettings(id); |
| 512 } |
| 513 |
| 514 void MessageCenterBubble::OnShowNotificationSettingsDialog( |
| 515 gfx::NativeView context) { |
| 516 message_center()->OnShowNotificationSettingsDialog(context); |
| 517 } |
| 518 |
| 519 void MessageCenterBubble::OnClicked(const std::string& id) { |
| 520 message_center()->OnClicked(id); |
| 521 } |
| 522 |
| 523 void MessageCenterBubble::OnButtonClicked(const std::string& id, |
| 524 int button_index) { |
| 525 message_center()->OnButtonClicked(id, button_index); |
| 526 } |
| 527 |
| 528 void MessageCenterBubble::OnExpanded(const std::string& id) { |
| 529 message_center()->OnExpanded(id); |
| 530 |
| 531 // Update the view corresponding to this notification. |
| 532 const NotificationList::Notifications& notifications = |
| 533 message_center()->notification_list()->GetNotifications(); |
| 534 for (NotificationList::Notifications::const_iterator iter = |
| 535 notifications.begin(); iter != notifications.end(); ++iter) { |
| 536 if ((*iter)->id() == id) { |
| 537 contents_view_->UpdateOneNotification(*(*iter)); |
| 538 break; |
| 539 } |
| 540 } |
| 541 } |
| 542 |
481 size_t MessageCenterBubble::NumMessageViewsForTest() const { | 543 size_t MessageCenterBubble::NumMessageViewsForTest() const { |
482 return contents_view_->NumMessageViews(); | 544 return contents_view_->NumMessageViews(); |
483 } | 545 } |
484 | 546 |
485 } // namespace message_center | 547 } // namespace message_center |
OLD | NEW |