533 lines
15 KiB
C++
533 lines
15 KiB
C++
// Copyright (c) 2021 The Chromium Embedded Framework Authors.
|
|
// Portions copyright (c) 2012 The Chromium Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#include "libcef/browser/simple_menu_model_impl.h"
|
|
|
|
#include <vector>
|
|
|
|
#include "libcef/browser/thread_util.h"
|
|
#include "libcef/common/task_runner_impl.h"
|
|
|
|
namespace {
|
|
|
|
// Value based on the documentation on SimpleMenuModel::GetIndexOfCommandId().
|
|
const int kInvalidIndex = -1;
|
|
const int kInvalidCommandId = -1;
|
|
const int kInvalidGroupId = -1;
|
|
|
|
cef_menu_item_type_t GetCefItemType(ui::MenuModel::ItemType type) {
|
|
switch (type) {
|
|
case ui::MenuModel::TYPE_COMMAND:
|
|
return MENUITEMTYPE_COMMAND;
|
|
case ui::MenuModel::TYPE_CHECK:
|
|
return MENUITEMTYPE_CHECK;
|
|
case ui::MenuModel::TYPE_RADIO:
|
|
return MENUITEMTYPE_RADIO;
|
|
case ui::MenuModel::TYPE_SEPARATOR:
|
|
return MENUITEMTYPE_SEPARATOR;
|
|
case ui::MenuModel::TYPE_SUBMENU:
|
|
return MENUITEMTYPE_SUBMENU;
|
|
default:
|
|
return MENUITEMTYPE_NONE;
|
|
}
|
|
}
|
|
|
|
} // namespace
|
|
|
|
CefSimpleMenuModelImpl::CefSimpleMenuModelImpl(
|
|
ui::SimpleMenuModel* model,
|
|
ui::SimpleMenuModel::Delegate* delegate,
|
|
StateDelegate* state_delegate,
|
|
bool is_owned,
|
|
bool is_submenu)
|
|
: supported_thread_id_(base::PlatformThread::CurrentId()),
|
|
model_(model),
|
|
delegate_(delegate),
|
|
state_delegate_(state_delegate),
|
|
is_owned_(is_owned),
|
|
is_submenu_(is_submenu) {
|
|
DCHECK(model_);
|
|
DCHECK(delegate_);
|
|
DCHECK(state_delegate_);
|
|
}
|
|
|
|
CefSimpleMenuModelImpl::~CefSimpleMenuModelImpl() {
|
|
// Detach() must be called before object destruction.
|
|
DCHECK(!model_);
|
|
DCHECK(submenumap_.empty());
|
|
}
|
|
|
|
void CefSimpleMenuModelImpl::Detach() {
|
|
DCHECK(VerifyContext());
|
|
|
|
if (!submenumap_.empty()) {
|
|
auto it = submenumap_.begin();
|
|
for (; it != submenumap_.end(); ++it) {
|
|
it->second->Detach();
|
|
}
|
|
submenumap_.clear();
|
|
}
|
|
|
|
if (is_owned_)
|
|
delete model_;
|
|
model_ = nullptr;
|
|
}
|
|
|
|
bool CefSimpleMenuModelImpl::IsSubMenu() {
|
|
if (!VerifyContext())
|
|
return false;
|
|
return is_submenu_;
|
|
}
|
|
|
|
bool CefSimpleMenuModelImpl::Clear() {
|
|
if (!VerifyContext())
|
|
return false;
|
|
|
|
model_->Clear();
|
|
return true;
|
|
}
|
|
|
|
size_t CefSimpleMenuModelImpl::GetCount() {
|
|
if (!VerifyContext())
|
|
return 0;
|
|
|
|
return model_->GetItemCount();
|
|
}
|
|
|
|
bool CefSimpleMenuModelImpl::AddSeparator() {
|
|
if (!VerifyContext())
|
|
return false;
|
|
|
|
model_->AddSeparator(ui::NORMAL_SEPARATOR);
|
|
return true;
|
|
}
|
|
|
|
bool CefSimpleMenuModelImpl::AddItem(int command_id, const CefString& label) {
|
|
if (!VerifyContext())
|
|
return false;
|
|
|
|
model_->AddItem(command_id, label);
|
|
return true;
|
|
}
|
|
|
|
bool CefSimpleMenuModelImpl::AddCheckItem(int command_id,
|
|
const CefString& label) {
|
|
if (!VerifyContext())
|
|
return false;
|
|
|
|
model_->AddCheckItem(command_id, label);
|
|
return true;
|
|
}
|
|
|
|
bool CefSimpleMenuModelImpl::AddRadioItem(int command_id,
|
|
const CefString& label,
|
|
int group_id) {
|
|
if (!VerifyContext())
|
|
return false;
|
|
|
|
model_->AddRadioItem(command_id, label, group_id);
|
|
return true;
|
|
}
|
|
|
|
CefRefPtr<CefMenuModel> CefSimpleMenuModelImpl::AddSubMenu(
|
|
int command_id,
|
|
const CefString& label) {
|
|
if (!VerifyContext())
|
|
return nullptr;
|
|
|
|
auto new_menu = CreateNewSubMenu(nullptr);
|
|
model_->AddSubMenu(command_id, label, new_menu->model());
|
|
return new_menu;
|
|
}
|
|
|
|
bool CefSimpleMenuModelImpl::InsertSeparatorAt(size_t index) {
|
|
if (!VerifyContext())
|
|
return false;
|
|
|
|
model_->InsertSeparatorAt(index, ui::NORMAL_SEPARATOR);
|
|
return true;
|
|
}
|
|
|
|
bool CefSimpleMenuModelImpl::InsertItemAt(size_t index,
|
|
int command_id,
|
|
const CefString& label) {
|
|
if (!VerifyContext() || !ValidIndex(index))
|
|
return false;
|
|
|
|
model_->InsertItemAt(index, command_id, label);
|
|
return true;
|
|
}
|
|
|
|
bool CefSimpleMenuModelImpl::InsertCheckItemAt(size_t index,
|
|
int command_id,
|
|
const CefString& label) {
|
|
if (!VerifyContext() || !ValidIndex(index))
|
|
return false;
|
|
|
|
model_->InsertCheckItemAt(index, command_id, label);
|
|
return true;
|
|
}
|
|
|
|
bool CefSimpleMenuModelImpl::InsertRadioItemAt(size_t index,
|
|
int command_id,
|
|
const CefString& label,
|
|
int group_id) {
|
|
if (!VerifyContext() || !ValidIndex(index))
|
|
return false;
|
|
|
|
model_->InsertRadioItemAt(index, command_id, label, group_id);
|
|
return true;
|
|
}
|
|
|
|
CefRefPtr<CefMenuModel> CefSimpleMenuModelImpl::InsertSubMenuAt(
|
|
size_t index,
|
|
int command_id,
|
|
const CefString& label) {
|
|
if (!VerifyContext() || !ValidIndex(index))
|
|
return nullptr;
|
|
|
|
auto new_menu = CreateNewSubMenu(nullptr);
|
|
model_->InsertSubMenuAt(index, command_id, label, new_menu->model());
|
|
return new_menu;
|
|
}
|
|
|
|
bool CefSimpleMenuModelImpl::Remove(int command_id) {
|
|
return RemoveAt(GetIndexOf(command_id));
|
|
}
|
|
|
|
bool CefSimpleMenuModelImpl::RemoveAt(size_t index) {
|
|
if (!VerifyContext() || !ValidIndex(index))
|
|
return false;
|
|
|
|
auto* sub_menu =
|
|
static_cast<ui::SimpleMenuModel*>(model_->GetSubmenuModelAt(index));
|
|
if (sub_menu) {
|
|
auto it = submenumap_.find(sub_menu);
|
|
if (it != submenumap_.end()) {
|
|
it->second->Detach();
|
|
submenumap_.erase(it);
|
|
}
|
|
}
|
|
|
|
model_->RemoveItemAt(index);
|
|
return true;
|
|
}
|
|
|
|
int CefSimpleMenuModelImpl::GetIndexOf(int command_id) {
|
|
if (!VerifyContext())
|
|
return kInvalidIndex;
|
|
|
|
auto index = model_->GetIndexOfCommandId(command_id);
|
|
if (index.has_value())
|
|
return static_cast<int>(*index);
|
|
return -1;
|
|
}
|
|
|
|
int CefSimpleMenuModelImpl::GetCommandIdAt(size_t index) {
|
|
if (!VerifyContext() || !ValidIndex(index))
|
|
return kInvalidCommandId;
|
|
|
|
return model_->GetCommandIdAt(index);
|
|
}
|
|
|
|
bool CefSimpleMenuModelImpl::SetCommandIdAt(size_t index, int command_id) {
|
|
NOTIMPLEMENTED();
|
|
return false;
|
|
}
|
|
|
|
CefString CefSimpleMenuModelImpl::GetLabel(int command_id) {
|
|
return GetLabelAt(GetIndexOf(command_id));
|
|
}
|
|
|
|
CefString CefSimpleMenuModelImpl::GetLabelAt(size_t index) {
|
|
if (!VerifyContext() || !ValidIndex(index))
|
|
return CefString();
|
|
|
|
return model_->GetLabelAt(index);
|
|
}
|
|
|
|
bool CefSimpleMenuModelImpl::SetLabel(int command_id, const CefString& label) {
|
|
return SetLabelAt(GetIndexOf(command_id), label);
|
|
}
|
|
|
|
bool CefSimpleMenuModelImpl::SetLabelAt(size_t index, const CefString& label) {
|
|
if (!VerifyContext() || !ValidIndex(index))
|
|
return false;
|
|
|
|
model_->SetLabel(index, label);
|
|
return true;
|
|
}
|
|
|
|
CefSimpleMenuModelImpl::MenuItemType CefSimpleMenuModelImpl::GetType(
|
|
int command_id) {
|
|
return GetTypeAt(GetIndexOf(command_id));
|
|
}
|
|
|
|
CefSimpleMenuModelImpl::MenuItemType CefSimpleMenuModelImpl::GetTypeAt(
|
|
size_t index) {
|
|
if (!VerifyContext() || !ValidIndex(index))
|
|
return MENUITEMTYPE_NONE;
|
|
|
|
return GetCefItemType(model_->GetTypeAt(index));
|
|
}
|
|
|
|
int CefSimpleMenuModelImpl::GetGroupId(int command_id) {
|
|
return GetGroupIdAt(GetIndexOf(command_id));
|
|
}
|
|
|
|
int CefSimpleMenuModelImpl::GetGroupIdAt(size_t index) {
|
|
if (!VerifyContext() || !ValidIndex(index))
|
|
return kInvalidGroupId;
|
|
|
|
return model_->GetGroupIdAt(index);
|
|
}
|
|
|
|
bool CefSimpleMenuModelImpl::SetGroupId(int command_id, int group_id) {
|
|
return SetGroupIdAt(GetIndexOf(command_id), group_id);
|
|
}
|
|
|
|
bool CefSimpleMenuModelImpl::SetGroupIdAt(size_t index, int group_id) {
|
|
NOTIMPLEMENTED();
|
|
return false;
|
|
}
|
|
|
|
CefRefPtr<CefMenuModel> CefSimpleMenuModelImpl::GetSubMenu(int command_id) {
|
|
return GetSubMenuAt(GetIndexOf(command_id));
|
|
}
|
|
|
|
CefRefPtr<CefMenuModel> CefSimpleMenuModelImpl::GetSubMenuAt(size_t index) {
|
|
if (!VerifyContext() || !ValidIndex(index))
|
|
return nullptr;
|
|
|
|
auto* sub_model =
|
|
static_cast<ui::SimpleMenuModel*>(model_->GetSubmenuModelAt(index));
|
|
auto it = submenumap_.find(sub_model);
|
|
if (it != submenumap_.end())
|
|
return it->second;
|
|
return CreateNewSubMenu(sub_model);
|
|
}
|
|
|
|
bool CefSimpleMenuModelImpl::IsVisible(int command_id) {
|
|
return IsVisibleAt(GetIndexOf(command_id));
|
|
}
|
|
|
|
bool CefSimpleMenuModelImpl::IsVisibleAt(size_t index) {
|
|
if (!VerifyContext() || !ValidIndex(index))
|
|
return false;
|
|
|
|
return model_->IsVisibleAt(index);
|
|
}
|
|
|
|
bool CefSimpleMenuModelImpl::SetVisible(int command_id, bool visible) {
|
|
return SetVisibleAt(GetIndexOf(command_id), visible);
|
|
}
|
|
|
|
bool CefSimpleMenuModelImpl::SetVisibleAt(size_t index, bool visible) {
|
|
if (!VerifyContext() || !ValidIndex(index))
|
|
return false;
|
|
|
|
model_->SetVisibleAt(index, visible);
|
|
return true;
|
|
}
|
|
|
|
bool CefSimpleMenuModelImpl::IsEnabled(int command_id) {
|
|
return IsEnabledAt(GetIndexOf(command_id));
|
|
}
|
|
|
|
bool CefSimpleMenuModelImpl::IsEnabledAt(size_t index) {
|
|
if (!VerifyContext() || !ValidIndex(index))
|
|
return false;
|
|
|
|
return model_->IsEnabledAt(index);
|
|
}
|
|
|
|
bool CefSimpleMenuModelImpl::SetEnabled(int command_id, bool enabled) {
|
|
return SetEnabledAt(GetIndexOf(command_id), enabled);
|
|
}
|
|
|
|
bool CefSimpleMenuModelImpl::SetEnabledAt(size_t index, bool enabled) {
|
|
if (!VerifyContext() || !ValidIndex(index))
|
|
return false;
|
|
|
|
model_->SetEnabledAt(index, enabled);
|
|
return true;
|
|
}
|
|
|
|
bool CefSimpleMenuModelImpl::IsChecked(int command_id) {
|
|
return IsCheckedAt(GetIndexOf(command_id));
|
|
}
|
|
|
|
bool CefSimpleMenuModelImpl::IsCheckedAt(size_t index) {
|
|
if (!VerifyContext() || !ValidIndex(index))
|
|
return false;
|
|
|
|
return model_->IsItemCheckedAt(index);
|
|
}
|
|
|
|
bool CefSimpleMenuModelImpl::SetChecked(int command_id, bool checked) {
|
|
if (!VerifyContext() || command_id == kInvalidIndex)
|
|
return false;
|
|
|
|
state_delegate_->SetChecked(command_id, checked);
|
|
return true;
|
|
}
|
|
|
|
bool CefSimpleMenuModelImpl::SetCheckedAt(size_t index, bool checked) {
|
|
return SetChecked(GetCommandIdAt(index), checked);
|
|
}
|
|
|
|
bool CefSimpleMenuModelImpl::HasAccelerator(int command_id) {
|
|
return HasAcceleratorAt(GetIndexOf(command_id));
|
|
}
|
|
|
|
bool CefSimpleMenuModelImpl::HasAcceleratorAt(size_t index) {
|
|
if (!VerifyContext() || !ValidIndex(index))
|
|
return false;
|
|
|
|
ui::Accelerator accelerator;
|
|
return model_->GetAcceleratorAt(index, &accelerator);
|
|
}
|
|
|
|
bool CefSimpleMenuModelImpl::SetAccelerator(int command_id,
|
|
int key_code,
|
|
bool shift_pressed,
|
|
bool ctrl_pressed,
|
|
bool alt_pressed) {
|
|
if (!VerifyContext() || command_id == kInvalidIndex)
|
|
return false;
|
|
|
|
int modifiers = 0;
|
|
if (shift_pressed)
|
|
modifiers |= ui::EF_SHIFT_DOWN;
|
|
if (ctrl_pressed)
|
|
modifiers |= ui::EF_CONTROL_DOWN;
|
|
if (alt_pressed)
|
|
modifiers |= ui::EF_ALT_DOWN;
|
|
|
|
state_delegate_->SetAccelerator(
|
|
command_id,
|
|
ui::Accelerator(static_cast<ui::KeyboardCode>(key_code), modifiers));
|
|
return true;
|
|
}
|
|
|
|
bool CefSimpleMenuModelImpl::SetAcceleratorAt(size_t index,
|
|
int key_code,
|
|
bool shift_pressed,
|
|
bool ctrl_pressed,
|
|
bool alt_pressed) {
|
|
return SetAccelerator(GetCommandIdAt(index), key_code, shift_pressed,
|
|
ctrl_pressed, alt_pressed);
|
|
}
|
|
|
|
bool CefSimpleMenuModelImpl::RemoveAccelerator(int command_id) {
|
|
if (!VerifyContext() || command_id == kInvalidIndex)
|
|
return false;
|
|
state_delegate_->SetAccelerator(command_id, absl::nullopt);
|
|
return true;
|
|
}
|
|
|
|
bool CefSimpleMenuModelImpl::RemoveAcceleratorAt(size_t index) {
|
|
return RemoveAccelerator(GetCommandIdAt(index));
|
|
}
|
|
|
|
bool CefSimpleMenuModelImpl::GetAccelerator(int command_id,
|
|
int& key_code,
|
|
bool& shift_pressed,
|
|
bool& ctrl_pressed,
|
|
bool& alt_pressed) {
|
|
return GetAcceleratorAt(GetIndexOf(command_id), key_code, shift_pressed,
|
|
ctrl_pressed, alt_pressed);
|
|
}
|
|
|
|
bool CefSimpleMenuModelImpl::GetAcceleratorAt(size_t index,
|
|
int& key_code,
|
|
bool& shift_pressed,
|
|
bool& ctrl_pressed,
|
|
bool& alt_pressed) {
|
|
if (!VerifyContext() || !ValidIndex(index))
|
|
return false;
|
|
|
|
ui::Accelerator accel;
|
|
if (model_->GetAcceleratorAt(index, &accel)) {
|
|
key_code = accel.key_code();
|
|
shift_pressed = accel.modifiers() & ui::EF_SHIFT_DOWN;
|
|
ctrl_pressed = accel.modifiers() & ui::EF_CONTROL_DOWN;
|
|
alt_pressed = accel.modifiers() & ui::EF_ALT_DOWN;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool CefSimpleMenuModelImpl::SetColor(int command_id,
|
|
cef_menu_color_type_t color_type,
|
|
cef_color_t color) {
|
|
NOTIMPLEMENTED();
|
|
return false;
|
|
}
|
|
|
|
bool CefSimpleMenuModelImpl::SetColorAt(int index,
|
|
cef_menu_color_type_t color_type,
|
|
cef_color_t color) {
|
|
NOTIMPLEMENTED();
|
|
return false;
|
|
}
|
|
|
|
bool CefSimpleMenuModelImpl::GetColor(int command_id,
|
|
cef_menu_color_type_t color_type,
|
|
cef_color_t& color) {
|
|
NOTIMPLEMENTED();
|
|
return false;
|
|
}
|
|
|
|
bool CefSimpleMenuModelImpl::GetColorAt(int index,
|
|
cef_menu_color_type_t color_type,
|
|
cef_color_t& color) {
|
|
NOTIMPLEMENTED();
|
|
return false;
|
|
}
|
|
|
|
bool CefSimpleMenuModelImpl::SetFontList(int command_id,
|
|
const CefString& font_list) {
|
|
NOTIMPLEMENTED();
|
|
return false;
|
|
}
|
|
|
|
bool CefSimpleMenuModelImpl::SetFontListAt(int index,
|
|
const CefString& font_list) {
|
|
NOTIMPLEMENTED();
|
|
return false;
|
|
}
|
|
|
|
bool CefSimpleMenuModelImpl::VerifyContext() {
|
|
if (base::PlatformThread::CurrentId() != supported_thread_id_) {
|
|
// This object should only be accessed from the thread that created it.
|
|
NOTREACHED();
|
|
return false;
|
|
}
|
|
|
|
if (!model_)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool CefSimpleMenuModelImpl::ValidIndex(size_t index) {
|
|
return index < model_->GetItemCount();
|
|
}
|
|
|
|
CefRefPtr<CefSimpleMenuModelImpl> CefSimpleMenuModelImpl::CreateNewSubMenu(
|
|
ui::SimpleMenuModel* model) {
|
|
bool is_owned = false;
|
|
if (!model) {
|
|
model = new ui::SimpleMenuModel(delegate_);
|
|
is_owned = true;
|
|
}
|
|
|
|
CefRefPtr<CefSimpleMenuModelImpl> new_impl = new CefSimpleMenuModelImpl(
|
|
model, delegate_, state_delegate_, is_owned, /*is_submodel=*/true);
|
|
submenumap_.insert(std::make_pair(model, new_impl));
|
|
return new_impl;
|
|
}
|