| // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "ui/message_center/views/message_center_view.h" |
| |
| #include <list> |
| #include <map> |
| |
| #include "base/macros.h" |
| #include "base/memory/weak_ptr.h" |
| #include "base/message_loop/message_loop.h" |
| #include "base/stl_util.h" |
| #include "build/build_config.h" |
| #include "ui/base/l10n/l10n_util.h" |
| #include "ui/gfx/animation/multi_animation.h" |
| #include "ui/gfx/canvas.h" |
| #include "ui/gfx/geometry/insets.h" |
| #include "ui/gfx/geometry/rect.h" |
| #include "ui/gfx/geometry/size.h" |
| #include "ui/message_center/message_center.h" |
| #include "ui/message_center/message_center_style.h" |
| #include "ui/message_center/message_center_tray.h" |
| #include "ui/message_center/message_center_types.h" |
| #include "ui/message_center/views/message_center_button_bar.h" |
| #include "ui/message_center/views/message_list_view.h" |
| #include "ui/message_center/views/message_view.h" |
| #include "ui/message_center/views/message_view_context_menu_controller.h" |
| #include "ui/message_center/views/message_view_factory.h" |
| #include "ui/message_center/views/notifier_settings_view.h" |
| #include "ui/resources/grit/ui_resources.h" |
| #include "ui/strings/grit/ui_strings.h" |
| #include "ui/views/background.h" |
| #include "ui/views/border.h" |
| #include "ui/views/controls/button/button.h" |
| #include "ui/views/controls/label.h" |
| #include "ui/views/controls/scroll_view.h" |
| #include "ui/views/controls/scrollbar/overlay_scroll_bar.h" |
| #include "ui/views/layout/fill_layout.h" |
| #include "ui/views/widget/widget.h" |
| |
| namespace message_center { |
| |
| // static |
| bool MessageCenterView::disable_animation_for_testing = false; |
| |
| namespace { |
| |
| const int kDefaultAnimationDurationMs = 120; |
| const int kDefaultFrameRateHz = 60; |
| |
| void SetViewHierarchyEnabled(views::View* view, bool enabled) { |
| for (int i = 0; i < view->child_count(); i++) |
| SetViewHierarchyEnabled(view->child_at(i), enabled); |
| view->SetEnabled(enabled); |
| } |
| |
| } // namespace |
| |
| // MessageCenterView /////////////////////////////////////////////////////////// |
| |
| MessageCenterView::MessageCenterView(MessageCenter* message_center, |
| MessageCenterTray* tray, |
| int max_height, |
| bool initially_settings_visible) |
| : message_center_(message_center), |
| tray_(tray), |
| scroller_(NULL), |
| settings_view_(NULL), |
| button_bar_(NULL), |
| settings_visible_(initially_settings_visible), |
| source_view_(NULL), |
| source_height_(0), |
| target_view_(NULL), |
| target_height_(0), |
| is_closing_(false), |
| is_locked_(message_center_->IsLockedState()), |
| mode_((!initially_settings_visible || is_locked_) ? Mode::BUTTONS_ONLY |
| : Mode::SETTINGS), |
| context_menu_controller_(new MessageViewContextMenuController(this)), |
| focus_manager_(nullptr) { |
| message_center_->AddObserver(this); |
| set_notify_enter_exit_on_child(true); |
| set_background(views::Background::CreateSolidBackground( |
| kMessageCenterBackgroundColor)); |
| |
| NotifierSettingsProvider* notifier_settings_provider = |
| message_center_->GetNotifierSettingsProvider(); |
| button_bar_ = new MessageCenterButtonBar( |
| this, message_center, notifier_settings_provider, |
| initially_settings_visible, GetButtonBarTitle()); |
| button_bar_->SetCloseAllButtonEnabled(false); |
| |
| const int button_height = button_bar_->GetPreferredSize().height(); |
| |
| scroller_ = new views::ScrollView(); |
| scroller_->ClipHeightTo(kMinScrollViewHeight, max_height - button_height); |
| scroller_->SetVerticalScrollBar(new views::OverlayScrollBar(false)); |
| scroller_->SetHorizontalScrollBar(new views::OverlayScrollBar(true)); |
| scroller_->set_background( |
| views::Background::CreateSolidBackground(kMessageCenterBackgroundColor)); |
| |
| scroller_->SetPaintToLayer(); |
| scroller_->layer()->SetFillsBoundsOpaquely(false); |
| scroller_->layer()->SetMasksToBounds(true); |
| |
| message_list_view_.reset(new MessageListView()); |
| message_list_view_->set_scroller(scroller_); |
| message_list_view_->set_owned_by_client(); |
| message_list_view_->AddObserver(this); |
| |
| // We want to swap the contents of the scroll view between the empty list |
| // view and the message list view, without constructing them afresh each |
| // time. So, since the scroll view deletes old contents each time you |
| // set the contents (regardless of the |owned_by_client_| setting) we need |
| // an intermediate view for the contents whose children we can swap in and |
| // out. |
| views::View* scroller_contents = new views::View(); |
| scroller_contents->SetLayoutManager(new views::FillLayout()); |
| scroller_contents->AddChildView(message_list_view_.get()); |
| scroller_->SetContents(scroller_contents); |
| |
| settings_view_ = new NotifierSettingsView(notifier_settings_provider); |
| |
| scroller_->SetVisible(false); // Because it has no notifications at first. |
| settings_view_->SetVisible(mode_ == Mode::SETTINGS); |
| |
| AddChildView(scroller_); |
| AddChildView(settings_view_); |
| AddChildView(button_bar_); |
| } |
| |
| MessageCenterView::~MessageCenterView() { |
| message_list_view_->RemoveObserver(this); |
| |
| if (!is_closing_) |
| message_center_->RemoveObserver(this); |
| |
| if (focus_manager_) |
| focus_manager_->RemoveFocusChangeListener(this); |
| } |
| |
| void MessageCenterView::Init() { |
| focus_manager_ = GetFocusManager(); |
| if (focus_manager_) |
| focus_manager_->AddFocusChangeListener(this); |
| } |
| |
| void MessageCenterView::SetNotifications( |
| const NotificationList::Notifications& notifications) { |
| if (is_closing_) |
| return; |
| |
| notification_views_.clear(); |
| |
| int index = 0; |
| for (NotificationList::Notifications::const_iterator iter = |
| notifications.begin(); iter != notifications.end(); ++iter) { |
| AddNotificationAt(*(*iter), index++); |
| |
| message_center_->DisplayedNotification( |
| (*iter)->id(), message_center::DISPLAY_SOURCE_MESSAGE_CENTER); |
| if (notification_views_.size() >= kMaxVisibleMessageCenterNotifications) |
| break; |
| } |
| |
| Update(false /* animate */); |
| scroller_->RequestFocus(); |
| } |
| |
| void MessageCenterView::SetSettingsVisible(bool visible) { |
| settings_visible_ = visible; |
| Update(true /* animate */); |
| } |
| |
| void MessageCenterView::ClearAllClosableNotifications() { |
| if (is_closing_) |
| return; |
| |
| is_clearing_all_notifications_ = true; |
| UpdateButtonBarStatus(); |
| SetViewHierarchyEnabled(scroller_, false); |
| message_list_view_->ClearAllClosableNotifications( |
| scroller_->GetVisibleRect()); |
| } |
| |
| void MessageCenterView::OnAllNotificationsCleared() { |
| is_clearing_all_notifications_ = false; |
| SetViewHierarchyEnabled(scroller_, true); |
| button_bar_->SetCloseAllButtonEnabled(false); |
| |
| // The status of buttons will be updated after removing all notifications. |
| |
| // Action by user. |
| message_center_->RemoveAllNotifications( |
| true /* by_user */, |
| message_center::MessageCenter::RemoveType::NON_PINNED); |
| } |
| |
| size_t MessageCenterView::NumMessageViewsForTest() const { |
| return message_list_view_->child_count(); |
| } |
| |
| void MessageCenterView::OnSettingsChanged() { |
| scroller_->InvalidateLayout(); |
| PreferredSizeChanged(); |
| Layout(); |
| } |
| |
| void MessageCenterView::SetIsClosing(bool is_closing) { |
| is_closing_ = is_closing; |
| if (is_closing) |
| message_center_->RemoveObserver(this); |
| else |
| message_center_->AddObserver(this); |
| } |
| |
| void MessageCenterView::OnDidChangeFocus(views::View* before, |
| views::View* now) { |
| if (message_list_view_ && (message_list_view_->Contains(before) || |
| message_list_view_->Contains(now))) { |
| // Focus state of a children of message view center is changed. |
| for (auto pair : notification_views_) { |
| if (pair.second->Contains(before) || pair.second->Contains(now)) |
| pair.second->UpdateControlButtonsVisibility(); |
| } |
| } |
| } |
| |
| void MessageCenterView::Layout() { |
| if (is_closing_) |
| return; |
| |
| int button_height = button_bar_->GetHeightForWidth(width()) + |
| button_bar_->GetInsets().height(); |
| // Skip unnecessary re-layout of contents during the resize animation. |
| bool animating = settings_transition_animation_ && |
| settings_transition_animation_->is_animating(); |
| if (animating && settings_transition_animation_->current_part_index() == 0) { |
| button_bar_->SetBounds(0, height() - button_height, width(), button_height); |
| return; |
| } |
| |
| scroller_->SetBounds(0, |
| 0, |
| width(), |
| height() - button_height); |
| settings_view_->SetBounds(0, |
| 0, |
| width(), |
| height() - button_height); |
| |
| bool is_scrollable = false; |
| if (scroller_->visible()) |
| is_scrollable = scroller_->height() < message_list_view_->height(); |
| else if (settings_view_->visible()) |
| is_scrollable = settings_view_->IsScrollable(); |
| |
| if (!animating) { |
| if (is_scrollable) { |
| // Draw separator line on the top of the button bar if it is on the bottom |
| // or draw it at the bottom if the bar is on the top. |
| button_bar_->SetBorder(views::CreateSolidSidedBorder( |
| 1, 0, 0, 0, kFooterDelimiterColor)); |
| } else { |
| button_bar_->SetBorder( |
| views::CreateEmptyBorder(1, 0, 0, 0)); |
| } |
| button_bar_->SchedulePaint(); |
| } |
| button_bar_->SetBounds(0, |
| height() - button_height, |
| width(), |
| button_height); |
| if (GetWidget()) |
| GetWidget()->GetRootView()->SchedulePaint(); |
| } |
| |
| gfx::Size MessageCenterView::GetPreferredSize() const { |
| if (settings_transition_animation_ && |
| settings_transition_animation_->is_animating()) { |
| int content_width = |
| std::max(source_view_ ? source_view_->GetPreferredSize().width() : 0, |
| target_view_ ? target_view_->GetPreferredSize().width() : 0); |
| int width = std::max(content_width, |
| button_bar_->GetPreferredSize().width()); |
| return gfx::Size(width, GetHeightForWidth(width)); |
| } |
| |
| int width = 0; |
| for (int i = 0; i < child_count(); ++i) { |
| const views::View* child = child_at(0); |
| if (child->visible()) |
| width = std::max(width, child->GetPreferredSize().width()); |
| } |
| return gfx::Size(width, GetHeightForWidth(width)); |
| } |
| |
| int MessageCenterView::GetHeightForWidth(int width) const { |
| views::Border* button_border = button_bar_->border(); |
| if (settings_transition_animation_ && |
| settings_transition_animation_->is_animating()) { |
| int content_height = target_height_; |
| if (settings_transition_animation_->current_part_index() == 0) { |
| content_height = settings_transition_animation_->CurrentValueBetween( |
| source_height_, target_height_); |
| } |
| return button_bar_->GetHeightForWidth(width) + content_height + |
| (button_border ? button_border->GetInsets().height() : 0); |
| } |
| |
| int content_height = 0; |
| if (scroller_->visible()) |
| content_height += scroller_->GetHeightForWidth(width); |
| else if (settings_view_->visible()) |
| content_height += settings_view_->GetHeightForWidth(width); |
| return button_bar_->GetHeightForWidth(width) + content_height + |
| (button_border ? button_border->GetInsets().height() : 0); |
| } |
| |
| bool MessageCenterView::OnMouseWheel(const ui::MouseWheelEvent& event) { |
| // Do not rely on the default scroll event handler of ScrollView because |
| // the scroll happens only when the focus is on the ScrollView. The |
| // notification center will allow the scrolling even when the focus is on |
| // the buttons. |
| if (scroller_->bounds().Contains(event.location())) |
| return scroller_->OnMouseWheel(event); |
| return views::View::OnMouseWheel(event); |
| } |
| |
| void MessageCenterView::OnMouseExited(const ui::MouseEvent& event) { |
| if (is_closing_) |
| return; |
| |
| message_list_view_->ResetRepositionSession(); |
| Update(true /* animate */); |
| } |
| |
| void MessageCenterView::OnNotificationAdded(const std::string& id) { |
| int index = 0; |
| const NotificationList::Notifications& notifications = |
| message_center_->GetVisibleNotifications(); |
| for (NotificationList::Notifications::const_iterator iter = |
| notifications.begin(); iter != notifications.end(); |
| ++iter, ++index) { |
| if ((*iter)->id() == id) { |
| AddNotificationAt(*(*iter), index); |
| break; |
| } |
| if (notification_views_.size() >= kMaxVisibleMessageCenterNotifications) |
| break; |
| } |
| Update(true /* animate */); |
| } |
| |
| void MessageCenterView::OnNotificationRemoved(const std::string& id, |
| bool by_user) { |
| NotificationViewsMap::iterator view_iter = notification_views_.find(id); |
| if (view_iter == notification_views_.end()) |
| return; |
| MessageView* view = view_iter->second; |
| int index = message_list_view_->GetIndexOf(view); |
| DCHECK_LE(0, index); |
| if (by_user) { |
| message_list_view_->SetRepositionTarget(view->bounds()); |
| // Moves the keyboard focus to the next notification if the removed |
| // notification is focused so that the user can dismiss notifications |
| // without re-focusing by tab key. |
| if (view->IsCloseButtonFocused() || view->HasFocus()) { |
| views::View* next_focused_view = NULL; |
| if (message_list_view_->child_count() > index + 1) |
| next_focused_view = message_list_view_->child_at(index + 1); |
| else if (index > 0) |
| next_focused_view = message_list_view_->child_at(index - 1); |
| |
| if (next_focused_view) { |
| if (view->IsCloseButtonFocused()) { |
| // Safe cast since all views in MessageListView are MessageViews. |
| static_cast<MessageView*>( |
| next_focused_view)->RequestFocusOnCloseButton(); |
| } else { |
| next_focused_view->RequestFocus(); |
| } |
| } |
| } |
| } |
| message_list_view_->RemoveNotification(view); |
| notification_views_.erase(view_iter); |
| Update(true /* animate */); |
| } |
| |
| // This is a separate function so we can override it in tests. |
| bool MessageCenterView::SetRepositionTarget() { |
| // Set the item on the mouse cursor as the reposition target so that it |
| // should stick to the current position over the update. |
| if (message_list_view_->IsMouseHovered()) { |
| for (const auto& hover_id_view : notification_views_) { |
| MessageView* hover_view = hover_id_view.second; |
| |
| if (hover_view->IsMouseHovered()) { |
| message_list_view_->SetRepositionTarget(hover_view->bounds()); |
| return true; |
| } |
| } |
| } |
| return false; |
| } |
| |
| void MessageCenterView::OnNotificationUpdated(const std::string& id) { |
| // TODO(edcourtney): We may be able to remove this, since |UpdateNotification| |
| // checks it anyway. |
| NotificationViewsMap::const_iterator view_iter = notification_views_.find(id); |
| if (view_iter == notification_views_.end()) |
| return; |
| |
| // If there is no reposition target anymore, make sure to reset the reposition |
| // session. |
| if (!SetRepositionTarget()) |
| message_list_view_->ResetRepositionSession(); |
| |
| UpdateNotification(id); |
| } |
| |
| void MessageCenterView::OnLockedStateChanged(bool locked) { |
| is_locked_ = locked; |
| UpdateButtonBarStatus(); |
| Update(true /* animate */); |
| } |
| |
| void MessageCenterView::ClickOnNotification( |
| const std::string& notification_id) { |
| message_center_->ClickOnNotification(notification_id); |
| } |
| |
| void MessageCenterView::RemoveNotification(const std::string& notification_id, |
| bool by_user) { |
| message_center_->RemoveNotification(notification_id, by_user); |
| } |
| |
| std::unique_ptr<ui::MenuModel> MessageCenterView::CreateMenuModel( |
| const NotifierId& notifier_id, |
| const base::string16& display_source) { |
| return tray_->CreateNotificationMenuModel(notifier_id, display_source); |
| } |
| |
| bool MessageCenterView::HasClickedListener(const std::string& notification_id) { |
| return message_center_->HasClickedListener(notification_id); |
| } |
| |
| void MessageCenterView::ClickOnNotificationButton( |
| const std::string& notification_id, |
| int button_index) { |
| message_center_->ClickOnNotificationButton(notification_id, button_index); |
| } |
| |
| void MessageCenterView::ClickOnSettingsButton( |
| const std::string& notification_id) { |
| message_center_->ClickOnSettingsButton(notification_id); |
| } |
| |
| void MessageCenterView::UpdateNotificationSize( |
| const std::string& notification_id) { |
| // TODO(edcourtney, yoshiki): We don't call OnNotificationUpdated directly |
| // because it resets the reposition session, which can end up deleting |
| // notification items when it cancels animations. This causes problems for |
| // ARC notifications. See crbug.com/714493. OnNotificationUpdated should not |
| // have to consider the reposition session, but OnMouseEntered and |
| // OnMouseExited don't work properly for ARC notifications at the moment. |
| // See crbug.com/714587. |
| UpdateNotification(notification_id); |
| } |
| |
| void MessageCenterView::AnimationEnded(const gfx::Animation* animation) { |
| DCHECK_EQ(animation, settings_transition_animation_.get()); |
| |
| Visibility visibility = |
| mode_ == Mode::SETTINGS ? VISIBILITY_SETTINGS : VISIBILITY_MESSAGE_CENTER; |
| message_center_->SetVisibility(visibility); |
| |
| if (source_view_) { |
| source_view_->SetVisible(false); |
| } |
| if (target_view_) |
| target_view_->SetVisible(true); |
| if (source_view_ && source_view_->layer()) |
| source_view_->layer()->SetOpacity(1.0); |
| if (target_view_ && target_view_->layer()) |
| target_view_->layer()->SetOpacity(1.0); |
| settings_transition_animation_.reset(); |
| PreferredSizeChanged(); |
| Layout(); |
| } |
| |
| void MessageCenterView::AnimationProgressed(const gfx::Animation* animation) { |
| DCHECK_EQ(animation, settings_transition_animation_.get()); |
| PreferredSizeChanged(); |
| if (settings_transition_animation_->current_part_index() == 1) { |
| if (source_view_ && source_view_->layer()) { |
| source_view_->layer()->SetOpacity( |
| 1.0 - settings_transition_animation_->GetCurrentValue()); |
| SchedulePaint(); |
| } |
| } else if (settings_transition_animation_->current_part_index() == 2) { |
| if (target_view_ && target_view_->layer()) { |
| target_view_->layer()->SetOpacity( |
| settings_transition_animation_->GetCurrentValue()); |
| SchedulePaint(); |
| } |
| } |
| } |
| |
| void MessageCenterView::AnimationCanceled(const gfx::Animation* animation) { |
| DCHECK_EQ(animation, settings_transition_animation_.get()); |
| AnimationEnded(animation); |
| } |
| |
| void MessageCenterView::AddNotificationAt(const Notification& notification, |
| int index) { |
| MessageView* view = |
| MessageViewFactory::Create(this, notification, false); // Not top-level. |
| view->set_context_menu_controller(context_menu_controller_.get()); |
| notification_views_[notification.id()] = view; |
| view->set_scroller(scroller_); |
| message_list_view_->AddNotificationAt(view, index); |
| } |
| |
| base::string16 MessageCenterView::GetButtonBarTitle() const { |
| if (is_locked_) |
| return l10n_util::GetStringUTF16(IDS_MESSAGE_CENTER_FOOTER_LOCKSCREEN); |
| |
| if (mode_ == Mode::BUTTONS_ONLY) |
| return l10n_util::GetStringUTF16(IDS_MESSAGE_CENTER_NO_MESSAGES); |
| |
| return l10n_util::GetStringUTF16(IDS_MESSAGE_CENTER_FOOTER_TITLE); |
| } |
| |
| void MessageCenterView::Update(bool animate) { |
| bool no_message_views = notification_views_.empty(); |
| |
| if (is_locked_) |
| SetVisibilityMode(Mode::BUTTONS_ONLY, animate); |
| else if (settings_visible_) |
| SetVisibilityMode(Mode::SETTINGS, animate); |
| else if (no_message_views) |
| SetVisibilityMode(Mode::BUTTONS_ONLY, animate); |
| else |
| SetVisibilityMode(Mode::NOTIFICATIONS, animate); |
| |
| if (no_message_views) { |
| scroller_->SetFocusBehavior(FocusBehavior::NEVER); |
| } else { |
| #if defined(OS_MACOSX) |
| scroller_->SetFocusBehavior(FocusBehavior::ACCESSIBLE_ONLY); |
| #else |
| scroller_->SetFocusBehavior(FocusBehavior::ALWAYS); |
| #endif |
| } |
| |
| UpdateButtonBarStatus(); |
| |
| if (scroller_->visible()) |
| scroller_->InvalidateLayout(); |
| PreferredSizeChanged(); |
| Layout(); |
| } |
| |
| void MessageCenterView::SetVisibilityMode(Mode mode, bool animate) { |
| if (is_closing_) |
| return; |
| |
| if (mode == mode_) |
| return; |
| |
| if (mode_ == Mode::NOTIFICATIONS) |
| source_view_ = scroller_; |
| else if (mode_ == Mode::SETTINGS) |
| source_view_ = settings_view_; |
| else |
| source_view_ = NULL; |
| |
| if (mode == Mode::NOTIFICATIONS) |
| target_view_ = scroller_; |
| else if (mode == Mode::SETTINGS) |
| target_view_ = settings_view_; |
| else |
| target_view_ = NULL; |
| |
| mode_ = mode; |
| |
| source_height_ = source_view_ ? source_view_->GetHeightForWidth(width()) : 0; |
| target_height_ = target_view_ ? target_view_->GetHeightForWidth(width()) : 0; |
| |
| if (!animate || disable_animation_for_testing) { |
| AnimationEnded(NULL); |
| return; |
| } |
| |
| gfx::MultiAnimation::Parts parts; |
| // First part: slide resize animation. |
| parts.push_back(gfx::MultiAnimation::Part( |
| (source_height_ == target_height_) ? 0 : kDefaultAnimationDurationMs, |
| gfx::Tween::EASE_OUT)); |
| // Second part: fade-out the source_view. |
| if (source_view_ && source_view_->layer()) { |
| parts.push_back(gfx::MultiAnimation::Part( |
| kDefaultAnimationDurationMs, gfx::Tween::LINEAR)); |
| } else { |
| parts.push_back(gfx::MultiAnimation::Part()); |
| } |
| // Third part: fade-in the target_view. |
| if (target_view_ && target_view_->layer()) { |
| parts.push_back(gfx::MultiAnimation::Part( |
| kDefaultAnimationDurationMs, gfx::Tween::LINEAR)); |
| target_view_->layer()->SetOpacity(0); |
| target_view_->SetVisible(true); |
| } else { |
| parts.push_back(gfx::MultiAnimation::Part()); |
| } |
| settings_transition_animation_.reset(new gfx::MultiAnimation( |
| parts, base::TimeDelta::FromMicroseconds(1000000 / kDefaultFrameRateHz))); |
| settings_transition_animation_->set_delegate(this); |
| settings_transition_animation_->set_continuous(false); |
| settings_transition_animation_->Start(); |
| } |
| |
| void MessageCenterView::UpdateButtonBarStatus() { |
| // Disables all buttons during animation of cleaning of all notifications. |
| if (is_clearing_all_notifications_) { |
| button_bar_->SetSettingsAndQuietModeButtonsEnabled(false); |
| button_bar_->SetCloseAllButtonEnabled(false); |
| return; |
| } |
| |
| button_bar_->SetBackArrowVisible(mode_ == Mode::SETTINGS); |
| button_bar_->SetButtonsVisible(!is_locked_); |
| button_bar_->SetTitle(GetButtonBarTitle()); |
| |
| if (!is_locked_) |
| EnableCloseAllIfAppropriate(); |
| } |
| |
| void MessageCenterView::EnableCloseAllIfAppropriate() { |
| if (mode_ == Mode::NOTIFICATIONS) { |
| bool no_closable_views = true; |
| for (const auto& view : notification_views_) { |
| if (!view.second->IsPinned()) { |
| no_closable_views = false; |
| break; |
| } |
| } |
| button_bar_->SetCloseAllButtonEnabled(!no_closable_views); |
| } else { |
| // Disable the close-all button since no notification is visible. |
| button_bar_->SetCloseAllButtonEnabled(false); |
| } |
| } |
| |
| void MessageCenterView::SetNotificationViewForTest(MessageView* view) { |
| message_list_view_->AddNotificationAt(view, 0); |
| } |
| |
| void MessageCenterView::UpdateNotification(const std::string& id) { |
| // TODO(edcourtney, yoshiki): This check seems like it should not be needed. |
| // Investigate what circumstances (if any) trigger it. |
| NotificationViewsMap::const_iterator view_iter = notification_views_.find(id); |
| if (view_iter == notification_views_.end()) |
| return; |
| |
| // TODO(dimich): add MessageCenter::GetVisibleNotificationById(id) |
| MessageView* view = view_iter->second; |
| const NotificationList::Notifications& notifications = |
| message_center_->GetVisibleNotifications(); |
| for (NotificationList::Notifications::const_iterator iter = |
| notifications.begin(); |
| iter != notifications.end(); ++iter) { |
| if ((*iter)->id() == id) { |
| int old_width = view->width(); |
| int old_height = view->height(); |
| bool old_pinned = view->IsPinned(); |
| message_list_view_->UpdateNotification(view, **iter); |
| if (view->GetHeightForWidth(old_width) != old_height) { |
| Update(true /* animate */); |
| } else if (view->IsPinned() != old_pinned) { |
| // Animate flag is false, since the pinned flag transition doesn't need |
| // animation. |
| Update(false /* animate */); |
| } |
| break; |
| } |
| } |
| |
| // Notify accessibility that the contents have changed. |
| view->NotifyAccessibilityEvent(ui::AX_EVENT_CHILDREN_CHANGED, false); |
| } |
| |
| } // namespace message_center |