blob: f414fc85ce02c4aefad8245dde2ffc19dd478ea4 [file] [log] [blame]
// Copyright 2014 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 "remoting/host/chromeos/message_box.h"
#include <utility>
#include "base/macros.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/views/controls/message_box_view.h"
#include "ui/views/metadata/metadata_header_macros.h"
#include "ui/views/metadata/metadata_impl_macros.h"
#include "ui/views/widget/widget.h"
#include "ui/views/window/dialog_delegate.h"
namespace remoting {
// MessageBox::Core creates the dialog using the views::DialogWidget. The
// DialogWidget is created by the caller but its lifetime is managed by the
// NativeWidget. The DialogWidget communicates with the caller using the
//.DialogDelegateView interface, which must remain valid until DeleteDelegate()
// is called, at which the DialogDelegateView deletes itself.
//
// The Core class is introduced to abstract this awkward ownership model. The
// Core and the MessageBox hold a raw references to each other, which is
// invalidated when either side are destroyed.
class MessageBox::Core : public views::DialogDelegateView {
public:
METADATA_HEADER(Core);
Core(const std::u16string& title_label,
const std::u16string& message_label,
const std::u16string& ok_label,
const std::u16string& cancel_label,
ResultCallback result_callback,
MessageBox* message_box);
Core(const Core&) = delete;
Core& operator=(const Core&) = delete;
// Mirrors the public MessageBox interface.
void Show();
void Hide();
// views::DialogDelegateView:
ui::ModalType GetModalType() const override;
std::u16string GetWindowTitle() const override;
views::View* GetContentsView() override;
views::Widget* GetWidget() override;
const views::Widget* GetWidget() const override;
void DeleteDelegate() override;
// Called by MessageBox::Core when it is destroyed.
void OnMessageBoxDestroyed();
private:
const std::u16string title_label_;
ResultCallback result_callback_;
MessageBox* message_box_;
// Owned by the native widget hierarchy.
views::MessageBoxView* message_box_view_;
};
MessageBox::Core::Core(const std::u16string& title_label,
const std::u16string& message_label,
const std::u16string& ok_label,
const std::u16string& cancel_label,
ResultCallback result_callback,
MessageBox* message_box)
: title_label_(title_label),
result_callback_(std::move(result_callback)),
message_box_(message_box),
message_box_view_(new views::MessageBoxView(message_label)) {
DCHECK(message_box_);
DialogDelegate::SetButtonLabel(ui::DIALOG_BUTTON_OK, ok_label);
DialogDelegate::SetButtonLabel(ui::DIALOG_BUTTON_CANCEL, cancel_label);
auto run_callback = [](MessageBox::Core* core, Result result) {
if (core->result_callback_)
std::move(core->result_callback_).Run(result);
};
DialogDelegate::SetAcceptCallback(
base::BindOnce(run_callback, base::Unretained(this), OK));
DialogDelegate::SetCancelCallback(
base::BindOnce(run_callback, base::Unretained(this), CANCEL));
DialogDelegate::SetCloseCallback(
base::BindOnce(run_callback, base::Unretained(this), CANCEL));
}
void MessageBox::Core::Show() {
// The widget is owned by the NativeWidget. See comments in widget.h.
views::Widget* widget =
CreateDialogWidget(this, /* delegate */
nullptr /* parent window*/,
nullptr /* parent view */);
if (widget) {
widget->Show();
}
}
void MessageBox::Core::Hide() {
if (GetWidget()) {
GetWidget()->Close();
}
}
ui::ModalType MessageBox::Core::GetModalType() const {
return ui::MODAL_TYPE_SYSTEM;
}
std::u16string MessageBox::Core::GetWindowTitle() const {
return title_label_;
}
views::View* MessageBox::Core::GetContentsView() {
return message_box_view_;
}
views::Widget* MessageBox::Core::GetWidget() {
return message_box_view_->GetWidget();
}
const views::Widget* MessageBox::Core::GetWidget() const {
return message_box_view_->GetWidget();
}
void MessageBox::Core::DeleteDelegate() {
if (message_box_) {
message_box_->core_ = nullptr;
}
delete this;
}
void MessageBox::Core::OnMessageBoxDestroyed() {
DCHECK(message_box_);
message_box_ = nullptr;
// The callback should not be invoked after MessageBox is destroyed.
result_callback_.Reset();
}
BEGIN_METADATA(MessageBox, Core, views::DialogDelegateView)
END_METADATA
MessageBox::MessageBox(const std::u16string& title_label,
const std::u16string& message_label,
const std::u16string& ok_label,
const std::u16string& cancel_label,
ResultCallback result_callback)
: core_(new Core(title_label,
message_label,
ok_label,
cancel_label,
std::move(result_callback),
this)) {
core_->Show();
}
MessageBox::~MessageBox() {
DCHECK(thread_checker_.CalledOnValidThread());
if (core_) {
core_->OnMessageBoxDestroyed();
core_->Hide();
core_ = nullptr;
}
}
} // namespace remoting