blob: ad5b357e4815bc185fd0b96de34b0ca7991fdf46 [file] [log] [blame]
// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef ASH_CLIPBOARD_CLIPBOARD_HISTORY_MENU_MODEL_ADAPTER_H_
#define ASH_CLIPBOARD_CLIPBOARD_HISTORY_MENU_MODEL_ADAPTER_H_
#include <memory>
#include <optional>
#include "ash/ash_export.h"
#include "ash/public/cpp/clipboard_history_controller.h"
#include "base/memory/raw_ptr.h"
#include "base/time/time.h"
#include "chromeos/crosapi/mojom/clipboard_history.mojom.h"
#include "ui/base/models/simple_menu_model.h"
#include "ui/views/controls/menu/menu_model_adapter.h"
namespace gfx {
class Rect;
} // namespace gfx
namespace views {
class MenuItemView;
class MenuRunner;
} // namespace views
namespace ash {
namespace clipboard_history_util {
enum class Action;
} // namespace clipboard_history_util
class ClipboardHistory;
class ClipboardHistoryItem;
class ClipboardHistoryItemView;
// Used to show the clipboard history menu, which holds the last few things
// copied.
class ASH_EXPORT ClipboardHistoryMenuModelAdapter
: public views::MenuModelAdapter {
public:
static std::unique_ptr<ClipboardHistoryMenuModelAdapter> Create(
ui::SimpleMenuModel::Delegate* delegate,
ClipboardHistoryController::OnMenuClosingCallback
on_menu_closing_callback,
base::RepeatingClosure menu_closed_callback,
const ClipboardHistory* clipboard_history);
ClipboardHistoryMenuModelAdapter(const ClipboardHistoryMenuModelAdapter&) =
delete;
ClipboardHistoryMenuModelAdapter& operator=(
const ClipboardHistoryMenuModelAdapter&) = delete;
~ClipboardHistoryMenuModelAdapter() override;
// Shows the menu anchored at `anchor_rect`. `source_type` and `show_source`
// indicate how the menu was triggered. `menu_last_time_shown` and
// `nudge_last_time_shown` indicate when the menu or any nudge was last shown.
void Run(const gfx::Rect& anchor_rect,
ui::MenuSourceType source_type,
crosapi::mojom::ClipboardHistoryControllerShowSource show_source,
const std::optional<base::Time>& menu_last_time_shown,
const std::optional<base::Time>& nudge_last_time_shown);
// Returns if the menu is currently running.
bool IsRunning() const;
// Hides and cancels the menu. `will_paste_item` indicates whether a clipboard
// history item will be pasted after the menu is closed.
void Cancel(bool will_paste_item);
// Returns the command of the menu's first clipboard history item. This
// differs from `clipboard_history_util::kFirstItemCommandId` when the menu's
// first item has been removed. If the menu is empty, the result is absent.
std::optional<int> GetFirstMenuItemCommand();
// Returns the command of the currently selected menu item. If no menu item is
// currently selected, returns |std::nullopt|.
std::optional<int> GetSelectedMenuItemCommand() const;
// Returns the item mapped by `command_id` in `item_snapshots_`.
const ClipboardHistoryItem& GetItemFromCommandId(int command_id) const;
// Returns the count of menu items.
size_t GetMenuItemsCount() const;
// Selects the menu item specified by `command_id`.
void SelectMenuItemWithCommandId(int command_id);
// Selects the menu item hovered by mouse.
void SelectMenuItemHoveredByMouse();
// Removes the menu item specified by `command_id`.
void RemoveMenuItemWithCommandId(int command_id);
// Advances the pseudo focus (backward if `reverse` is true).
void AdvancePseudoFocus(bool reverse);
// Returns the action to take on the menu item specified by `command_id`.
clipboard_history_util::Action GetActionForCommandId(int command_id) const;
// Returns menu bounds in screen coordinates.
gfx::Rect GetMenuBoundsInScreenForTest() const;
const views::MenuItemView* GetMenuItemViewAtForTest(size_t index) const;
views::MenuItemView* GetMenuItemViewAtForTest(size_t index);
const ui::SimpleMenuModel* GetModelForTest() const;
private:
class MenuModelWithWillCloseCallback;
class ScopedA11yIgnore;
using ItemViewsByCommandId = std::map<int, ClipboardHistoryItemView*>;
ClipboardHistoryMenuModelAdapter(
std::unique_ptr<MenuModelWithWillCloseCallback> model,
base::RepeatingClosure menu_closed_callback,
const ClipboardHistory* clipboard_history);
// Advances the pseduo focus from the selected history item view (backward if
// `reverse` is true).
void AdvancePseudoFocusFromSelectedItem(bool reverse);
// Returns the command id of the menu item to be selected after the
// menu item specified by `command_id` is deleted.
int CalculateSelectedCommandIdAfterDeletion(int command_id) const;
// Removes the item view specified by `command_id` from the root menu.
void RemoveItemView(int command_id);
// views::MenuModelAdapter:
views::MenuItemView* AppendMenuItem(views::MenuItemView* menu,
ui::MenuModel* model,
size_t index) override;
void OnMenuClosed(views::MenuItemView* menu) override;
// The model which holds the contents of the menu.
std::unique_ptr<MenuModelWithWillCloseCallback> const model_;
// Responsible for showing `root_view_`.
std::unique_ptr<views::MenuRunner> menu_runner_;
// The root MenuItemView which contains all child MenuItemViews. Owned by
// `menu_runner_`.
raw_ptr<views::MenuItemView> root_view_ = nullptr;
// The timestamp taken when the menu is opened. Used in metrics.
base::TimeTicks menu_open_time_;
// The source which opened the menu, absent until the menu is `Run()`.
std::optional<crosapi::mojom::ClipboardHistoryControllerShowSource>
menu_show_source_;
// The mapping between the command ids and items that are copied from
// `clipboard_history_` when the menu is created. It is used to solve the
// possible inconsistency between the menu model data and the clipboard
// history data. For example, a new item is added to `clipboard_history_`
// while the menu is showing.
// It updates synchronously when a item is removed.
std::map<int, ClipboardHistoryItem> item_snapshots_;
// Stores mappings between command ids and history item view pointers.
// It updates synchronously when a item is removed.
ItemViewsByCommandId item_views_by_command_id_;
const raw_ptr<const ClipboardHistory> clipboard_history_;
// Indicates the number of item deletion operations in progress. Note that
// a `ClipboardHistoryItemView` instance is deleted asynchronously.
int item_deletion_in_progress_count_ = 0;
// The index of the clipboard history menu header, if it exists.
std::optional<size_t> header_index_;
// The index of the clipboard history menu footer, if it exists.
std::optional<size_t> footer_index_;
std::unique_ptr<ScopedA11yIgnore> scoped_ignore_;
// Indicates whether `Run()` has been called before.
bool run_before_ = false;
base::WeakPtrFactory<ClipboardHistoryMenuModelAdapter> weak_ptr_factory_{
this};
};
} // namespace ash
#endif // ASH_CLIPBOARD_CLIPBOARD_HISTORY_MENU_MODEL_ADAPTER_H_