blob: 3777d9fb3a57f705a8631b2579d2512a49889dcb [file] [log] [blame]
// Copyright 2019 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 "chrome/browser/ui/tabs/tab_group.h"
#include <map>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "base/check_op.h"
#include "base/optional.h"
#include "chrome/browser/ui/tab_ui_helper.h"
#include "chrome/browser/ui/tabs/tab_group_controller.h"
#include "chrome/browser/ui/tabs/tab_strip_model_observer.h"
#include "chrome/grit/generated_resources.h"
#include "components/tab_groups/tab_group_id.h"
#include "components/tab_groups/tab_group_visual_data.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/gfx/text_elider.h"
TabGroup::TabGroup(TabGroupController* controller,
const tab_groups::TabGroupId& id,
const tab_groups::TabGroupVisualData& visual_data)
: controller_(controller), id_(id) {
visual_data_ = std::make_unique<tab_groups::TabGroupVisualData>(visual_data);
}
TabGroup::~TabGroup() = default;
void TabGroup::SetVisualData(const tab_groups::TabGroupVisualData& visual_data,
bool is_customized) {
std::unique_ptr<tab_groups::TabGroupVisualData> old_visuals =
std::move(visual_data_);
TabGroupChange::VisualsChange visuals;
visuals.old_visuals = old_visuals.get();
visuals.new_visuals = &visual_data;
visual_data_ = std::make_unique<tab_groups::TabGroupVisualData>(visual_data);
// Once the visual data is customized, it should stay customized.
is_customized_ |= is_customized;
controller_->ChangeTabGroupVisuals(id_, visuals);
}
std::u16string TabGroup::GetContentString() const {
gfx::Range tabs_in_group = ListTabs();
DCHECK_GT(tabs_in_group.length(), 0u);
TabUIHelper* const tab_ui_helper = TabUIHelper::FromWebContents(
controller_->GetWebContentsAt(tabs_in_group.start()));
constexpr size_t kContextMenuTabTitleMaxLength = 30;
std::u16string format_string = l10n_util::GetPluralStringFUTF16(
IDS_TAB_CXMENU_PLACEHOLDER_GROUP_TITLE, tabs_in_group.length() - 1);
std::u16string short_title;
gfx::ElideString(tab_ui_helper->GetTitle(), kContextMenuTabTitleMaxLength,
&short_title);
return base::ReplaceStringPlaceholders(format_string, {short_title}, nullptr);
}
void TabGroup::AddTab() {
if (tab_count_ == 0) {
controller_->CreateTabGroup(id_);
TabGroupChange::VisualsChange visuals;
visuals.old_visuals = nullptr;
controller_->ChangeTabGroupVisuals(id_, visuals);
}
controller_->ChangeTabGroupContents(id_);
++tab_count_;
}
void TabGroup::RemoveTab() {
DCHECK_GT(tab_count_, 0);
--tab_count_;
if (tab_count_ == 0)
controller_->CloseTabGroup(id_);
else
controller_->ChangeTabGroupContents(id_);
}
bool TabGroup::IsEmpty() const {
return tab_count_ == 0;
}
bool TabGroup::IsCustomized() const {
return is_customized_;
}
base::Optional<int> TabGroup::GetFirstTab() const {
for (int i = 0; i < controller_->GetTabCount(); ++i) {
if (controller_->GetTabGroupForTab(i) == id_)
return i;
}
return base::nullopt;
}
base::Optional<int> TabGroup::GetLastTab() const {
for (int i = controller_->GetTabCount() - 1; i >= 0; --i) {
if (controller_->GetTabGroupForTab(i) == id_)
return i;
}
return base::nullopt;
}
gfx::Range TabGroup::ListTabs() const {
base::Optional<int> maybe_first_tab = GetFirstTab();
if (!maybe_first_tab)
return gfx::Range();
int first_tab = maybe_first_tab.value();
// Safe to assume GetLastTab() is not nullopt.
int last_tab = GetLastTab().value();
// If DCHECKs are enabled, check for group contiguity. The result
// doesn't really make sense if the group is discontiguous.
if (DCHECK_IS_ON()) {
for (int i = first_tab; i <= last_tab; ++i)
DCHECK(controller_->GetTabGroupForTab(i) == id_);
}
return gfx::Range(first_tab, last_tab + 1);
}