// 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 "ui/base/l10n/l10n_util.h" #include "ui/views/controls/message_box_view.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: Core(const base::string16& title_label, const base::string16& message_label, const base::string16& ok_label, const base::string16& cancel_label, ResultCallback result_callback, MessageBox* message_box); // Mirrors the public MessageBox interface. void Show(); void Hide(); // views::DialogDelegateView interface. bool Accept() override; bool Cancel() override; ui::ModalType GetModalType() const override; base::string16 GetWindowTitle() const override; base::string16 GetDialogButtonLabel(ui::DialogButton button) const override; // views::WidgetDelegate interface. 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 base::string16 title_label_; const base::string16 ok_label_; const base::string16 cancel_label_; ResultCallback result_callback_; MessageBox* message_box_; // Owned by the native widget hierarchy. views::MessageBoxView* message_box_view_; DISALLOW_COPY_AND_ASSIGN(Core); }; MessageBox::Core::Core(const base::string16& title_label, const base::string16& message_label, const base::string16& ok_label, const base::string16& cancel_label, ResultCallback result_callback, MessageBox* message_box) : title_label_(title_label), ok_label_(ok_label), cancel_label_(cancel_label), result_callback_(result_callback), message_box_(message_box), message_box_view_(new views::MessageBoxView( views::MessageBoxView::InitParams(message_label))) { DCHECK(message_box_); } 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(); } } bool MessageBox::Core::Accept() { if (!result_callback_.is_null()) { base::ResetAndReturn(&result_callback_).Run(OK); } return true /* close the window*/; } bool MessageBox::Core::Cancel() { if (!result_callback_.is_null()) { base::ResetAndReturn(&result_callback_).Run(CANCEL); } return true /* close the window*/; } ui::ModalType MessageBox::Core::GetModalType() const { return ui::MODAL_TYPE_SYSTEM; } base::string16 MessageBox::Core::GetWindowTitle() const { return title_label_; } base::string16 MessageBox::Core::GetDialogButtonLabel( ui::DialogButton button) const { switch (button) { case ui::DIALOG_BUTTON_OK: return ok_label_; case ui::DIALOG_BUTTON_CANCEL: return cancel_label_; default: NOTREACHED(); return base::string16(); } } 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(); } MessageBox::MessageBox(const base::string16& title_label, const base::string16& message_label, const base::string16& ok_label, const base::string16& cancel_label, ResultCallback result_callback) : core_(new Core(title_label, message_label, ok_label, cancel_label, result_callback, this)) { thread_checker_.DetachFromThread(); } MessageBox::~MessageBox() { if (core_) { core_->OnMessageBoxDestroyed(); core_->Hide(); core_ = nullptr; } } void MessageBox::Show() { DCHECK(thread_checker_.CalledOnValidThread()); core_->Show(); } void MessageBox::Hide() { DCHECK(thread_checker_.CalledOnValidThread()); if (core_) { core_->Hide(); } } } // namespace remoting