blob: fdc19ab8c5535dc9c29fe36a73dcf15d5a22830f [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 "chrome/browser/extensions/api/debugger/extension_dev_tools_infobar.h"
#include <memory>
#include "base/callback_helpers.h"
#include "base/lazy_instance.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/devtools/global_confirm_info_bar.h"
#include "chrome/grit/generated_resources.h"
#include "components/infobars/core/confirm_infobar_delegate.h"
#include "ui/base/l10n/l10n_util.h"
namespace extensions {
namespace {
// The InfoBarDelegate that ExtensionDevToolsInfoBar shows.
class ExtensionDevToolsInfoBarDelegate : public ConfirmInfoBarDelegate {
public:
ExtensionDevToolsInfoBarDelegate(const base::Closure& dismissed_callback,
const std::string& client_name);
~ExtensionDevToolsInfoBarDelegate() override;
// ConfirmInfoBarDelegate:
infobars::InfoBarDelegate::InfoBarIdentifier GetIdentifier() const override;
bool ShouldExpire(const NavigationDetails& details) const override;
void InfoBarDismissed() override;
base::string16 GetMessageText() const override;
gfx::ElideBehavior GetMessageElideBehavior() const override;
int GetButtons() const override;
bool Cancel() override;
private:
const base::string16 client_name_;
base::Closure dismissed_callback_;
DISALLOW_COPY_AND_ASSIGN(ExtensionDevToolsInfoBarDelegate);
};
ExtensionDevToolsInfoBarDelegate::ExtensionDevToolsInfoBarDelegate(
const base::Closure& dismissed_callback,
const std::string& client_name)
: ConfirmInfoBarDelegate(),
client_name_(base::UTF8ToUTF16(client_name)),
dismissed_callback_(dismissed_callback) {}
ExtensionDevToolsInfoBarDelegate::~ExtensionDevToolsInfoBarDelegate() {}
infobars::InfoBarDelegate::InfoBarIdentifier
ExtensionDevToolsInfoBarDelegate::GetIdentifier() const {
return EXTENSION_DEV_TOOLS_INFOBAR_DELEGATE;
}
bool ExtensionDevToolsInfoBarDelegate::ShouldExpire(
const NavigationDetails& details) const {
return false;
}
void ExtensionDevToolsInfoBarDelegate::InfoBarDismissed() {
DCHECK(!dismissed_callback_.is_null());
// Use ResetAndReturn() since running the callback may delete |this|.
base::ResetAndReturn(&dismissed_callback_).Run();
}
base::string16 ExtensionDevToolsInfoBarDelegate::GetMessageText() const {
return l10n_util::GetStringFUTF16(IDS_DEV_TOOLS_INFOBAR_LABEL, client_name_);
}
gfx::ElideBehavior ExtensionDevToolsInfoBarDelegate::GetMessageElideBehavior()
const {
// The important part of the message text above is at the end:
// "... is debugging the browser". If the extension name is very long,
// we'd rather truncate it instead. See https://crbug.com/823194.
return gfx::ELIDE_HEAD;
}
int ExtensionDevToolsInfoBarDelegate::GetButtons() const {
return BUTTON_CANCEL;
}
bool ExtensionDevToolsInfoBarDelegate::Cancel() {
InfoBarDismissed();
// InfoBarDismissed() will have closed us already.
return false;
}
using ExtensionInfoBars = std::map<std::string, ExtensionDevToolsInfoBar*>;
base::LazyInstance<ExtensionInfoBars>::Leaky g_extension_info_bars =
LAZY_INSTANCE_INITIALIZER;
} // namespace
// static
ExtensionDevToolsInfoBar* ExtensionDevToolsInfoBar::Create(
const std::string& extension_id,
const std::string& extension_name,
ExtensionDevToolsClientHost* client_host,
const base::Closure& dismissed_callback) {
ExtensionInfoBars::iterator it =
g_extension_info_bars.Get().find(extension_id);
ExtensionDevToolsInfoBar* infobar = nullptr;
if (it != g_extension_info_bars.Get().end())
infobar = it->second;
else
infobar = new ExtensionDevToolsInfoBar(extension_id, extension_name);
infobar->callbacks_[client_host] = dismissed_callback;
return infobar;
}
ExtensionDevToolsInfoBar::ExtensionDevToolsInfoBar(
const std::string& extension_id,
const std::string& extension_name)
: extension_id_(extension_id) {
g_extension_info_bars.Get()[extension_id] = this;
// This class closes the |infobar_|, so it's safe to pass Unretained(this).
auto delegate = std::make_unique<ExtensionDevToolsInfoBarDelegate>(
base::Bind(&ExtensionDevToolsInfoBar::InfoBarDismissed,
base::Unretained(this)),
extension_name);
infobar_ = GlobalConfirmInfoBar::Show(std::move(delegate));
}
ExtensionDevToolsInfoBar::~ExtensionDevToolsInfoBar() {
g_extension_info_bars.Get().erase(extension_id_);
if (infobar_)
infobar_->Close();
}
void ExtensionDevToolsInfoBar::Remove(
ExtensionDevToolsClientHost* client_host) {
callbacks_.erase(client_host);
if (callbacks_.empty())
delete this;
}
void ExtensionDevToolsInfoBar::InfoBarDismissed() {
std::map<ExtensionDevToolsClientHost*, base::Closure> copy = callbacks_;
for (const auto& pair : copy)
pair.second.Run();
}
} // namespace extensions