blob: 0ae218c0f280df1b4d1aa1138f7ab0428e5a8430 [file] [log] [blame]
// Copyright 2018 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 "ui/views/controls/views_text_services_context_menu.h"
#import <Cocoa/Cocoa.h>
#include "ui/base/cocoa/text_services_context_menu.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/models/simple_menu_model.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/decorated_text.h"
#import "ui/gfx/decorated_text_mac.h"
#include "ui/resources/grit/ui_resources.h"
#include "ui/strings/grit/ui_strings.h"
#include "ui/views/controls/textfield/textfield.h"
#include "ui/views/controls/views_text_services_context_menu_base.h"
#include "ui/views/widget/widget.h"
namespace views {
namespace {
// This class serves as a bridge to TextServicesContextMenu to add and handle
// text service items in the context menu. The items include Speech, Look Up
// and BiDi.
class ViewsTextServicesContextMenuMac
: public ViewsTextServicesContextMenuBase,
public ui::TextServicesContextMenu::Delegate {
public:
ViewsTextServicesContextMenuMac(ui::SimpleMenuModel* menu, Textfield* client)
: ViewsTextServicesContextMenuBase(menu, client),
text_services_menu_(this) {
// Insert the "Look up" item in the first position.
base::string16 text = GetSelectedText();
if (!text.empty()) {
menu->InsertSeparatorAt(0, ui::NORMAL_SEPARATOR);
menu->InsertItemAt(
0, IDS_CONTENT_CONTEXT_LOOK_UP,
l10n_util::GetStringFUTF16(IDS_CONTENT_CONTEXT_LOOK_UP, text));
}
text_services_menu_.AppendToContextMenu(menu);
text_services_menu_.AppendEditableItems(menu);
}
~ViewsTextServicesContextMenuMac() override {}
// ViewsTextServicesContextMenu:
bool SupportsCommand(int command_id) const override {
return text_services_menu_.SupportsCommand(command_id) ||
command_id == IDS_CONTENT_CONTEXT_LOOK_UP ||
ViewsTextServicesContextMenuBase::SupportsCommand(command_id);
}
bool IsCommandIdEnabled(int command_id) const override {
if (text_services_menu_.SupportsCommand(command_id))
return text_services_menu_.IsCommandIdEnabled(command_id);
switch (command_id) {
case IDS_CONTENT_CONTEXT_LOOK_UP:
return true;
default:
return ViewsTextServicesContextMenuBase::IsCommandIdEnabled(command_id);
}
}
void ExecuteCommand(int command_id) override {
switch (command_id) {
case IDS_CONTENT_CONTEXT_LOOK_UP:
LookUpInDictionary();
break;
default:
ViewsTextServicesContextMenuBase::ExecuteCommand(command_id);
break;
}
}
// TextServicesContextMenu::Delegate:
base::string16 GetSelectedText() const override {
if (client()->GetTextInputType() == ui::TEXT_INPUT_TYPE_PASSWORD)
return base::string16();
return client()->GetSelectedText();
}
bool IsTextDirectionEnabled(
base::i18n::TextDirection direction) const override {
return direction != base::i18n::UNKNOWN_DIRECTION;
}
bool IsTextDirectionChecked(
base::i18n::TextDirection direction) const override {
return direction != base::i18n::UNKNOWN_DIRECTION &&
client()->GetTextDirection() == direction;
}
void UpdateTextDirection(base::i18n::TextDirection direction) override {
DCHECK_NE(direction, base::i18n::UNKNOWN_DIRECTION);
base::i18n::TextDirection text_direction =
direction == base::i18n::LEFT_TO_RIGHT ? base::i18n::LEFT_TO_RIGHT
: base::i18n::RIGHT_TO_LEFT;
client()->ChangeTextDirectionAndLayoutAlignment(text_direction);
}
private:
// Handler for the "Look Up" menu item.
void LookUpInDictionary() {
gfx::Point baseline_point;
gfx::DecoratedText text;
if (client()->GetWordLookupDataFromSelection(&text, &baseline_point)) {
Widget* widget = client()->GetWidget();
NSView* view = widget->GetNativeView().GetNativeNSView();
views::View::ConvertPointToTarget(client(), widget->GetRootView(),
&baseline_point);
NSPoint lookup_point = NSMakePoint(
baseline_point.x(), NSHeight([view frame]) - baseline_point.y());
[view showDefinitionForAttributedString:
gfx::GetAttributedStringFromDecoratedText(text)
atPoint:lookup_point];
}
}
// Appends and handles the text service menu.
ui::TextServicesContextMenu text_services_menu_;
DISALLOW_COPY_AND_ASSIGN(ViewsTextServicesContextMenuMac);
};
} // namespace
// static
std::unique_ptr<ViewsTextServicesContextMenu>
ViewsTextServicesContextMenu::Create(ui::SimpleMenuModel* menu,
Textfield* client) {
return std::make_unique<ViewsTextServicesContextMenuMac>(menu, client);
}
// static
bool ViewsTextServicesContextMenu::IsTextDirectionCheckedForTesting(
ViewsTextServicesContextMenu* menu,
base::i18n::TextDirection direction) {
return static_cast<views::ViewsTextServicesContextMenuMac*>(menu)
->IsTextDirectionChecked(direction);
}
} // namespace views