Files
Claudio DeSouza cffb249298 [cr149] FindLastActiveWithProfile returning BWI
This change allows a couple of more places to be migrated to
`BrowserWindowInterface`.

Chromium changes:
https://chromium.googlesource.com/chromium/src/+/e8d0df41d25900497716dd3a4b070c6436fa1a97

commit e8d0df41d25900497716dd3a4b070c6436fa1a97
Author: Kun Wang <kunwang@microsoft.com>
Date:   Wed Apr 15 23:35:39 2026 -0700

    [bedrock] Migrate FindLastActiveWithProfile Step 1

    Bug: 494010890
    Change-Id: Ie0385deeda2e2f28baf75a810ada0becf5807c78
    Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7753884
    Reviewed-by: Thomas Lukaszewicz <tluk@chromium.org>
    Reviewed-by: Qikai Zhong <qikaizhong@microsoft.com>
    Commit-Queue: Kun Wang <kunwang@microsoft.com>
    Cr-Commit-Position: refs/heads/main@{#1615659}
2026-05-22 16:24:59 -04:00

233 lines
8.6 KiB
C++

// Copyright (c) 2024 The Brave Authors. All rights reserved.
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.
// Based on Chromium code subject to the following license:
// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "brave/browser/ui/commander/entity_match.h"
#include <utility>
#include "base/check.h"
#include "brave/browser/ui/commander/fuzzy_finder.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_window/public/browser_window_interface.h"
#include "chrome/browser/ui/browser_window/public/browser_window_interface_iterator.h"
#include "chrome/browser/ui/tab_ui_helper.h"
#include "chrome/browser/ui/tabs/tab_group_model.h"
#include "chrome/browser/ui/tabs/tab_utils.h"
#include "chrome/grit/generated_resources.h"
#include "components/sessions/content/session_tab_helper.h"
#include "components/tabs/public/tab_group.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/gfx/text_elider.h"
namespace commander {
namespace {
// TODO(lgrey): Just guessing for now! Not even sure if we need a max width,
// but right now, the code that does "<title> and x other tabs" wants a max.
double constexpr kMaxTitleWidth = 1000;
// TODO(crbug.com/418774949) Move to TabGroupFeatures for desktop.
std::u16string GetContentString(const BrowserWindowInterface* browser,
const TabGroup& group) {
constexpr size_t kContextMenuTabTitleMaxLength = 30;
std::u16string format_string = l10n_util::GetPluralStringFUTF16(
IDS_TAB_CXMENU_PLACEHOLDER_GROUP_TITLE, group.tab_count() - 1);
std::u16string short_title;
gfx::ElideString(
TabUIHelper::From(browser->GetTabStripModel()->GetActiveTab())
->GetTitle(),
kContextMenuTabTitleMaxLength, &short_title);
return base::ReplaceStringPlaceholders(format_string, short_title, nullptr);
}
} // namespace
WindowMatch::WindowMatch(BrowserWindowInterface* browser,
const std::u16string& title,
double score)
: browser(browser), title(title), score(score) {}
WindowMatch::~WindowMatch() = default;
WindowMatch::WindowMatch(WindowMatch&& other) = default;
WindowMatch& WindowMatch::operator=(WindowMatch&& other) = default;
std::unique_ptr<CommandItem> WindowMatch::ToCommandItem() const {
auto item = std::make_unique<CommandItem>(title, score, matched_ranges);
item->entity_type = CommandItem::Entity::kWindow;
return item;
}
GroupMatch::GroupMatch(tab_groups::TabGroupId group,
const std::u16string& title,
double score)
: group(group), title(title), score(score) {}
GroupMatch::~GroupMatch() = default;
GroupMatch::GroupMatch(GroupMatch&& other) = default;
GroupMatch& GroupMatch::operator=(GroupMatch&& other) = default;
std::unique_ptr<CommandItem> GroupMatch::ToCommandItem() const {
auto item = std::make_unique<CommandItem>(title, score, matched_ranges);
item->entity_type = CommandItem::Entity::kGroup;
return item;
}
TabMatch::TabMatch(int index,
int session_id,
const std::u16string& title,
double score)
: index(index), session_id(session_id), title(title), score(score) {}
TabMatch::~TabMatch() = default;
TabMatch::TabMatch(TabMatch&& other) = default;
TabMatch& TabMatch::operator=(TabMatch&& other) = default;
std::unique_ptr<CommandItem> TabMatch::ToCommandItem() const {
auto item = std::make_unique<CommandItem>(title, score, matched_ranges);
item->entity_type = CommandItem::Entity::kTab;
return item;
}
TabSearchOptions::TabSearchOptions() = default;
TabSearchOptions::~TabSearchOptions() = default;
std::vector<TabMatch> TabsMatchingInput(const BrowserWindowInterface* browser,
const std::u16string& input,
const TabSearchOptions& options) {
DCHECK(browser);
DCHECK(!(options.only_pinned && options.only_unpinned));
DCHECK(!(options.only_audible && options.only_muted));
DCHECK(!options.exclude_tab_group.has_value() ||
options.exclude_tab_group != options.only_tab_group);
double ordering_score = 1.0;
std::vector<TabMatch> results;
FuzzyFinder finder(input);
std::vector<gfx::Range> ranges;
const TabStripModel* tab_strip_model = browser->GetTabStripModel();
for (int i = 0; i < tab_strip_model->count(); ++i) {
if (tab_strip_model->IsTabPinned(i) ? options.only_unpinned
: options.only_pinned) {
continue;
}
content::WebContents* contents = tab_strip_model->GetWebContentsAt(i);
if (options.only_audible && !contents->IsCurrentlyAudible()) {
continue;
}
if (options.only_muted && !contents->IsAudioMuted()) {
continue;
}
auto group = tab_strip_model->GetTabGroupForTab(i);
if (options.only_tab_group.has_value() && options.only_tab_group != group) {
continue;
}
if (options.exclude_tab_group.has_value() &&
options.exclude_tab_group == group) {
continue;
}
auto title = contents->GetTitle();
if (input.empty()) {
TabMatch match(i, sessions::SessionTabHelper::IdForTab(contents).id(),
title, ordering_score);
results.push_back(std::move(match));
ordering_score *= .95;
} else {
double score = finder.Find(title, ranges);
if (score > 0) {
TabMatch match(i, sessions::SessionTabHelper::IdForTab(contents).id(),
title, score);
match.matched_ranges = ranges;
results.push_back(std::move(match));
}
}
}
return results;
}
std::vector<WindowMatch> WindowsMatchingInput(
const BrowserWindowInterface* browser_to_exclude,
const std::u16string& input,
bool match_profile) {
std::vector<WindowMatch> results;
double mru_score = .95;
FuzzyFinder finder(input);
std::vector<gfx::Range> ranges;
// TODO(https://github.com/brave/brave-browser/issues/49807): This code as a
// whole needs to be revisited with regards the use of `Browser*`.
ForEachCurrentBrowserWindowInterfaceOrderedByActivation(
[&](BrowserWindowInterface* browser_window_interface) {
Browser* browser =
browser_window_interface->GetBrowserForMigrationOnly();
if (browser == browser_to_exclude || !browser->is_type_normal()) {
return true; // continue iterating
}
if (match_profile &&
browser->profile() != browser_to_exclude->GetProfile()) {
return true; // continue iterating
}
std::u16string title =
browser->GetWindowTitleForMaxWidth(kMaxTitleWidth);
if (input.empty()) {
WindowMatch match(browser, title, mru_score);
results.push_back(std::move(match));
mru_score *= .95;
} else {
double score = finder.Find(title, ranges);
if (score > 0) {
WindowMatch match(browser, std::move(title), score);
match.matched_ranges = ranges;
results.push_back(std::move(match));
}
}
return true; // continue iterating
});
return results;
}
std::vector<GroupMatch> GroupsMatchingInput(
const BrowserWindowInterface* browser,
const std::u16string& input,
std::optional<tab_groups::TabGroupId> group_to_exclude) {
DCHECK(browser);
std::vector<GroupMatch> results;
FuzzyFinder finder(input);
std::vector<gfx::Range> ranges;
TabGroupModel* model = browser->GetTabStripModel()->group_model();
if (!model) {
return results;
}
// For empty input, use this to preserve TabGroupModel's ordering, which is
// arbitrary but still helpful to keep consistent across calls and surfaces.
double ordering_score = .95;
for (const tab_groups::TabGroupId& group_id : model->ListTabGroups()) {
if (group_to_exclude == group_id) {
continue;
}
TabGroup* group = model->GetTabGroup(group_id);
const std::u16string& group_title = group->visual_data()->title();
const std::u16string& title =
group_title.empty() ? GetContentString(browser, *group) : group_title;
if (input.empty()) {
GroupMatch match(group_id, title, ordering_score);
results.push_back(std::move(match));
ordering_score *= .95;
} else {
double score = finder.Find(title, ranges);
if (score > 0) {
GroupMatch match(group_id, title, score);
match.matched_ranges = ranges;
results.push_back(std::move(match));
}
}
}
return results;
}
} // namespace commander