yusukes | 1168eda | 2016-04-27 07:52:08 | [diff] [blame] | 1 | // 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 Kurimoto | b9da403 | 2022-01-20 00:57:41 | [diff] [blame] | 5 | #include "chrome/browser/chromeos/arc/open_with_menu.h" |
yusukes | 1168eda | 2016-04-27 07:52:08 | [diff] [blame] | 6 | |
yusukes | a0c66046 | 2016-05-04 17:04:26 | [diff] [blame] | 7 | #include <algorithm> |
yusukes | 1168eda | 2016-04-27 07:52:08 | [diff] [blame] | 8 | |
yusukes | 1168eda | 2016-04-27 07:52:08 | [diff] [blame] | 9 | #include "base/strings/string_util.h" |
Eriko Kurimoto | 0e0d14a | 2022-01-28 01:57:04 | [diff] [blame] | 10 | #include "build/chromeos_buildflags.h" |
yusukes | 1168eda | 2016-04-27 07:52:08 | [diff] [blame] | 11 | #include "chrome/app/chrome_command_ids.h" |
yusukes | 1168eda | 2016-04-27 07:52:08 | [diff] [blame] | 12 | #include "chrome/grit/generated_resources.h" |
yusukes | 1168eda | 2016-04-27 07:52:08 | [diff] [blame] | 13 | #include "components/renderer_context_menu/render_view_context_menu_proxy.h" |
David Jacobo | 8a5eba0a | 2018-08-09 05:07:22 | [diff] [blame] | 14 | #include "content/public/browser/browser_context.h" |
Lukasz Anforowicz | 8c4446dc | 2020-03-11 22:16:42 | [diff] [blame] | 15 | #include "content/public/browser/context_menu_params.h" |
yusukes | 1168eda | 2016-04-27 07:52:08 | [diff] [blame] | 16 | #include "ui/base/l10n/l10n_util.h" |
Richard Knoll | 8c54910 | 2020-08-25 17:24:07 | [diff] [blame] | 17 | #include "ui/base/models/image_model.h" |
yusukes | 1168eda | 2016-04-27 07:52:08 | [diff] [blame] | 18 | |
Eriko Kurimoto | 0e0d14a | 2022-01-28 01:57:04 | [diff] [blame] | 19 | #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 Stade | 6bf35f0 | 2017-09-01 01:11:13 | [diff] [blame] | 25 | namespace arc { |
yusukes | 1168eda | 2016-04-27 07:52:08 | [diff] [blame] | 26 | |
Evan Stade | 6bf35f0 | 2017-09-01 01:11:13 | [diff] [blame] | 27 | const int OpenWithMenu::kNumMainMenuCommands = 4; |
| 28 | const int OpenWithMenu::kNumSubMenuCommands = 10; |
| 29 | |
| 30 | bool OpenWithMenu::SubMenuDelegate::IsCommandIdChecked(int command_id) const { |
yusukes | a0c66046 | 2016-05-04 17:04:26 | [diff] [blame] | 31 | return false; |
| 32 | } |
yusukes | 1168eda | 2016-04-27 07:52:08 | [diff] [blame] | 33 | |
Evan Stade | 6bf35f0 | 2017-09-01 01:11:13 | [diff] [blame] | 34 | bool OpenWithMenu::SubMenuDelegate::IsCommandIdEnabled(int command_id) const { |
yusukes | a0c66046 | 2016-05-04 17:04:26 | [diff] [blame] | 35 | return true; |
| 36 | } |
| 37 | |
Evan Stade | 6bf35f0 | 2017-09-01 01:11:13 | [diff] [blame] | 38 | void OpenWithMenu::SubMenuDelegate::ExecuteCommand(int command_id, |
| 39 | int event_flags) { |
yusukes | a0c66046 | 2016-05-04 17:04:26 | [diff] [blame] | 40 | parent_->ExecuteCommand(command_id); |
| 41 | } |
| 42 | |
Evan Stade | 6bf35f0 | 2017-09-01 01:11:13 | [diff] [blame] | 43 | OpenWithMenu::OpenWithMenu(content::BrowserContext* context, |
| 44 | RenderViewContextMenuProxy* proxy) |
| 45 | : context_(context), |
| 46 | proxy_(proxy), |
yusukes | a0c66046 | 2016-05-04 17:04:26 | [diff] [blame] | 47 | more_apps_label_( |
| 48 | l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_MORE_APPS)) {} |
| 49 | |
Evan Stade | 6bf35f0 | 2017-09-01 01:11:13 | [diff] [blame] | 50 | OpenWithMenu::~OpenWithMenu() = default; |
yusukes | a0c66046 | 2016-05-04 17:04:26 | [diff] [blame] | 51 | |
Evan Stade | 6bf35f0 | 2017-09-01 01:11:13 | [diff] [blame] | 52 | void OpenWithMenu::InitMenu(const content::ContextMenuParams& params) { |
David Jacobo | 8a5eba0a | 2018-08-09 05:07:22 | [diff] [blame] | 53 | // Enforcing no items are added to the context menu during incognito mode. |
| 54 | if (context_->IsOffTheRecord()) |
| 55 | return; |
| 56 | |
Eriko Kurimoto | 0e0d14a | 2022-01-28 01:57:04 | [diff] [blame] | 57 | #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>()); |
yusukes | a0c66046 | 2016-05-04 17:04:26 | [diff] [blame] | 64 | 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 Stade | 6bf35f0 | 2017-09-01 01:11:13 | [diff] [blame] | 76 | bool OpenWithMenu::IsCommandIdSupported(int command_id) { |
yusukes | a0c66046 | 2016-05-04 17:04:26 | [diff] [blame] | 77 | return command_id >= IDC_CONTENT_CONTEXT_OPEN_WITH1 && |
| 78 | command_id <= IDC_CONTENT_CONTEXT_OPEN_WITH_LAST; |
| 79 | } |
| 80 | |
Evan Stade | 6bf35f0 | 2017-09-01 01:11:13 | [diff] [blame] | 81 | bool OpenWithMenu::IsCommandIdChecked(int command_id) { |
yusukes | a0c66046 | 2016-05-04 17:04:26 | [diff] [blame] | 82 | return false; |
| 83 | } |
| 84 | |
Evan Stade | 6bf35f0 | 2017-09-01 01:11:13 | [diff] [blame] | 85 | bool OpenWithMenu::IsCommandIdEnabled(int command_id) { |
yusukes | a0c66046 | 2016-05-04 17:04:26 | [diff] [blame] | 86 | return true; |
| 87 | } |
| 88 | |
Evan Stade | 6bf35f0 | 2017-09-01 01:11:13 | [diff] [blame] | 89 | void OpenWithMenu::ExecuteCommand(int command_id) { |
yusukes | a0c66046 | 2016-05-04 17:04:26 | [diff] [blame] | 90 | // 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 Stade | 6bf35f0 | 2017-09-01 01:11:13 | [diff] [blame] | 95 | |
| 96 | menu_model_->OpenLinkWithHandler(it->second.id); |
yusukes | a0c66046 | 2016-05-04 17:04:26 | [diff] [blame] | 97 | } |
| 98 | |
Evan Stade | 6bf35f0 | 2017-09-01 01:11:13 | [diff] [blame] | 99 | void OpenWithMenu::ModelChanged(const std::vector<LinkHandlerInfo>& handlers) { |
yusukes | a0c66046 | 2016-05-04 17:04:26 | [diff] [blame] | 100 | 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örrie | f27844b | 2021-03-11 23:18:48 | [diff] [blame] | 111 | proxy_->UpdateMenuItem(command_id, false, true, std::u16string()); |
yusukes | a0c66046 | 2016-05-04 17:04:26 | [diff] [blame] | 112 | } else { |
| 113 | // Update the menu with the new model. |
Jan Wilken Dörrie | f27844b | 2021-03-11 23:18:48 | [diff] [blame] | 114 | const std::u16string label = l10n_util::GetStringFUTF16( |
Evan Stade | 6bf35f0 | 2017-09-01 01:11:13 | [diff] [blame] | 115 | IDS_CONTENT_CONTEXT_OPEN_WITH_APP, it->second.name); |
yusukes | a0c66046 | 2016-05-04 17:04:26 | [diff] [blame] | 116 | proxy_->UpdateMenuItem(command_id, true, false, label); |
| 117 | if (!it->second.icon.IsEmpty()) |
Richard Knoll | 8c54910 | 2020-08-25 17:24:07 | [diff] [blame] | 118 | proxy_->UpdateMenuIcon(command_id, |
| 119 | ui::ImageModel::FromImage(it->second.icon)); |
yusukes | a0c66046 | 2016-05-04 17:04:26 | [diff] [blame] | 120 | } |
| 121 | } |
| 122 | } |
| 123 | |
Evan Stade | 6bf35f0 | 2017-09-01 01:11:13 | [diff] [blame] | 124 | void OpenWithMenu::AddPlaceholderItemsForTesting( |
yusukes | a0c66046 | 2016-05-04 17:04:26 | [diff] [blame] | 125 | RenderViewContextMenuProxy* proxy, |
| 126 | ui::SimpleMenuModel* submenu) { |
| 127 | return AddPlaceholderItems(proxy, submenu); |
| 128 | } |
| 129 | |
Evan Stade | 6bf35f0 | 2017-09-01 01:11:13 | [diff] [blame] | 130 | std::pair<OpenWithMenu::HandlerMap, int> |
| 131 | OpenWithMenu::BuildHandlersMapForTesting( |
| 132 | const std::vector<LinkHandlerInfo>& handlers) { |
yusukes | a0c66046 | 2016-05-04 17:04:26 | [diff] [blame] | 133 | return BuildHandlersMap(handlers); |
| 134 | } |
| 135 | |
Evan Stade | 6bf35f0 | 2017-09-01 01:11:13 | [diff] [blame] | 136 | void OpenWithMenu::AddPlaceholderItems(RenderViewContextMenuProxy* proxy, |
| 137 | ui::SimpleMenuModel* submenu) { |
yusukes | a0c66046 | 2016-05-04 17:04:26 | [diff] [blame] | 138 | for (int i = 0; i < kNumSubMenuCommands; ++i) { |
| 139 | const int command_id = |
| 140 | IDC_CONTENT_CONTEXT_OPEN_WITH1 + kNumMainMenuCommands + i; |
Jan Wilken Dörrie | f27844b | 2021-03-11 23:18:48 | [diff] [blame] | 141 | submenu->AddItem(command_id, std::u16string()); |
yusukes | a0c66046 | 2016-05-04 17:04:26 | [diff] [blame] | 142 | } |
| 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örrie | f27844b | 2021-03-11 23:18:48 | [diff] [blame] | 146 | proxy->AddMenuItem(command_id, std::u16string()); |
yusukes | a0c66046 | 2016-05-04 17:04:26 | [diff] [blame] | 147 | } |
Jan Wilken Dörrie | f27844b | 2021-03-11 23:18:48 | [diff] [blame] | 148 | proxy->AddSubMenu(++command_id, std::u16string(), submenu); |
yusukes | a0c66046 | 2016-05-04 17:04:26 | [diff] [blame] | 149 | } |
| 150 | |
Evan Stade | 6bf35f0 | 2017-09-01 01:11:13 | [diff] [blame] | 151 | std::pair<OpenWithMenu::HandlerMap, int> OpenWithMenu::BuildHandlersMap( |
| 152 | const std::vector<LinkHandlerInfo>& handlers) { |
yusukes | a0c66046 | 2016-05-04 17:04:26 | [diff] [blame] | 153 | const int kInvalidCommandId = -1; |
| 154 | const int submenu_id_start = |
| 155 | IDC_CONTENT_CONTEXT_OPEN_WITH1 + kNumMainMenuCommands; |
| 156 | |
Evan Stade | 6bf35f0 | 2017-09-01 01:11:13 | [diff] [blame] | 157 | OpenWithMenu::HandlerMap handler_map; |
yusukes | a0c66046 | 2016-05-04 17:04:26 | [diff] [blame] | 158 | 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); |
yusukes | 1168eda | 2016-04-27 07:52:08 | [diff] [blame] | 188 | } |
| 189 | |
Evan Stade | 6bf35f0 | 2017-09-01 01:11:13 | [diff] [blame] | 190 | } // namespace arc |