// Copyright 2020 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. #ifndef UI_BASE_MODELS_DIALOG_MODEL_FIELD_H_ #define UI_BASE_MODELS_DIALOG_MODEL_FIELD_H_ #include "base/callback.h" #include "base/containers/flat_set.h" #include "base/gtest_prod_util.h" #include "base/strings/string16.h" #include "base/types/pass_key.h" #include "ui/base/accelerators/accelerator.h" #include "ui/base/models/combobox_model.h" namespace ui { class DialogModel; class DialogModelButton; class DialogModelBodyText; class DialogModelCheckbox; class DialogModelCombobox; class DialogModelHost; class DialogModelTextfield; class Event; // TODO(pbos): Move this to separate header. // DialogModelLabel is an exception to below classes. This is not a // DialogModelField but rather represents a text label and styling. This is used // with DialogModelBodyText and DialogModelCheckbox for instance and has support // for showing a link. class COMPONENT_EXPORT(UI_BASE) DialogModelLabel { public: struct COMPONENT_EXPORT(UI_BASE) Link { // TODO(pbos): Move this definition (maybe as a ui::LinkCallback) so it can // be reused with views::Link. using Callback = base::RepeatingCallback; Link(int message_id, Callback callback); Link(int message_id, base::RepeatingClosure closure); Link(const Link&); ~Link(); const int message_id; const Callback callback; }; explicit DialogModelLabel(int message_id); explicit DialogModelLabel(base::string16 fixed_string); DialogModelLabel(const DialogModelLabel&); DialogModelLabel& operator=(const DialogModelLabel&) = delete; ~DialogModelLabel(); static DialogModelLabel CreateWithLink(int message_id, Link link); static DialogModelLabel CreateWithLinks(int message_id, std::vector links); // Gets the string. Not for use with links, in which case the caller must use // links() and message_id() to construct the final label. This is required to // style the final label appropriately and support link callbacks. The caller // is responsible for checking links().empty() before calling this. const base::string16& GetString(base::PassKey) const; DialogModelLabel& set_is_secondary() { is_secondary_ = true; return *this; } DialogModelLabel& set_allow_character_break() { allow_character_break_ = true; return *this; } int message_id(base::PassKey) const { return message_id_; } const std::vector links(base::PassKey) const { return links_; } bool is_secondary(base::PassKey) const { return is_secondary_; } bool allow_character_break(base::PassKey) const { return allow_character_break_; } private: explicit DialogModelLabel(int message_id, std::vector links); const int message_id_; const base::string16 string_; const std::vector links_; bool is_secondary_ = false; bool allow_character_break_ = false; }; // These "field" classes represent entries in a DialogModel. They are owned // by the model and either created through the model or DialogModel::Builder. // These entries can be referred to by setting the field's unique id in // construction parameters (::Params::SetUniqueId()). They can then later be // acquired through DialogModel::GetFieldByUniqueId() methods. // These fields own the data corresponding to their field. For instance, the // text of a textfield in a model is read using DialogModelTextfield::text() and // stays in sync with the visible dialog (through DialogModelHosts). class COMPONENT_EXPORT(UI_BASE) DialogModelField { public: enum Type { kButton, kBodyText, kCheckbox, kCombobox, kTextfield }; DialogModelField(const DialogModelField&) = delete; DialogModelField& operator=(const DialogModelField&) = delete; virtual ~DialogModelField(); // Methods with base::PassKey are only intended to be called // by the DialogModelHost implementation. Type type(base::PassKey) const { return type_; } const base::flat_set& accelerators( base::PassKey) const { return accelerators_; } int unique_id(base::PassKey) const { return unique_id_; } DialogModelButton* AsButton(base::PassKey); DialogModelBodyText* AsBodyText(base::PassKey); DialogModelCheckbox* AsCheckbox(base::PassKey); DialogModelCombobox* AsCombobox(base::PassKey); DialogModelTextfield* AsTextfield(base::PassKey); protected: // Children of this class need to be constructed through DialogModel to help // enforce that they're added to the model. DialogModelField(base::PassKey, DialogModel* model, Type type, int unique_id, base::flat_set accelerators); DialogModelButton* AsButton(); DialogModelBodyText* AsBodyText(); DialogModelCheckbox* AsCheckbox(); DialogModelCombobox* AsCombobox(); DialogModelTextfield* AsTextfield(); private: friend class DialogModel; FRIEND_TEST_ALL_PREFIXES(DialogModelButtonTest, UsesParamsUniqueId); DialogModel* const model_; const Type type_; const int unique_id_; const base::flat_set accelerators_; }; // Field class representing a dialog button. class COMPONENT_EXPORT(UI_BASE) DialogModelButton : public DialogModelField { public: class COMPONENT_EXPORT(UI_BASE) Params { public: Params(); Params(const Params&) = delete; Params& operator=(const Params&) = delete; ~Params(); Params& SetUniqueId(int unique_id); Params& AddAccelerator(Accelerator accelerator); private: friend class DialogModelButton; int unique_id_ = -1; base::flat_set accelerators_; }; // Note that this is constructed through a DialogModel which adds it to model // fields. DialogModelButton(base::PassKey pass_key, DialogModel* model, base::RepeatingCallback callback, base::string16 label, const Params& params); DialogModelButton(const DialogModelButton&) = delete; DialogModelButton& operator=(const DialogModelButton&) = delete; ~DialogModelButton() override; // Methods with base::PassKey are only intended to be called // by the DialogModelHost implementation. const base::string16& label(base::PassKey) const { return label_; } void OnPressed(base::PassKey, const Event& event); private: friend class DialogModel; const base::string16 label_; // The button callback gets called when the button is activated. Whether // that happens on key-press, release, etc. is implementation (and platform) // dependent. base::RepeatingCallback callback_; }; // Field class representing body text. class COMPONENT_EXPORT(UI_BASE) DialogModelBodyText : public DialogModelField { public: // Note that this is constructed through a DialogModel which adds it to model // fields. DialogModelBodyText(base::PassKey pass_key, DialogModel* model, const DialogModelLabel& label); DialogModelBodyText(const DialogModelBodyText&) = delete; DialogModelBodyText& operator=(const DialogModelBodyText&) = delete; ~DialogModelBodyText() override; const DialogModelLabel& label(base::PassKey) const { return label_; } private: const DialogModelLabel label_; }; // Field class representing a checkbox with descriptive text. class COMPONENT_EXPORT(UI_BASE) DialogModelCheckbox : public DialogModelField { public: class COMPONENT_EXPORT(UI_BASE) Params { public: Params() = default; Params(const Params&) = delete; Params& operator=(const Params&) = delete; ~Params() = default; Params& SetIsChecked(bool is_checked) { is_checked_ = is_checked; return *this; } private: friend class DialogModelCheckbox; bool is_checked_ = false; }; // Note that this is constructed through a DialogModel which adds it to model // fields. DialogModelCheckbox(base::PassKey pass_key, DialogModel* model, int unique_id, const DialogModelLabel& label, const Params& params); DialogModelCheckbox(const DialogModelCheckbox&) = delete; DialogModelCheckbox& operator=(const DialogModelCheckbox&) = delete; ~DialogModelCheckbox() override; bool is_checked() const { return is_checked_; } void OnChecked(base::PassKey, bool is_checked); const DialogModelLabel& label(base::PassKey) const { return label_; } private: const DialogModelLabel label_; bool is_checked_; }; // Field class representing a combobox and corresponding label to describe the // combobox: // //