File: open_with_menu.cc

package info (click to toggle)
chromium 138.0.7204.157-1
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 6,071,864 kB
  • sloc: cpp: 34,936,859; ansic: 7,176,967; javascript: 4,110,704; python: 1,419,953; asm: 946,768; xml: 739,967; pascal: 187,324; sh: 89,623; perl: 88,663; objc: 79,944; sql: 50,304; cs: 41,786; fortran: 24,137; makefile: 21,806; php: 13,980; tcl: 13,166; yacc: 8,925; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (183 lines) | stat: -rw-r--r-- 6,506 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/chromeos/arc/open_with_menu.h"

#include <algorithm>

#include "base/strings/string_util.h"
#include "chrome/app/chrome_command_ids.h"
#include "chrome/browser/ash/arc/intent_helper/arc_intent_helper_mojo_ash.h"
#include "chrome/grit/generated_resources.h"
#include "components/renderer_context_menu/render_view_context_menu_proxy.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/context_menu_params.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/models/image_model.h"

namespace arc {

const int OpenWithMenu::kNumMainMenuCommands = 4;
const int OpenWithMenu::kNumSubMenuCommands = 10;

bool OpenWithMenu::SubMenuDelegate::IsCommandIdChecked(int command_id) const {
  return false;
}

bool OpenWithMenu::SubMenuDelegate::IsCommandIdEnabled(int command_id) const {
  return true;
}

void OpenWithMenu::SubMenuDelegate::ExecuteCommand(int command_id,
                                                   int event_flags) {
  parent_->ExecuteCommand(command_id);
}

OpenWithMenu::OpenWithMenu(content::BrowserContext* context,
                           RenderViewContextMenuProxy* proxy)
    : context_(context),
      proxy_(proxy),
      more_apps_label_(
          l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_MORE_APPS)) {}

OpenWithMenu::~OpenWithMenu() = default;

void OpenWithMenu::InitMenu(const content::ContextMenuParams& params) {
  // Enforcing no items are added to the context menu during incognito mode.
  if (context_->IsOffTheRecord())
    return;

  menu_model_ = LinkHandlerModel::Create(
      context_, params.link_url, std::make_unique<ArcIntentHelperMojoAsh>());
  if (!menu_model_)
    return;

  // Add placeholder items.
  std::unique_ptr<ui::SimpleMenuModel> submenu(
      new ui::SimpleMenuModel(&submenu_delegate_));
  AddPlaceholderItems(proxy_, submenu.get());
  submenu_ = std::move(submenu);

  menu_model_->AddObserver(this);
}

bool OpenWithMenu::IsCommandIdSupported(int command_id) {
  return command_id >= IDC_CONTENT_CONTEXT_OPEN_WITH1 &&
         command_id <= IDC_CONTENT_CONTEXT_OPEN_WITH_LAST;
}

bool OpenWithMenu::IsCommandIdChecked(int command_id) {
  return false;
}

bool OpenWithMenu::IsCommandIdEnabled(int command_id) {
  return true;
}

void OpenWithMenu::ExecuteCommand(int command_id) {
  // Note: SubmenuDelegate also calls this method with a command_id for the
  // submenu.
  const auto it = handlers_.find(command_id);
  if (it == handlers_.end())
    return;

  menu_model_->OpenLinkWithHandler(it->second.id);
}

void OpenWithMenu::ModelChanged(const std::vector<LinkHandlerInfo>& handlers) {
  auto result = BuildHandlersMap(handlers);
  handlers_ = std::move(result.first);
  const int submenu_parent_id = result.second;
  for (int command_id = IDC_CONTENT_CONTEXT_OPEN_WITH1;
       command_id <= IDC_CONTENT_CONTEXT_OPEN_WITH_LAST; ++command_id) {
    const auto it = handlers_.find(command_id);
    if (command_id == submenu_parent_id) {
      // Show the submenu parent.
      proxy_->UpdateMenuItem(command_id, /*enabled=*/true, /*hidden=*/false,
                             /*title=*/more_apps_label_);
    } else if (it == handlers_.end()) {
      // Hide the menu or submenu parent.
      proxy_->UpdateMenuItem(command_id, /*enabled=*/false, /*hidden=*/true,
                             /*title=*/std::u16string());
    } else {
      // Update the menu with the new model.
      const std::u16string label = l10n_util::GetStringFUTF16(
          IDS_CONTENT_CONTEXT_OPEN_WITH_APP, it->second.name);
      proxy_->UpdateMenuItem(command_id, /*enabled=*/true, /*hidden=*/false,
                             label);
      if (!it->second.icon.IsEmpty()) {
        proxy_->UpdateMenuIcon(command_id,
                               ui::ImageModel::FromImage(it->second.icon));
      }
    }
  }
}

void OpenWithMenu::AddPlaceholderItemsForTesting(
    RenderViewContextMenuProxy* proxy,
    ui::SimpleMenuModel* submenu) {
  return AddPlaceholderItems(proxy, submenu);
}

std::pair<OpenWithMenu::HandlerMap, int>
OpenWithMenu::BuildHandlersMapForTesting(
    const std::vector<LinkHandlerInfo>& handlers) {
  return BuildHandlersMap(handlers);
}

void OpenWithMenu::AddPlaceholderItems(RenderViewContextMenuProxy* proxy,
                                       ui::SimpleMenuModel* submenu) {
  for (int i = 0; i < kNumSubMenuCommands; ++i) {
    const int command_id =
        IDC_CONTENT_CONTEXT_OPEN_WITH1 + kNumMainMenuCommands + i;
    submenu->AddItem(command_id, /*title=*/std::u16string());
  }
  int command_id;
  for (int i = 0; i < kNumMainMenuCommands - 1; ++i) {
    command_id = IDC_CONTENT_CONTEXT_OPEN_WITH1 + i;
    proxy->AddMenuItem(command_id, /*title=*/std::u16string());
  }
  proxy->AddSubMenu(++command_id, /*label=*/std::u16string(), submenu);
}

std::pair<OpenWithMenu::HandlerMap, int> OpenWithMenu::BuildHandlersMap(
    const std::vector<LinkHandlerInfo>& handlers) {
  const int kInvalidCommandId = -1;
  const int submenu_id_start =
      IDC_CONTENT_CONTEXT_OPEN_WITH1 + kNumMainMenuCommands;

  OpenWithMenu::HandlerMap handler_map;
  int submenu_parent_command_id = kInvalidCommandId;

  const int num_apps = handlers.size();
  size_t handlers_index = 0;
  // We use the last item in the main menu (IDC_CONTENT_CONTEXT_OPEN_WITH1 +
  // kNumMainMenuCommands- 1) as a parent of a submenu, and others as regular
  // menu items.
  if (num_apps < kNumMainMenuCommands) {
    // All apps can be shown with the regular main menu items.
    for (int i = 0; i < num_apps; ++i) {
      handler_map[IDC_CONTENT_CONTEXT_OPEN_WITH1 + i] =
          handlers[handlers_index++];
    }
  } else {
    // Otherwise, use the submenu too. In this case, disable the last item of
    // the regular main menu (hence '-2').
    for (int i = 0; i < kNumMainMenuCommands - 2; ++i) {
      handler_map[IDC_CONTENT_CONTEXT_OPEN_WITH1 + i] =
          handlers[handlers_index++];
    }
    submenu_parent_command_id =
        IDC_CONTENT_CONTEXT_OPEN_WITH1 + kNumMainMenuCommands - 1;
    const int sub_items =
        std::min(num_apps - (kNumMainMenuCommands - 2), kNumSubMenuCommands);
    for (int i = 0; i < sub_items; ++i) {
      handler_map[submenu_id_start + i] = handlers[handlers_index++];
    }
  }

  return std::make_pair(std::move(handler_map), submenu_parent_command_id);
}

}  // namespace arc