#ifndef UI_BASE_MODELS_DIALOG_MODEL_H_
#define UI_BASE_MODELS_DIALOG_MODEL_H_
#include <memory>
#include <optional>
#include <string>
#include <variant>
#include "base/component_export.h"
#include "base/functional/callback.h"
#include "base/functional/callback_forward.h"
#include "base/functional/callback_helpers.h"
#include "base/memory/raw_ptr.h"
#include "base/types/pass_key.h"
#include "ui/base/interaction/element_identifier.h"
#include "ui/base/models/dialog_model_field.h"
#include "ui/base/models/dialog_model_host.h"
#include "ui/base/models/image_model.h"
#include "ui/base/mojom/dialog_button.mojom.h"
#include "ui/base/ui_base_types.h"
namespace ui {
class ComboboxModel;
class COMPONENT_EXPORT(UI_BASE) DialogModelDelegate {
public:
DialogModelDelegate() = default;
DialogModelDelegate(const DialogModelDelegate&) = delete;
DialogModelDelegate& operator=(const DialogModelDelegate&) = delete;
virtual ~DialogModelDelegate() = default;
DialogModel* dialog_model() { return dialog_model_; }
private:
friend class DialogModel;
void set_dialog_model(DialogModel* model) { dialog_model_ = model; }
raw_ptr<DialogModel> dialog_model_ = nullptr;
};
class COMPONENT_EXPORT(UI_BASE) DialogModel final {
public:
class COMPONENT_EXPORT(UI_BASE) Button final : public DialogModelField {
public:
class COMPONENT_EXPORT(UI_BASE) Params : public DialogModelField::Params {
public:
Params();
Params(const Params&) = delete;
Params& operator=(const Params&) = delete;
~Params();
Params& SetId(ElementIdentifier id);
Params& SetLabel(std::u16string label);
Params& SetStyle(std::optional<ButtonStyle> style);
Params& SetEnabled(bool is_enabled);
Params& AddAccelerator(Accelerator accelerator);
Params& SetVisible(bool is_visible) {
DialogModelField::Params::SetVisible(is_visible);
return *this;
}
private:
friend class DialogModel;
friend class Button;
ElementIdentifier id_;
std::u16string label_;
std::optional<ButtonStyle> style_;
bool is_enabled_ = true;
base::flat_set<Accelerator> accelerators_;
};
Button(base::RepeatingCallback<void(const Event&)> callback,
const Params& params);
Button(const Button&) = delete;
Button& operator=(const Button&) = delete;
~Button() override;
const std::u16string& label() const { return label_; }
const std::optional<ButtonStyle> style() const { return style_; }
bool is_enabled() const { return is_enabled_; }
void OnPressed(base::PassKey<DialogModelHost>, const Event& event);
private:
friend class DialogModel;
std::u16string label_;
const std::optional<ButtonStyle> style_;
bool is_enabled_;
base::RepeatingCallback<void(const Event&)> callback_;
};
using ButtonCallbackVariant = std::variant<
decltype(base::DoNothing()),
base::OnceClosure,
base::RepeatingCallback<bool()>>;
class COMPONENT_EXPORT(UI_BASE) Builder final {
public:
explicit Builder(std::unique_ptr<DialogModelDelegate> delegate);
Builder();
Builder(const Builder&) = delete;
Builder& operator=(const Builder&) = delete;
~Builder();
[[nodiscard]] std::unique_ptr<DialogModel> Build();
DialogModel* model() { return model_.get(); }
Builder& OverrideShowCloseButton(bool show_close_button) {
model_->override_show_close_button_ = show_close_button;
return *this;
}
Builder& SetInternalName(std::string internal_name) {
model_->internal_name_ = std::move(internal_name);
return *this;
}
Builder& SetTitle(std::u16string title) {
model_->title_ = std::move(title);
return *this;
}
Builder& SetAccessibleTitle(std::u16string accessible_title) {
model_->accessible_title_ = std::move(accessible_title);
return *this;
}
Builder& SetSubtitle(std::u16string subtitle) {
model_->subtitle_ = std::move(subtitle);
return *this;
}
Builder& SetBannerImage(ImageModel banner,
ImageModel dark_mode_banner = ImageModel()) {
model_->banner_ = std::move(banner);
model_->dark_mode_banner_ = std::move(dark_mode_banner);
return *this;
}
Builder& SetIcon(ImageModel icon,
ImageModel dark_mode_icon = ImageModel()) {
model_->icon_ = std::move(icon);
model_->dark_mode_icon_ = std::move(dark_mode_icon);
return *this;
}
Builder& SetMainImage(ImageModel main_image) {
model_->main_image_ = std::move(main_image);
return *this;
}
Builder& SetIsAlertDialog() {
model_->is_alert_dialog_ = true;
return *this;
}
Builder& DisableCloseOnDeactivate() {
model_->close_on_deactivate_ = false;
return *this;
}
Builder& SetCloseActionCallback(base::OnceClosure callback) {
model_->close_action_callback_ = std::move(callback);
return *this;
}
Builder& SetDialogDestroyingCallback(base::OnceClosure callback) {
model_->dialog_destroying_callback_ = std::move(callback);
return *this;
}
Builder& AddOkButton(ButtonCallbackVariant callback,
const Button::Params& params = Button::Params());
Builder& AddCancelButton(ButtonCallbackVariant callback,
const Button::Params& params = Button::Params());
Builder& AddExtraButton(
base::RepeatingCallback<void(const Event&)> callback,
const Button::Params& params);
Builder& AddExtraLink(DialogModelLabel::TextReplacement link);
Builder& AddParagraph(const DialogModelLabel& label,
std::u16string header = std::u16string(),
ElementIdentifier id = ElementIdentifier()) {
model_->AddParagraph(label, header, id);
return *this;
}
Builder& AddCheckbox(ElementIdentifier id,
const DialogModelLabel& label,
const DialogModelCheckbox::Params& params =
DialogModelCheckbox::Params()) {
model_->AddCheckbox(id, label, params);
return *this;
}
Builder& AddCombobox(ElementIdentifier id,
std::u16string label,
std::unique_ptr<ui::ComboboxModel> combobox_model,
const DialogModelCombobox::Params& params =
DialogModelCombobox::Params()) {
model_->AddCombobox(id, std::move(label), std::move(combobox_model),
params);
return *this;
}
Builder& AddMenuItem(ImageModel icon,
std::u16string label,
base::RepeatingCallback<void(int)> callback,
const DialogModelMenuItem::Params& params =
DialogModelMenuItem::Params()) {
model_->AddMenuItem(std::move(icon), std::move(label),
std::move(callback), params);
return *this;
}
Builder& AddTitleItem(std::u16string label,
ElementIdentifier id = ElementIdentifier()) {
model_->AddTitleItem(std::move(label), id);
return *this;
}
Builder& AddSeparator() {
model_->AddSeparator();
return *this;
}
Builder& AddTextfield(ElementIdentifier id,
std::u16string label,
std::u16string text,
const DialogModelTextfield::Params& params =
DialogModelTextfield::Params()) {
model_->AddTextfield(id, std::move(label), std::move(text), params);
return *this;
}
Builder& AddPasswordField(ElementIdentifier id,
std::u16string label,
std::u16string accessible_text,
std::u16string incorrect_password_text,
const DialogModelPasswordField::Params& params =
DialogModelPasswordField::Params()) {
model_->AddPasswordField(id, std::move(label), std::move(accessible_text),
std::move(incorrect_password_text), params);
return *this;
}
Builder& SetFootnote(const DialogModelLabel& label) {
model_->SetFootnote(label);
return *this;
}
Builder& AddCustomField(
std::unique_ptr<DialogModelCustomField::Field> field,
ElementIdentifier id = ElementIdentifier()) {
model_->AddCustomField(std::move(field), id);
return *this;
}
Builder& OverrideDefaultButton(mojom::DialogButton button);
Builder& SetInitiallyFocusedField(ElementIdentifier id);
private:
Builder& AddButtonInternal(ButtonCallbackVariant callback,
const Button::Params& params,
std::optional<Button>& model_button,
ButtonCallbackVariant& model_callback);
std::unique_ptr<DialogModel> model_;
};
DialogModel(base::PassKey<DialogModel::Builder>,
std::unique_ptr<DialogModelDelegate> delegate);
DialogModel(const DialogModel&) = delete;
DialogModel& operator=(const DialogModel&) = delete;
~DialogModel();
DialogModelHost* host() { return host_; }
void AddParagraph(const DialogModelLabel& label,
std::u16string header = std::u16string(),
ElementIdentifier id = ElementIdentifier()) {
contents_.AddParagraph(label, std::move(header), id);
}
void AddCheckbox(ElementIdentifier id,
const DialogModelLabel& label,
const DialogModelCheckbox::Params& params =
DialogModelCheckbox::Params()) {
contents_.AddCheckbox(id, std::move(label), params);
}
void AddCombobox(ElementIdentifier id,
std::u16string label,
std::unique_ptr<ui::ComboboxModel> combobox_model,
const DialogModelCombobox::Params& params =
DialogModelCombobox::Params()) {
contents_.AddCombobox(id, std::move(label), std::move(combobox_model),
params);
}
void AddMenuItem(ImageModel icon,
std::u16string label,
base::RepeatingCallback<void(int)> callback,
const DialogModelMenuItem::Params& params =
DialogModelMenuItem::Params()) {
contents_.AddMenuItem(std::move(icon), std::move(label),
std::move(callback), params);
}
void AddTitleItem(std::u16string label,
ElementIdentifier id = ElementIdentifier()) {
contents_.AddTitleItem(std::move(label), id);
}
void AddSeparator() { contents_.AddSeparator(); }
void AddTextfield(ElementIdentifier id,
std::u16string label,
std::u16string text,
const DialogModelTextfield::Params& params =
DialogModelTextfield::Params()) {
contents_.AddTextfield(id, std::move(label), std::move(text), params);
}
void AddPasswordField(ElementIdentifier id,
std::u16string label,
std::u16string accessible_text,
std::u16string incorrect_password_text,
const DialogModelPasswordField::Params& params =
DialogModelField::Params()) {
contents_.AddPasswordField(id, std::move(label), std::move(accessible_text),
std::move(incorrect_password_text), params);
}
void SetFootnote(const DialogModelLabel& label) {
CHECK(!host_);
footnote_label_.emplace(label);
}
void AddCustomField(std::unique_ptr<DialogModelCustomField::Field> field,
ElementIdentifier id = ElementIdentifier()) {
contents_.AddCustomField(std::move(field), id);
}
bool HasField(ElementIdentifier id) const;
DialogModelField* GetFieldByUniqueId(ElementIdentifier id);
DialogModelCheckbox* GetCheckboxByUniqueId(ElementIdentifier id) {
return contents_.GetCheckboxByUniqueId(id);
}
DialogModelCombobox* GetComboboxByUniqueId(ElementIdentifier id) {
return contents_.GetComboboxByUniqueId(id);
}
DialogModelTextfield* GetTextfieldByUniqueId(ElementIdentifier id) {
return contents_.GetTextfieldByUniqueId(id);
}
DialogModelPasswordField* GetPasswordFieldByUniqueId(ElementIdentifier id) {
return contents_.GetPasswordFieldByUniqueId(id);
}
Button* GetButtonByUniqueId(ElementIdentifier id);
bool OnDialogAcceptAction(base::PassKey<DialogModelHost>);
bool OnDialogCancelAction(base::PassKey<DialogModelHost>);
void OnDialogCloseAction(base::PassKey<DialogModelHost>);
void OnDialogDestroying(base::PassKey<DialogModelHost>);
void SetVisible(ElementIdentifier id, bool visible);
void SetButtonLabel(Button* button, const std::u16string& label);
void SetButtonEnabled(Button* button, bool enabled);
void set_host(base::PassKey<DialogModelHost>, DialogModelHost* host) {
host_ = host;
}
const std::optional<bool>& override_show_close_button(
base::PassKey<DialogModelHost>) const {
return override_show_close_button_;
}
const std::string& internal_name(base::PassKey<DialogModelHost>) const {
return internal_name_;
}
const std::u16string& title(base::PassKey<DialogModelHost>) const {
return title_;
}
const std::u16string& accessible_title(base::PassKey<DialogModelHost>) const {
return accessible_title_;
}
const std::u16string& subtitle(base::PassKey<DialogModelHost>) const {
return subtitle_;
}
const ImageModel& main_image(base::PassKey<DialogModelHost>) const {
return main_image_;
}
const ImageModel& icon(base::PassKey<DialogModelHost>) const { return icon_; }
const ImageModel& dark_mode_icon(base::PassKey<DialogModelHost>) const {
return dark_mode_icon_;
}
const ImageModel& banner(base::PassKey<DialogModelHost>) const {
return banner_;
}
const ImageModel& dark_mode_banner(base::PassKey<DialogModelHost>) const {
return dark_mode_banner_;
}
const std::optional<mojom::DialogButton>& override_default_button(
base::PassKey<DialogModelHost>) const {
return override_default_button_;
}
ElementIdentifier initially_focused_field(
base::PassKey<DialogModelHost>) const {
return initially_focused_field_;
}
bool is_alert_dialog(base::PassKey<DialogModelHost>) const {
return is_alert_dialog_;
}
Button* ok_button(base::PassKey<DialogModelHost>) {
return ok_button_.has_value() ? &ok_button_.value() : nullptr;
}
Button* cancel_button(base::PassKey<DialogModelHost>) {
return cancel_button_.has_value() ? &cancel_button_.value() : nullptr;
}
Button* extra_button(base::PassKey<DialogModelHost>) {
return extra_button_.has_value() ? &extra_button_.value() : nullptr;
}
DialogModelLabel::TextReplacement* extra_link(
base::PassKey<DialogModelHost>) {
return extra_link_.has_value() ? &extra_link_.value() : nullptr;
}
const std::optional<DialogModelLabel>& footnote_label() const {
return footnote_label_;
}
bool close_on_deactivate(base::PassKey<DialogModelHost>) const {
return close_on_deactivate_;
}
DialogModelSection* contents() { return &contents_; }
const std::vector<std::unique_ptr<DialogModelField>>& fields(
base::PassKey<DialogModelHost>) {
return contents_.fields();
}
private:
static bool RunButtonCallback(ButtonCallbackVariant& callback_variant);
Button* MaybeGetButtonByUniqueId(ElementIdentifier id);
std::unique_ptr<DialogModelDelegate> delegate_;
raw_ptr<DialogModelHost> host_ = nullptr;
std::optional<bool> override_show_close_button_;
bool close_on_deactivate_ = true;
std::string internal_name_;
std::u16string title_;
std::u16string accessible_title_;
std::u16string subtitle_;
ImageModel icon_;
ImageModel dark_mode_icon_;
ImageModel main_image_;
ImageModel banner_;
ImageModel dark_mode_banner_;
std::optional<mojom::DialogButton> override_default_button_;
DialogModelSection contents_;
ElementIdentifier initially_focused_field_;
bool is_alert_dialog_ = false;
std::optional<Button> ok_button_;
std::optional<Button> cancel_button_;
std::optional<Button> extra_button_;
std::optional<DialogModelLabel::TextReplacement> extra_link_;
std::optional<DialogModelLabel> footnote_label_;
ButtonCallbackVariant accept_action_callback_;
ButtonCallbackVariant cancel_action_callback_;
base::OnceClosure close_action_callback_;
base::OnceClosure dialog_destroying_callback_;
};
}
#endif