blob: 3815767d1152c0b7fd5d50fb8ff77c52f16c2e78 [file] [log] [blame]
// 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 <string>
#include "base/callback.h"
#include "base/containers/flat_set.h"
#include "base/gtest_prod_util.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<void(const Event& event)>;
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(std::u16string 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<Link> 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 std::u16string& GetString(base::PassKey<DialogModelHost>) 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<DialogModelHost>) const { return message_id_; }
const std::vector<Link> links(base::PassKey<DialogModelHost>) const {
return links_;
}
bool is_secondary(base::PassKey<DialogModelHost>) const {
return is_secondary_;
}
bool allow_character_break(base::PassKey<DialogModelHost>) const {
return allow_character_break_;
}
private:
explicit DialogModelLabel(int message_id, std::vector<Link> links);
const int message_id_;
const std::u16string string_;
const std::vector<Link> 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<DialogModelHost> are only intended to be called
// by the DialogModelHost implementation.
Type type(base::PassKey<DialogModelHost>) const { return type_; }
const base::flat_set<Accelerator>& accelerators(
base::PassKey<DialogModelHost>) const {
return accelerators_;
}
int unique_id(base::PassKey<DialogModelHost>) const { return unique_id_; }
DialogModelButton* AsButton(base::PassKey<DialogModelHost>);
DialogModelBodyText* AsBodyText(base::PassKey<DialogModelHost>);
DialogModelCheckbox* AsCheckbox(base::PassKey<DialogModelHost>);
DialogModelCombobox* AsCombobox(base::PassKey<DialogModelHost>);
DialogModelTextfield* AsTextfield(base::PassKey<DialogModelHost>);
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>,
DialogModel* model,
Type type,
int unique_id,
base::flat_set<Accelerator> 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<Accelerator> 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<Accelerator> accelerators_;
};
// Note that this is constructed through a DialogModel which adds it to model
// fields.
DialogModelButton(base::PassKey<DialogModel> pass_key,
DialogModel* model,
base::RepeatingCallback<void(const Event&)> callback,
std::u16string label,
const Params& params);
DialogModelButton(const DialogModelButton&) = delete;
DialogModelButton& operator=(const DialogModelButton&) = delete;
~DialogModelButton() override;
// Methods with base::PassKey<DialogModelHost> are only intended to be called
// by the DialogModelHost implementation.
const std::u16string& label(base::PassKey<DialogModelHost>) const {
return label_;
}
void OnPressed(base::PassKey<DialogModelHost>, const Event& event);
private:
friend class DialogModel;
const std::u16string 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<void(const Event&)> 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<DialogModel> pass_key,
DialogModel* model,
const DialogModelLabel& label);
DialogModelBodyText(const DialogModelBodyText&) = delete;
DialogModelBodyText& operator=(const DialogModelBodyText&) = delete;
~DialogModelBodyText() override;
const DialogModelLabel& label(base::PassKey<DialogModelHost>) 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<DialogModel> 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<DialogModelHost>, bool is_checked);
const DialogModelLabel& label(base::PassKey<DialogModelHost>) const {
return label_;
}
private:
const DialogModelLabel label_;
bool is_checked_;
};
// Field class representing a combobox and corresponding label to describe the
// combobox:
//
// <label> [combobox]
// Ex: Folder [My Bookmarks]
class COMPONENT_EXPORT(UI_BASE) DialogModelCombobox : 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);
Params& SetAccessibleName(std::u16string accessible_name) {
accessible_name_ = std::move(accessible_name);
return *this;
}
// The combobox callback is invoked when an item has been selected. This
// nominally happens when selecting an item in the combobox menu. The
// selection notably does not change by hovering different items in the
// combobox menu or navigating it with up/down keys as long as the menu is
// open.
Params& SetCallback(base::RepeatingClosure callback);
private:
friend class DialogModelCombobox;
int unique_id_ = -1;
std::u16string accessible_name_;
base::RepeatingClosure callback_;
base::flat_set<Accelerator> accelerators_;
};
// Note that this is constructed through a DialogModel which adds it to model
// fields.
DialogModelCombobox(base::PassKey<DialogModel> pass_key,
DialogModel* model,
std::u16string label,
std::unique_ptr<ui::ComboboxModel> combobox_model,
const Params& params);
DialogModelCombobox(const DialogModelCombobox&) = delete;
DialogModelCombobox& operator=(const DialogModelCombobox&) = delete;
~DialogModelCombobox() override;
int selected_index() const { return selected_index_; }
ui::ComboboxModel* combobox_model() { return combobox_model_.get(); }
// Methods with base::PassKey<DialogModelHost> are only intended to be called
// by the DialogModelHost implementation.
const std::u16string& label(base::PassKey<DialogModelHost>) const {
return label_;
}
const std::u16string& accessible_name(base::PassKey<DialogModelHost>) const {
return accessible_name_;
}
void OnSelectedIndexChanged(base::PassKey<DialogModelHost>,
int selected_index);
void OnPerformAction(base::PassKey<DialogModelHost>);
private:
friend class DialogModel;
const std::u16string label_;
const std::u16string accessible_name_;
int selected_index_;
std::unique_ptr<ui::ComboboxModel> combobox_model_;
base::RepeatingClosure callback_;
};
// Field class representing a textfield and corresponding label to describe the
// textfield:
//
// <label> [textfield]
// Ex: Name [My email]
class COMPONENT_EXPORT(UI_BASE) DialogModelTextfield : 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);
Params& SetAccessibleName(std::u16string accessible_name) {
accessible_name_ = std::move(accessible_name);
return *this;
}
private:
friend class DialogModelTextfield;
int unique_id_ = -1;
std::u16string accessible_name_;
base::flat_set<Accelerator> accelerators_;
};
// Note that this is constructed through a DialogModel which adds it to model
// fields.
DialogModelTextfield(base::PassKey<DialogModel> pass_key,
DialogModel* model,
std::u16string label,
std::u16string text,
const Params& params);
DialogModelTextfield(const DialogModelTextfield&) = delete;
DialogModelTextfield& operator=(const DialogModelTextfield&) = delete;
~DialogModelTextfield() override;
const std::u16string& text() const { return text_; }
// Methods with base::PassKey<DialogModelHost> are only intended to be called
// by the DialogModelHost implementation.
const std::u16string& label(base::PassKey<DialogModelHost>) const {
return label_;
}
const std::u16string& accessible_name(base::PassKey<DialogModelHost>) const {
return accessible_name_;
}
void OnTextChanged(base::PassKey<DialogModelHost>, std::u16string text);
private:
friend class DialogModel;
const std::u16string label_;
const std::u16string accessible_name_;
std::u16string text_;
};
} // namespace ui
#endif // UI_BASE_MODELS_DIALOG_MODEL_FIELD_H_