blob: 94ec4e1b1e2ee019a418049bb395f6288ffcc1b2 [file] [log] [blame]
// Copyright 2017 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/ui/views/tabs/new_tab_button.h"
#include <memory>
#include <string>
#include "base/metrics/user_metrics.h"
#include "base/strings/string_number_conversions.h"
#include "chrome/app/chrome_command_ids.h"
#include "chrome/browser/ui/browser_commands.h"
#include "chrome/browser/ui/browser_element_identifiers.h"
#include "chrome/browser/ui/browser_window/public/browser_window_features.h"
#include "chrome/browser/ui/color/chrome_color_id.h"
#include "chrome/browser/ui/tabs/split_tab_metrics.h"
#include "chrome/browser/ui/tabs/tab_group_model.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/browser/ui/ui_features.h"
#include "chrome/browser/ui/views/tabs/tab_strip.h"
#include "chrome/grit/generated_resources.h"
#include "components/tabs/public/tab_group.h"
#include "ui/base/interaction/element_identifier.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/views/view_class_properties.h"
DEFINE_CLASS_ELEMENT_IDENTIFIER_VALUE(NewTabButtonMenuModel, kNewTab);
DEFINE_CLASS_ELEMENT_IDENTIFIER_VALUE(NewTabButtonMenuModel, kNewTabInGroup);
DEFINE_CLASS_ELEMENT_IDENTIFIER_VALUE(NewTabButtonMenuModel, kNewSplitView);
DEFINE_CLASS_ELEMENT_IDENTIFIER_VALUE(NewTabButtonMenuModel,
kCreateNewTabGroup);
NewTabButton::NewTabButton(TabStripController* tab_strip,
PressedCallback callback,
const gfx::VectorIcon& icon,
Edge fixed_flat_edge,
Edge animated_flat_edge,
BrowserWindowInterface* browser)
: TabStripControlButton(tab_strip,
std::move(callback),
icon,
fixed_flat_edge,
animated_flat_edge),
browser_(browser) {
set_context_menu_controller(this);
SetProperty(views::kElementIdentifierKey, kNewTabButtonElementId);
}
NewTabButton::~NewTabButton() = default;
void NewTabButton::ShowContextMenuForViewImpl(
View* source,
const gfx::Point& point,
ui::mojom::MenuSourceType source_type) {
if (features::IsTabGroupMenuMoreEntryPointsEnabled()) {
context_menu_model_ = std::make_unique<NewTabButtonMenuModel>(browser_);
int32_t menu_runner_flags =
views::MenuRunner::HAS_MNEMONICS | views::MenuRunner::CONTEXT_MENU;
context_menu_runner_ = std::make_unique<views::MenuRunner>(
context_menu_model_.get(), menu_runner_flags);
context_menu_runner_->RunMenuAt(
source->GetWidget(), nullptr, gfx::Rect(point, gfx::Size()),
views::MenuAnchorPosition::kTopLeft, source_type);
}
}
NewTabButtonMenuModel::NewTabButtonMenuModel(BrowserWindowInterface* browser)
: ui::SimpleMenuModel(this), browser_(browser) {
CHECK(browser_);
// Build the menu.
AddItemWithStringId(IDC_NEW_TAB, IDS_NEW_TAB);
SetElementIdentifierAt(GetIndexOfCommandId(IDC_NEW_TAB).value(), kNewTab);
AddNewTabInGroupItem();
AddSeparator(ui::NORMAL_SEPARATOR);
AddItemWithStringId(IDC_CREATE_NEW_TAB_GROUP, IDS_NEW_TAB_GROUP);
SetElementIdentifierAt(GetIndexOfCommandId(IDC_CREATE_NEW_TAB_GROUP).value(),
kCreateNewTabGroup);
if (base::FeatureList::IsEnabled(features::kSideBySide)) {
AddSeparator(ui::NORMAL_SEPARATOR);
AddNewSplitTabItem();
}
}
NewTabButtonMenuModel::~NewTabButtonMenuModel() = default;
void NewTabButtonMenuModel::ExecuteCommand(int command_id, int event_flags) {
CHECK(browser_);
switch (command_id) {
case IDC_NEW_TAB:
base::RecordAction(
base::UserMetricsAction("NewTabButton_ContextMenu_NewTab"));
break;
case IDC_ADD_NEW_TAB_RECENT_GROUP:
base::RecordAction(
base::UserMetricsAction("NewTabButton_ContextMenu_NewTabInGroup"));
break;
case IDC_CREATE_NEW_TAB_GROUP:
base::RecordAction(
base::UserMetricsAction("NewTabButton_ContextMenu_NewGroup"));
break;
case IDC_NEW_SPLIT_TAB:
base::RecordAction(
base::UserMetricsAction("NewTabButton_ContextMenu_NewSplitTab"));
break;
}
if (command_id == IDC_NEW_SPLIT_TAB) {
// Handle this command directly because we want to specify the source
// as the new tab button.
chrome::NewSplitTab(browser_,
split_tabs::SplitTabCreatedSource::kNewTabButton);
return;
}
chrome::ExecuteCommand(browser_, command_id);
}
bool NewTabButtonMenuModel::GetAcceleratorForCommandId(
int command_id,
ui::Accelerator* accelerator) const {
CHECK(browser_);
if (command_id < 0) {
// This is a non-interactive title.
return false;
}
return browser_->GetFeatures()
.accelerator_provider()
->GetAcceleratorForCommandId(command_id, accelerator);
}
void NewTabButtonMenuModel::AddNewTabInGroupItem() {
TabStripModel* tab_strip_model = browser_->GetTabStripModel();
CHECK(tab_strip_model);
TabGroupModel* tab_group_model = tab_strip_model->group_model();
CHECK(tab_group_model);
std::optional<tab_groups::TabGroupId> group_id =
tab_group_model->GetMostRecentTabGroupId();
if (!group_id) {
// There is no most recent group. So we don't enable this option.
AddItem(IDC_ADD_NEW_TAB_RECENT_GROUP,
l10n_util::GetStringUTF16(IDS_NEW_TAB_IN_GROUP_NO_GROUPS));
SetEnabledAt(GetIndexOfCommandId(IDC_ADD_NEW_TAB_RECENT_GROUP).value(),
false);
} else {
// The most recent tab group exists.
std::u16string group_name =
tab_group_model->GetTabGroup(*group_id)->visual_data()->title();
std::u16string menu_item_label;
if (group_name.empty()) {
// "New tab in 2 tabs
int num_tabs = tab_group_model->GetTabGroup(*group_id)->tab_count();
menu_item_label = l10n_util::GetPluralStringFUTF16(
IDS_NEW_TAB_IN_GROUP_NO_NAME, num_tabs);
} else {
// "New tab in |group_name|".
menu_item_label =
l10n_util::GetStringFUTF16(IDS_NEW_TAB_IN_GROUP, group_name);
}
AddItem(IDC_ADD_NEW_TAB_RECENT_GROUP, menu_item_label);
}
SetElementIdentifierAt(
GetIndexOfCommandId(IDC_ADD_NEW_TAB_RECENT_GROUP).value(),
kNewTabInGroup);
}
void NewTabButtonMenuModel ::AddNewSplitTabItem() {
AddItemWithStringId(IDC_NEW_SPLIT_TAB, IDS_TAB_CXMENU_NEW_SPLIT_WITH_CURRENT);
SetElementIdentifierAt(GetIndexOfCommandId(IDC_NEW_SPLIT_TAB).value(),
kNewSplitView);
TabStripModel* tab_strip_model = browser_->GetTabStripModel();
CHECK(tab_strip_model);
SetEnabledAt(GetIndexOfCommandId(IDC_NEW_SPLIT_TAB).value(),
!tab_strip_model->IsActiveTabSplit());
}