| // Copyright 2012 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <memory> |
| #include <string> |
| |
| #include "base/functional/callback.h" |
| #include "base/memory/raw_ptr.h" |
| #include "chrome/browser/extensions/extension_uninstall_dialog.h" |
| #include "chrome/browser/extensions/extension_util.h" |
| #include "chrome/browser/ui/extensions/extension_dialog_utils.h" |
| #include "chrome/grit/generated_resources.h" |
| #include "ui/base/interaction/element_identifier.h" |
| #include "ui/base/l10n/l10n_util.h" |
| #include "ui/base/models/dialog_model.h" |
| #include "ui/gfx/image/image_skia_operations.h" |
| |
| namespace { |
| |
| DEFINE_LOCAL_ELEMENT_IDENTIFIER_VALUE(kCheckboxId); |
| |
| // The implementation of the uninstall dialog. |
| class ExtensionUninstallDialogImpl |
| : public extensions::ExtensionUninstallDialog { |
| public: |
| ExtensionUninstallDialogImpl( |
| Profile* profile, |
| gfx::NativeWindow parent, |
| extensions::ExtensionUninstallDialog::Delegate* delegate); |
| ExtensionUninstallDialogImpl(const ExtensionUninstallDialogImpl&) = delete; |
| ExtensionUninstallDialogImpl& operator=(const ExtensionUninstallDialogImpl&) = |
| delete; |
| ~ExtensionUninstallDialogImpl() override; |
| |
| // Forwards that the dialog has been accepted to the delegate. |
| void DialogAccepted(); |
| // Reports a canceled dialog to the delegate (unless accepted). |
| void DialogClosing(); |
| |
| private: |
| void Show() override; |
| void Close() override; |
| |
| // Pointer to the DialogModel for the dialog. This is cleared when the dialog |
| // is being closed and OnDialogClosed is reported. As such it prevents access |
| // to the dialog after it's been closed, as well as preventing multiple |
| // reports of OnDialogClosed. |
| raw_ptr<ui::DialogModel> dialog_model_ = nullptr; |
| |
| // WeakPtrs because the associated dialog may outlive |this|, which is owned |
| // by the caller of extensions::ExtensionsUninstallDialog::Create(). |
| base::WeakPtrFactory<ExtensionUninstallDialogImpl> weak_ptr_factory_{this}; |
| }; |
| |
| ExtensionUninstallDialogImpl::ExtensionUninstallDialogImpl( |
| Profile* profile, |
| gfx::NativeWindow parent, |
| extensions::ExtensionUninstallDialog::Delegate* delegate) |
| : extensions::ExtensionUninstallDialog(profile, parent, delegate) {} |
| |
| ExtensionUninstallDialogImpl::~ExtensionUninstallDialogImpl() { |
| if (dialog_model_) { |
| dialog_model_->host()->Close(); |
| } |
| DCHECK(!dialog_model_); |
| } |
| |
| void ExtensionUninstallDialogImpl::Show() { |
| ui::DialogModel::Builder dialog_builder; |
| dialog_builder.SetInternalName("ExtensionUninstallDialog") |
| .SetTitle(l10n_util::GetStringFUTF16( |
| IDS_EXTENSION_PROMPT_UNINSTALL_TITLE, |
| extensions::util::GetFixupExtensionNameForUIDisplay( |
| extension()->name()))) |
| .OverrideShowCloseButton(false) |
| .SetDialogDestroyingCallback( |
| base::BindOnce(&ExtensionUninstallDialogImpl::DialogClosing, |
| weak_ptr_factory_.GetWeakPtr())) |
| .SetIcon(ui::ImageModel::FromImageSkia( |
| gfx::ImageSkiaOperations::CreateResizedImage( |
| icon(), skia::ImageOperations::ResizeMethod::RESIZE_GOOD, |
| gfx::Size(extension_misc::EXTENSION_ICON_SMALL, |
| extension_misc::EXTENSION_ICON_SMALL)))) |
| .AddOkButton(base::BindOnce(&ExtensionUninstallDialogImpl::DialogAccepted, |
| weak_ptr_factory_.GetWeakPtr()), |
| ui::DialogModel::Button::Params() |
| .SetLabel(l10n_util::GetStringUTF16( |
| IDS_EXTENSION_PROMPT_UNINSTALL_BUTTON)) |
| .SetId(kOkButtonElementId)) |
| .AddCancelButton( |
| base::DoNothing() /* Cancel is covered by WindowClosingCallback */, |
| ui::DialogModel::Button::Params().SetId(kCancelButtonElementId)); |
| |
| if (triggering_extension()) { |
| dialog_builder.AddParagraph( |
| ui::DialogModelLabel( |
| l10n_util::GetStringFUTF16( |
| IDS_EXTENSION_PROMPT_UNINSTALL_TRIGGERED_BY_EXTENSION, |
| extensions::util::GetFixupExtensionNameForUIDisplay( |
| triggering_extension()->name()))) |
| .set_is_secondary() |
| .set_allow_character_break()); |
| } |
| |
| if (ShouldShowCheckbox()) { |
| std::u16string checkbox_label = |
| triggering_extension() |
| ? l10n_util::GetStringFUTF16( |
| IDS_EXTENSION_PROMPT_UNINSTALL_REPORT_ABUSE_FROM_EXTENSION, |
| extensions::util::GetFixupExtensionNameForUIDisplay( |
| extension()->name())) |
| : l10n_util::GetStringUTF16( |
| IDS_EXTENSION_PROMPT_UNINSTALL_REPORT_ABUSE); |
| |
| dialog_builder.AddCheckbox(kCheckboxId, |
| ui::DialogModelLabel(checkbox_label)); |
| } |
| |
| std::unique_ptr<ui::DialogModel> dialog_model = dialog_builder.Build(); |
| dialog_model_ = dialog_model.get(); |
| |
| ShowDialog(parent(), extension()->id(), std::move(dialog_model)); |
| } |
| |
| void ExtensionUninstallDialogImpl::Close() { |
| DCHECK(dialog_model_); |
| dialog_model_->host()->Close(); |
| } |
| |
| void ExtensionUninstallDialogImpl::DialogAccepted() { |
| DCHECK(dialog_model_); |
| const bool checkbox_is_checked = |
| ShouldShowCheckbox() && |
| dialog_model_->GetCheckboxByUniqueId(kCheckboxId)->is_checked(); |
| dialog_model_ = nullptr; |
| OnDialogClosed(checkbox_is_checked |
| ? CLOSE_ACTION_UNINSTALL_AND_CHECKBOX_CHECKED |
| : CLOSE_ACTION_UNINSTALL); |
| } |
| |
| void ExtensionUninstallDialogImpl::DialogClosing() { |
| if (!dialog_model_) { |
| return; |
| } |
| dialog_model_ = nullptr; |
| OnDialogClosed(CLOSE_ACTION_CANCELED); |
| } |
| |
| } // namespace |
| |
| DEFINE_CLASS_ELEMENT_IDENTIFIER_VALUE(extensions::ExtensionUninstallDialog, |
| kCancelButtonElementId); |
| DEFINE_CLASS_ELEMENT_IDENTIFIER_VALUE(extensions::ExtensionUninstallDialog, |
| kOkButtonElementId); |
| |
| // static |
| std::unique_ptr<extensions::ExtensionUninstallDialog> |
| extensions::ExtensionUninstallDialog::Create(Profile* profile, |
| gfx::NativeWindow parent, |
| Delegate* delegate) { |
| return std::make_unique<ExtensionUninstallDialogImpl>(profile, parent, |
| delegate); |
| } |