chromium/ash/app_menu/notification_menu_controller.cc

// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ash/app_menu/notification_menu_controller.h"

#include "ash/app_menu/app_menu_model_adapter.h"
#include "ash/app_menu/notification_menu_view.h"
#include "ash/public/cpp/app_menu_constants.h"
#include "ui/base/models/simple_menu_model.h"
#include "ui/views/controls/menu/menu_item_view.h"
#include "ui/views/controls/menu/submenu_view.h"

namespace ash {

NotificationMenuController::NotificationMenuController(
    const std::string& app_id,
    views::MenuItemView* root_menu,
    AppMenuModelAdapter* app_menu_model_adapter)
    : app_id_(app_id),
      root_menu_(root_menu),
      app_menu_model_adapter_(app_menu_model_adapter) {
  DCHECK(app_menu_model_adapter_);
  message_center_observation_.Observe(message_center::MessageCenter::Get());
  InitializeNotificationMenuView();
}

NotificationMenuController::~NotificationMenuController() = default;

void NotificationMenuController::OnNotificationAdded(
    const std::string& notification_id) {
  message_center::Notification* notification =
      message_center::MessageCenter::Get()->FindVisibleNotificationById(
          notification_id);

  DCHECK(notification);

  if (notification->notifier_id().id != app_id_)
    return;

  if (!notification_menu_view_) {
    InitializeNotificationMenuView();
    return;
  }

  notification_menu_view_->AddNotificationItemView(*notification);
}

void NotificationMenuController::OnNotificationUpdated(
    const std::string& notification_id) {
  if (!notification_menu_view_)
    return;

  message_center::Notification* notification =
      message_center::MessageCenter::Get()->FindVisibleNotificationById(
          notification_id);

  DCHECK(notification);
  if (notification->notifier_id().id != app_id_)
    return;

  notification_menu_view_->UpdateNotificationItemView(*notification);
}

void NotificationMenuController::OnNotificationRemoved(
    const std::string& notification_id,
    bool by_user) {
  if (!notification_menu_view_)
    return;

  // Remove the view from the container.
  notification_menu_view_->OnNotificationRemoved(notification_id);

  if (!notification_menu_view_->IsEmpty())
    return;

  // There are no more notifications to show, so remove |item_| from
  // |root_menu_|, and remove the entry from the model.
  root_menu_->RemoveMenuItem(notification_menu_view_->parent());
  app_menu_model_adapter_->model()->RemoveItemAt(
      app_menu_model_adapter_->model()
          ->GetIndexOfCommandId(NOTIFICATION_CONTAINER)
          .value());
  notification_menu_view_ = nullptr;

  // Notify the root MenuItemView so it knows to resize and re-calculate the
  // menu bounds.
  root_menu_->ChildrenChanged();
}

ui::Layer* NotificationMenuController::GetSlideOutLayer() {
  return notification_menu_view_ ? notification_menu_view_->GetSlideOutLayer()
                                 : nullptr;
}

void NotificationMenuController::OnSlideChanged(bool in_progress) {}

void NotificationMenuController::OnSlideOut() {
  // Results in |this| being deleted if there are no more notifications to show.
  // Only the displayed NotificationItemView can call OnSlideOut.
  message_center::MessageCenter::Get()->RemoveNotification(
      notification_menu_view_->GetDisplayedNotificationID(), true);
}

void NotificationMenuController::ActivateNotificationAndClose(
    const std::string& notification_id) {
  message_center::MessageCenter::Get()->ClickOnNotification(notification_id);

  // Results in |this| being deleted.
  app_menu_model_adapter_->Cancel();
}

void NotificationMenuController::OnOverflowAddedOrRemoved() {
  // Make the root MenuItemView recalculate the menu bounds.
  root_menu_->ChildrenChanged();
}

void NotificationMenuController::InitializeNotificationMenuView() {
  DCHECK(!notification_menu_view_);

  // Initialize the container only if there are notifications to show.
  if (message_center::MessageCenter::Get()
          ->FindNotificationsByAppId(app_id_)
          .empty()) {
    return;
  }

  app_menu_model_adapter_->model()->AddItem(NOTIFICATION_CONTAINER,
                                            std::u16string());
  // Add the container MenuItemView to |root_menu_|.
  views::MenuItemView* container =
      root_menu_->AppendMenuItem(NOTIFICATION_CONTAINER);
  notification_menu_view_ = new NotificationMenuView(this, this, app_id_);
  container->AddChildView(notification_menu_view_.get());

  for (message_center::Notification* notification :
       message_center::MessageCenter::Get()->FindNotificationsByAppId(
           app_id_)) {
    notification_menu_view_->AddNotificationItemView(*notification);
  }

  // Notify the root MenuItemView so it knows to resize and re-calculate the
  // menu bounds.
  root_menu_->ChildrenChanged();
}

}  // namespace ash