Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(233)

Side by Side Diff: chrome/browser/renderer_context_menu/open_with_menu_factory_ash.cc

Issue 1760773004: Add "Open with <ARC-app-name>" items to the context menu (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Address dcheng's comment Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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
5 #include "chrome/browser/renderer_context_menu/open_with_menu_factory.h"
6
7 #include <memory>
8 #include <unordered_map>
9 #include <utility>
10 #include <vector>
11
12 #include "ash/link_handler_model.h"
13 #include "ash/link_handler_model_factory.h"
14 #include "ash/shell.h"
15 #include "base/strings/string_util.h"
16 #include "base/strings/utf_string_conversions.h"
17 #include "chrome/app/chrome_command_ids.h"
18 #include "chrome/grit/generated_resources.h"
19 #include "components/renderer_context_menu/render_view_context_menu_observer.h"
20 #include "components/renderer_context_menu/render_view_context_menu_proxy.h"
21 #include "content/public/common/context_menu_params.h"
22 #include "ui/base/l10n/l10n_util.h"
23 #include "ui/base/models/simple_menu_model.h"
24
25 namespace {
26
27 using HandlerMap = std::unordered_map<int, ash::LinkHandlerInfo>;
28
29 // An observer class which populates the "Open with <app>" menu items either
30 // synchronously or asynchronously.
31 class OpenWithMenuObserver : public RenderViewContextMenuObserver,
32 public ash::LinkHandlerModel::Observer {
33 public:
34 class SubMenuDelegate : public ui::SimpleMenuModel::Delegate {
35 public:
36 explicit SubMenuDelegate(OpenWithMenuObserver* parent) : parent_(parent) {}
37 ~SubMenuDelegate() override {}
38
39 bool IsCommandIdChecked(int command_id) const override { return false; }
40 bool IsCommandIdEnabled(int command_id) const override { return true; }
41
42 bool GetAcceleratorForCommandId(int command_id,
43 ui::Accelerator* accelerator) override {
44 return false;
45 }
46
47 void ExecuteCommand(int command_id, int event_flags) override {
48 parent_->ExecuteCommand(command_id);
49 }
50
51 private:
52 OpenWithMenuObserver* const parent_;
53
54 DISALLOW_COPY_AND_ASSIGN(SubMenuDelegate);
55 };
56
57 explicit OpenWithMenuObserver(RenderViewContextMenuProxy* proxy)
58 : proxy_(proxy),
59 submenu_delegate_(this),
60 more_apps_label_(
61 l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_MORE_APPS)) {}
62
63 ~OpenWithMenuObserver() override {}
64
65 // RenderViewContextMenuObserver overrides:
66 void InitMenu(const content::ContextMenuParams& params) override {
67 if (!ash::Shell::HasInstance())
68 return;
69 ash::LinkHandlerModelFactory* factory =
70 ash::Shell::GetInstance()->link_handler_model_factory();
71 if (!factory)
72 return;
73
74 link_url_ = params.link_url;
75 menu_model_ = factory->CreateModel(link_url_);
76 if (!menu_model_)
77 return;
78
79 // Add placeholder items.
80 std::unique_ptr<ui::SimpleMenuModel> submenu(
81 new ui::SimpleMenuModel(&submenu_delegate_));
82 for (int i = 0; i < kNumSubMenuCommands; ++i) {
83 const int command_id =
84 IDC_CONTENT_CONTEXT_OPEN_WITH1 + kNumMainMenuCommands + i;
85 submenu->AddItem(command_id, base::EmptyString16());
86 }
87 submenu_ = std::move(submenu);
88
89 int command_id;
90 for (int i = 0; i < kNumMainMenuCommands - 1; ++i) {
91 command_id = IDC_CONTENT_CONTEXT_OPEN_WITH1 + i;
92 proxy_->AddMenuItem(command_id, base::EmptyString16());
93 }
94 proxy_->AddSubMenu(++command_id, more_apps_label_, submenu_.get());
95
96 menu_model_->AddObserver(this);
97 }
98
99 bool IsCommandIdSupported(int command_id) override {
100 return command_id >= IDC_CONTENT_CONTEXT_OPEN_WITH1 &&
101 command_id <= IDC_CONTENT_CONTEXT_OPEN_WITH_LAST;
102 }
103
104 bool IsCommandIdChecked(int command_id) override { return false; }
105 bool IsCommandIdEnabled(int command_id) override { return true; }
106
107 void ExecuteCommand(int command_id) override {
108 // Note: SubmenuDelegate also calls this method with a command_id for the
109 // submenu.
110 const auto it = handlers_.find(command_id);
111 if (it == handlers_.end())
112 return;
113 menu_model_->OpenLinkWithHandler(link_url_, it->second.id);
114 }
115
116 void OnMenuCancel() override {}
117
118 // ash::OpenWithItems::Delegate overrides:
119 void ModelChanged(
120 const std::vector<ash::LinkHandlerInfo>& handlers) override {
121 auto result = BuildHandlersMap(handlers);
122 handlers_ = std::move(result.first);
123 const int submenu_parent_id = result.second;
124 for (int command_id = IDC_CONTENT_CONTEXT_OPEN_WITH1;
125 command_id <= IDC_CONTENT_CONTEXT_OPEN_WITH_LAST; ++command_id) {
126 const auto it = handlers_.find(command_id);
127 if (command_id == submenu_parent_id) {
128 // Show the submenu parent.
129 proxy_->UpdateMenuItem(command_id, true, false, more_apps_label_);
130 } else if (it == handlers_.end()) {
131 // Hide the menu or submenu parent.
132 proxy_->UpdateMenuItem(command_id, false, true, base::EmptyString16());
133 } else {
134 // Update the menu with the new model.
135 const base::string16 label =
136 l10n_util::GetStringFUTF16(IDS_CONTENT_CONTEXT_OPEN_WITH_APP,
137 base::UTF8ToUTF16(it->second.name));
138 proxy_->UpdateMenuItem(command_id, true, false, label);
139 }
140 }
141 }
142
143 static std::pair<HandlerMap, int> BuildHandlersMapForTesting(
144 const std::vector<ash::LinkHandlerInfo>& handlers) {
145 return BuildHandlersMap(handlers);
146 }
147
148 private:
149 // Converts |handlers| into HandlerMap which is a map from a command ID to a
150 // LinkHandlerInfo and returns the map. Also returns a command id for the
151 // parent of the submenu. When the submenu is not needed, the function
152 // returns |kInvalidCommandId|.
153 static std::pair<HandlerMap, int> BuildHandlersMap(
154 const std::vector<ash::LinkHandlerInfo>& handlers) {
155 const int kInvalidCommandId = -1;
156 const int submenu_id_start =
157 IDC_CONTENT_CONTEXT_OPEN_WITH1 + kNumMainMenuCommands;
158
159 HandlerMap handler_map;
160 int submenu_parent_command_id = kInvalidCommandId;
161
162 const int num_apps = handlers.size();
163 size_t handlers_index = 0;
164 // We use the last item in the main menu (IDC_CONTENT_CONTEXT_OPEN_WITH1 +
165 // kNumMainMenuCommands- 1) as a parent of a submenu, and others as regular
166 // menu items.
167 if (num_apps < kNumMainMenuCommands) {
168 // All apps can be shown with the regular main menu items.
169 for (int i = 0; i < num_apps; ++i) {
170 handler_map[IDC_CONTENT_CONTEXT_OPEN_WITH1 + i] =
171 handlers[handlers_index++];
172 }
173 } else {
174 // Otherwise, use the submenu too. In this case, disable the last item of
175 // the regular main menu (hence '-2').
176 for (int i = 0; i < kNumMainMenuCommands - 2; ++i) {
177 handler_map[IDC_CONTENT_CONTEXT_OPEN_WITH1 + i] =
178 handlers[handlers_index++];
179 }
180 submenu_parent_command_id =
181 IDC_CONTENT_CONTEXT_OPEN_WITH1 + kNumMainMenuCommands - 1;
182 const int sub_items =
183 std::min(num_apps - (kNumMainMenuCommands - 2), kNumSubMenuCommands);
184 for (int i = 0; i < sub_items; ++i) {
185 handler_map[submenu_id_start + i] = handlers[handlers_index++];
186 }
187 }
188
189 return std::make_pair(std::move(handler_map), submenu_parent_command_id);
190 }
191
192 static const int kNumMainMenuCommands;
193 static const int kNumSubMenuCommands;
194
195 RenderViewContextMenuProxy* const proxy_;
196 SubMenuDelegate submenu_delegate_;
197 const base::string16 more_apps_label_;
198 GURL link_url_;
199
200 // A menu model received from Ash side.
201 std::unique_ptr<ash::LinkHandlerModel> menu_model_;
202 HandlerMap handlers_;
203 // A submenu passed to Chrome side.
204 std::unique_ptr<ui::MenuModel> submenu_;
205
206 DISALLOW_COPY_AND_ASSIGN(OpenWithMenuObserver);
207 };
208
209 const int OpenWithMenuObserver::kNumMainMenuCommands = 4;
210 const int OpenWithMenuObserver::kNumSubMenuCommands = 10;
211
212 } // namespace
213
214 std::pair<HandlerMap, int> BuildHandlersMapForTesting(
215 const std::vector<ash::LinkHandlerInfo>& handlers) {
216 return OpenWithMenuObserver::BuildHandlersMapForTesting(handlers);
217 }
218
219 RenderViewContextMenuObserver* OpenWithMenuFactory::CreateMenu(
220 RenderViewContextMenuProxy* proxy) {
221 return new OpenWithMenuObserver(proxy);
222 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698