blob: 8bffb8b57f87b3d234b2560e61da6503ab302c43 [file] [log] [blame]
yusukes1168eda2016-04-27 07:52:081// Copyright 2016 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Eriko Kurimotob9da4032022-01-20 00:57:415#include "chrome/browser/chromeos/arc/open_with_menu.h"
yusukes1168eda2016-04-27 07:52:086
yusukesa0c660462016-05-04 17:04:267#include <algorithm>
yusukes1168eda2016-04-27 07:52:088
yusukes1168eda2016-04-27 07:52:089#include "base/strings/string_util.h"
Eriko Kurimoto0e0d14a2022-01-28 01:57:0410#include "build/chromeos_buildflags.h"
yusukes1168eda2016-04-27 07:52:0811#include "chrome/app/chrome_command_ids.h"
yusukes1168eda2016-04-27 07:52:0812#include "chrome/grit/generated_resources.h"
yusukes1168eda2016-04-27 07:52:0813#include "components/renderer_context_menu/render_view_context_menu_proxy.h"
David Jacobo8a5eba0a2018-08-09 05:07:2214#include "content/public/browser/browser_context.h"
Lukasz Anforowicz8c4446dc2020-03-11 22:16:4215#include "content/public/browser/context_menu_params.h"
yusukes1168eda2016-04-27 07:52:0816#include "ui/base/l10n/l10n_util.h"
Richard Knoll8c549102020-08-25 17:24:0717#include "ui/base/models/image_model.h"
yusukes1168eda2016-04-27 07:52:0818
Eriko Kurimoto0e0d14a2022-01-28 01:57:0419#if BUILDFLAG(IS_CHROMEOS_ASH)
20#include "chrome/browser/ash/arc/intent_helper/arc_intent_helper_mojo_ash.h"
21#else // BUILDFLAG(IS_CHROMEOS_LACROS)
22#include "chrome/browser/lacros/arc/arc_intent_helper_mojo_lacros.h"
23#endif
24
Evan Stade6bf35f02017-09-01 01:11:1325namespace arc {
yusukes1168eda2016-04-27 07:52:0826
Evan Stade6bf35f02017-09-01 01:11:1327const int OpenWithMenu::kNumMainMenuCommands = 4;
28const int OpenWithMenu::kNumSubMenuCommands = 10;
29
30bool OpenWithMenu::SubMenuDelegate::IsCommandIdChecked(int command_id) const {
yusukesa0c660462016-05-04 17:04:2631 return false;
32}
yusukes1168eda2016-04-27 07:52:0833
Evan Stade6bf35f02017-09-01 01:11:1334bool OpenWithMenu::SubMenuDelegate::IsCommandIdEnabled(int command_id) const {
yusukesa0c660462016-05-04 17:04:2635 return true;
36}
37
Evan Stade6bf35f02017-09-01 01:11:1338void OpenWithMenu::SubMenuDelegate::ExecuteCommand(int command_id,
39 int event_flags) {
yusukesa0c660462016-05-04 17:04:2640 parent_->ExecuteCommand(command_id);
41}
42
Evan Stade6bf35f02017-09-01 01:11:1343OpenWithMenu::OpenWithMenu(content::BrowserContext* context,
44 RenderViewContextMenuProxy* proxy)
45 : context_(context),
46 proxy_(proxy),
yusukesa0c660462016-05-04 17:04:2647 more_apps_label_(
48 l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_MORE_APPS)) {}
49
Evan Stade6bf35f02017-09-01 01:11:1350OpenWithMenu::~OpenWithMenu() = default;
yusukesa0c660462016-05-04 17:04:2651
Evan Stade6bf35f02017-09-01 01:11:1352void OpenWithMenu::InitMenu(const content::ContextMenuParams& params) {
David Jacobo8a5eba0a2018-08-09 05:07:2253 // Enforcing no items are added to the context menu during incognito mode.
54 if (context_->IsOffTheRecord())
55 return;
56
Eriko Kurimoto0e0d14a2022-01-28 01:57:0457#if BUILDFLAG(IS_CHROMEOS_ASH)
58 using ArcIntentHelperMojo = ArcIntentHelperMojoAsh;
59#else // BUILDFLAG(IS_CHROMEOS_LACROS)
60 using ArcIntentHelperMojo = ArcIntentHelperMojoLacros;
61#endif
62 menu_model_ = LinkHandlerModel::Create(
63 context_, params.link_url, std::make_unique<ArcIntentHelperMojo>());
yusukesa0c660462016-05-04 17:04:2664 if (!menu_model_)
65 return;
66
67 // Add placeholder items.
68 std::unique_ptr<ui::SimpleMenuModel> submenu(
69 new ui::SimpleMenuModel(&submenu_delegate_));
70 AddPlaceholderItems(proxy_, submenu.get());
71 submenu_ = std::move(submenu);
72
73 menu_model_->AddObserver(this);
74}
75
Evan Stade6bf35f02017-09-01 01:11:1376bool OpenWithMenu::IsCommandIdSupported(int command_id) {
yusukesa0c660462016-05-04 17:04:2677 return command_id >= IDC_CONTENT_CONTEXT_OPEN_WITH1 &&
78 command_id <= IDC_CONTENT_CONTEXT_OPEN_WITH_LAST;
79}
80
Evan Stade6bf35f02017-09-01 01:11:1381bool OpenWithMenu::IsCommandIdChecked(int command_id) {
yusukesa0c660462016-05-04 17:04:2682 return false;
83}
84
Evan Stade6bf35f02017-09-01 01:11:1385bool OpenWithMenu::IsCommandIdEnabled(int command_id) {
yusukesa0c660462016-05-04 17:04:2686 return true;
87}
88
Evan Stade6bf35f02017-09-01 01:11:1389void OpenWithMenu::ExecuteCommand(int command_id) {
yusukesa0c660462016-05-04 17:04:2690 // Note: SubmenuDelegate also calls this method with a command_id for the
91 // submenu.
92 const auto it = handlers_.find(command_id);
93 if (it == handlers_.end())
94 return;
Evan Stade6bf35f02017-09-01 01:11:1395
96 menu_model_->OpenLinkWithHandler(it->second.id);
yusukesa0c660462016-05-04 17:04:2697}
98
Evan Stade6bf35f02017-09-01 01:11:1399void OpenWithMenu::ModelChanged(const std::vector<LinkHandlerInfo>& handlers) {
yusukesa0c660462016-05-04 17:04:26100 auto result = BuildHandlersMap(handlers);
101 handlers_ = std::move(result.first);
102 const int submenu_parent_id = result.second;
103 for (int command_id = IDC_CONTENT_CONTEXT_OPEN_WITH1;
104 command_id <= IDC_CONTENT_CONTEXT_OPEN_WITH_LAST; ++command_id) {
105 const auto it = handlers_.find(command_id);
106 if (command_id == submenu_parent_id) {
107 // Show the submenu parent.
108 proxy_->UpdateMenuItem(command_id, true, false, more_apps_label_);
109 } else if (it == handlers_.end()) {
110 // Hide the menu or submenu parent.
Jan Wilken Dörrief27844b2021-03-11 23:18:48111 proxy_->UpdateMenuItem(command_id, false, true, std::u16string());
yusukesa0c660462016-05-04 17:04:26112 } else {
113 // Update the menu with the new model.
Jan Wilken Dörrief27844b2021-03-11 23:18:48114 const std::u16string label = l10n_util::GetStringFUTF16(
Evan Stade6bf35f02017-09-01 01:11:13115 IDS_CONTENT_CONTEXT_OPEN_WITH_APP, it->second.name);
yusukesa0c660462016-05-04 17:04:26116 proxy_->UpdateMenuItem(command_id, true, false, label);
117 if (!it->second.icon.IsEmpty())
Richard Knoll8c549102020-08-25 17:24:07118 proxy_->UpdateMenuIcon(command_id,
119 ui::ImageModel::FromImage(it->second.icon));
yusukesa0c660462016-05-04 17:04:26120 }
121 }
122}
123
Evan Stade6bf35f02017-09-01 01:11:13124void OpenWithMenu::AddPlaceholderItemsForTesting(
yusukesa0c660462016-05-04 17:04:26125 RenderViewContextMenuProxy* proxy,
126 ui::SimpleMenuModel* submenu) {
127 return AddPlaceholderItems(proxy, submenu);
128}
129
Evan Stade6bf35f02017-09-01 01:11:13130std::pair<OpenWithMenu::HandlerMap, int>
131OpenWithMenu::BuildHandlersMapForTesting(
132 const std::vector<LinkHandlerInfo>& handlers) {
yusukesa0c660462016-05-04 17:04:26133 return BuildHandlersMap(handlers);
134}
135
Evan Stade6bf35f02017-09-01 01:11:13136void OpenWithMenu::AddPlaceholderItems(RenderViewContextMenuProxy* proxy,
137 ui::SimpleMenuModel* submenu) {
yusukesa0c660462016-05-04 17:04:26138 for (int i = 0; i < kNumSubMenuCommands; ++i) {
139 const int command_id =
140 IDC_CONTENT_CONTEXT_OPEN_WITH1 + kNumMainMenuCommands + i;
Jan Wilken Dörrief27844b2021-03-11 23:18:48141 submenu->AddItem(command_id, std::u16string());
yusukesa0c660462016-05-04 17:04:26142 }
143 int command_id;
144 for (int i = 0; i < kNumMainMenuCommands - 1; ++i) {
145 command_id = IDC_CONTENT_CONTEXT_OPEN_WITH1 + i;
Jan Wilken Dörrief27844b2021-03-11 23:18:48146 proxy->AddMenuItem(command_id, std::u16string());
yusukesa0c660462016-05-04 17:04:26147 }
Jan Wilken Dörrief27844b2021-03-11 23:18:48148 proxy->AddSubMenu(++command_id, std::u16string(), submenu);
yusukesa0c660462016-05-04 17:04:26149}
150
Evan Stade6bf35f02017-09-01 01:11:13151std::pair<OpenWithMenu::HandlerMap, int> OpenWithMenu::BuildHandlersMap(
152 const std::vector<LinkHandlerInfo>& handlers) {
yusukesa0c660462016-05-04 17:04:26153 const int kInvalidCommandId = -1;
154 const int submenu_id_start =
155 IDC_CONTENT_CONTEXT_OPEN_WITH1 + kNumMainMenuCommands;
156
Evan Stade6bf35f02017-09-01 01:11:13157 OpenWithMenu::HandlerMap handler_map;
yusukesa0c660462016-05-04 17:04:26158 int submenu_parent_command_id = kInvalidCommandId;
159
160 const int num_apps = handlers.size();
161 size_t handlers_index = 0;
162 // We use the last item in the main menu (IDC_CONTENT_CONTEXT_OPEN_WITH1 +
163 // kNumMainMenuCommands- 1) as a parent of a submenu, and others as regular
164 // menu items.
165 if (num_apps < kNumMainMenuCommands) {
166 // All apps can be shown with the regular main menu items.
167 for (int i = 0; i < num_apps; ++i) {
168 handler_map[IDC_CONTENT_CONTEXT_OPEN_WITH1 + i] =
169 handlers[handlers_index++];
170 }
171 } else {
172 // Otherwise, use the submenu too. In this case, disable the last item of
173 // the regular main menu (hence '-2').
174 for (int i = 0; i < kNumMainMenuCommands - 2; ++i) {
175 handler_map[IDC_CONTENT_CONTEXT_OPEN_WITH1 + i] =
176 handlers[handlers_index++];
177 }
178 submenu_parent_command_id =
179 IDC_CONTENT_CONTEXT_OPEN_WITH1 + kNumMainMenuCommands - 1;
180 const int sub_items =
181 std::min(num_apps - (kNumMainMenuCommands - 2), kNumSubMenuCommands);
182 for (int i = 0; i < sub_items; ++i) {
183 handler_map[submenu_id_start + i] = handlers[handlers_index++];
184 }
185 }
186
187 return std::make_pair(std::move(handler_map), submenu_parent_command_id);
yusukes1168eda2016-04-27 07:52:08188}
189
Evan Stade6bf35f02017-09-01 01:11:13190} // namespace arc