Commit f34b0c09 authored by Peter Boström's avatar Peter Boström Committed by Commit Bot

Remove model_field_id() from DialogModelField

The DialogModelField pointer is instead used to identify the field.

Bug: 1106422
Change-Id: I2cd8ddd5bc4d79f4afa85bce47556fc31299155e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2353408Reviewed-by: default avatarScott Violet <sky@chromium.org>
Commit-Queue: Peter Boström <pbos@chromium.org>
Cr-Commit-Position: refs/heads/master@{#797953}
parent 20c0b349
...@@ -108,18 +108,18 @@ void DialogModel::AddTextfield(base::string16 label, ...@@ -108,18 +108,18 @@ void DialogModel::AddTextfield(base::string16 label,
base::string16 text, base::string16 text,
const DialogModelTextfield::Params& params) { const DialogModelTextfield::Params& params) {
fields_.push_back(std::make_unique<DialogModelTextfield>( fields_.push_back(std::make_unique<DialogModelTextfield>(
ReserveField(), std::move(label), std::move(text), params)); GetPassKey(), this, std::move(label), std::move(text), params));
if (host_) if (host_)
host_->OnModelChanged(this); host_->OnFieldAdded(fields_.back().get());
} }
void DialogModel::AddCombobox(base::string16 label, void DialogModel::AddCombobox(base::string16 label,
std::unique_ptr<ui::ComboboxModel> combobox_model, std::unique_ptr<ui::ComboboxModel> combobox_model,
const DialogModelCombobox::Params& params) { const DialogModelCombobox::Params& params) {
fields_.push_back(std::make_unique<DialogModelCombobox>( fields_.push_back(std::make_unique<DialogModelCombobox>(
ReserveField(), std::move(label), std::move(combobox_model), params)); GetPassKey(), this, std::move(label), std::move(combobox_model), params));
if (host_) if (host_)
host_->OnModelChanged(this); host_->OnFieldAdded(fields_.back().get());
} }
DialogModelField* DialogModel::GetFieldByUniqueId(int unique_id) { DialogModelField* DialogModel::GetFieldByUniqueId(int unique_id) {
...@@ -150,20 +150,10 @@ DialogModelTextfield* DialogModel::GetTextfieldByUniqueId(int unique_id) { ...@@ -150,20 +150,10 @@ DialogModelTextfield* DialogModel::GetTextfieldByUniqueId(int unique_id) {
return static_cast<DialogModelTextfield*>(field); return static_cast<DialogModelTextfield*>(field);
} }
DialogModelButton* DialogModel::GetDialogButton(DialogButton button) {
return GetButtonFromModelFieldId(button);
}
DialogModelButton* DialogModel::GetExtraButton() {
return GetButtonFromModelFieldId(kExtraButtonId);
}
void DialogModel::OnButtonPressed(util::PassKey<DialogModelHost>, void DialogModel::OnButtonPressed(util::PassKey<DialogModelHost>,
int id, DialogModelButton* button,
const Event& event) { const Event& event) {
DCHECK_GT(id, DIALOG_BUTTON_LAST); DCHECK_EQ(button->model_, this);
auto* button = GetButtonFromModelFieldId(id);
if (button->callback_) if (button->callback_)
button->callback_.Run(event); button->callback_.Run(event);
} }
...@@ -184,22 +174,24 @@ void DialogModel::OnDialogClosed(util::PassKey<DialogModelHost>) { ...@@ -184,22 +174,24 @@ void DialogModel::OnDialogClosed(util::PassKey<DialogModelHost>) {
} }
void DialogModel::OnComboboxSelectedIndexChanged(util::PassKey<DialogModelHost>, void DialogModel::OnComboboxSelectedIndexChanged(util::PassKey<DialogModelHost>,
int id, DialogModelCombobox* combobox,
int index) { int index) {
GetComboboxFromModelFieldId(id)->selected_index_ = index; DCHECK_EQ(combobox->model_, this);
combobox->selected_index_ = index;
} }
void DialogModel::OnComboboxPerformAction(util::PassKey<DialogModelHost>, void DialogModel::OnComboboxPerformAction(util::PassKey<DialogModelHost>,
int id) { DialogModelCombobox* combobox) {
auto* model = GetComboboxFromModelFieldId(id); DCHECK_EQ(combobox->model_, this);
if (model->callback_) if (combobox->callback_)
model->callback_.Run(); combobox->callback_.Run();
} }
void DialogModel::OnTextfieldTextChanged(util::PassKey<DialogModelHost>, void DialogModel::OnTextfieldTextChanged(util::PassKey<DialogModelHost>,
int id, DialogModelTextfield* textfield,
base::string16 text) { base::string16 text) {
GetTextfieldFromModelFieldId(id)->text_ = text; DCHECK_EQ(textfield->model_, this);
textfield->text_ = std::move(text);
} }
void DialogModel::OnWindowClosing(util::PassKey<DialogModelHost>) { void DialogModel::OnWindowClosing(util::PassKey<DialogModelHost>) {
...@@ -207,52 +199,26 @@ void DialogModel::OnWindowClosing(util::PassKey<DialogModelHost>) { ...@@ -207,52 +199,26 @@ void DialogModel::OnWindowClosing(util::PassKey<DialogModelHost>) {
std::move(window_closing_callback_).Run(); std::move(window_closing_callback_).Run();
} }
void DialogModel::AddDialogButton(int button, void DialogModel::AddDialogButton(int button_id,
base::string16 label, base::string16 label,
const DialogModelButton::Params& params) { const DialogModelButton::Params& params) {
DCHECK_LE(button, kExtraButtonId);
if (button != kExtraButtonId) // Dialog buttons should use dialog callbacks.
DCHECK(!params.has_callback());
DCHECK(!host_); // Dialog buttons should be added before adding to host. DCHECK(!host_); // Dialog buttons should be added before adding to host.
DCHECK(!GetFieldFromModelFieldId(button)); base::Optional<DialogModelButton>* button = nullptr;
fields_.push_back(std::make_unique<DialogModelButton>( switch (button_id) {
DialogModelField::Reservation(this, button), std::move(label), params)); case ui::DIALOG_BUTTON_OK:
} button = &ok_button_;
break;
DialogModelField* DialogModel::GetFieldFromModelFieldId(int id) { case ui::DIALOG_BUTTON_CANCEL:
for (const auto& field : fields_) { button = &cancel_button_;
if (id == field->model_field_id_) break;
return field.get(); case kExtraButtonId:
button = &extra_button_;
break;
default:
NOTREACHED();
} }
return nullptr; DCHECK(!button->has_value());
} button->emplace(GetPassKey(), this, std::move(label), params);
DialogModelButton* DialogModel::GetButtonFromModelFieldId(int id) {
auto* field = GetFieldFromModelFieldId(id);
DCHECK(field);
DCHECK_EQ(field->type_, DialogModelField::kButton);
return static_cast<DialogModelButton*>(field);
}
DialogModelCombobox* DialogModel::GetComboboxFromModelFieldId(int id) {
auto* field = GetFieldFromModelFieldId(id);
DCHECK(field);
DCHECK_EQ(field->type_, DialogModelField::kCombobox);
return static_cast<DialogModelCombobox*>(field);
}
DialogModelTextfield* DialogModel::GetTextfieldFromModelFieldId(int id) {
auto* field = GetFieldFromModelFieldId(id);
DCHECK(field);
DCHECK_EQ(field->type_, DialogModelField::kTextfield);
return static_cast<DialogModelTextfield*>(field);
}
DialogModelField::Reservation DialogModel::ReserveField() {
const int id = next_field_id_++;
DCHECK(!GetFieldFromModelFieldId(id));
return DialogModelField::Reservation(this, id);
} }
} // namespace ui } // namespace ui
\ No newline at end of file
...@@ -167,24 +167,21 @@ class COMPONENT_EXPORT(UI_BASE) DialogModel final { ...@@ -167,24 +167,21 @@ class COMPONENT_EXPORT(UI_BASE) DialogModel final {
DialogModelCombobox* GetComboboxByUniqueId(int unique_id); DialogModelCombobox* GetComboboxByUniqueId(int unique_id);
DialogModelTextfield* GetTextfieldByUniqueId(int unique_id); DialogModelTextfield* GetTextfieldByUniqueId(int unique_id);
// Get dialog buttons.
DialogModelButton* GetDialogButton(DialogButton button);
DialogModelButton* GetExtraButton();
// Methods with util::PassKey<DialogModelHost> are for host implementations // Methods with util::PassKey<DialogModelHost> are for host implementations
// only. // only.
void OnButtonPressed(util::PassKey<DialogModelHost>, void OnButtonPressed(util::PassKey<DialogModelHost>,
int id, DialogModelButton* field,
const Event& event); const Event& event);
void OnDialogAccepted(util::PassKey<DialogModelHost>); void OnDialogAccepted(util::PassKey<DialogModelHost>);
void OnDialogCancelled(util::PassKey<DialogModelHost>); void OnDialogCancelled(util::PassKey<DialogModelHost>);
void OnDialogClosed(util::PassKey<DialogModelHost>); void OnDialogClosed(util::PassKey<DialogModelHost>);
void OnComboboxPerformAction(util::PassKey<DialogModelHost>, int id); void OnComboboxPerformAction(util::PassKey<DialogModelHost>,
DialogModelCombobox* combobox);
void OnComboboxSelectedIndexChanged(util::PassKey<DialogModelHost>, void OnComboboxSelectedIndexChanged(util::PassKey<DialogModelHost>,
int id, DialogModelCombobox* combobox,
int index); int index);
void OnTextfieldTextChanged(util::PassKey<DialogModelHost>, void OnTextfieldTextChanged(util::PassKey<DialogModelHost>,
int id, DialogModelTextfield* textfield,
base::string16 text); base::string16 text);
void OnWindowClosing(util::PassKey<DialogModelHost>); void OnWindowClosing(util::PassKey<DialogModelHost>);
...@@ -206,6 +203,18 @@ class COMPONENT_EXPORT(UI_BASE) DialogModel final { ...@@ -206,6 +203,18 @@ class COMPONENT_EXPORT(UI_BASE) DialogModel final {
return initially_focused_field_; return initially_focused_field_;
} }
DialogModelButton* ok_button(util::PassKey<DialogModelHost>) {
return ok_button_.has_value() ? &ok_button_.value() : nullptr;
}
DialogModelButton* cancel_button(util::PassKey<DialogModelHost>) {
return cancel_button_.has_value() ? &cancel_button_.value() : nullptr;
}
DialogModelButton* extra_button(util::PassKey<DialogModelHost>) {
return extra_button_.has_value() ? &extra_button_.value() : nullptr;
}
// Accessor for ordered fields in the model. This includes DialogButtons even // Accessor for ordered fields in the model. This includes DialogButtons even
// though they should be handled separately (OK button has fixed position in // though they should be handled separately (OK button has fixed position in
// dialog). // dialog).
...@@ -215,19 +224,14 @@ class COMPONENT_EXPORT(UI_BASE) DialogModel final { ...@@ -215,19 +224,14 @@ class COMPONENT_EXPORT(UI_BASE) DialogModel final {
} }
private: private:
util::PassKey<DialogModel> GetPassKey() {
return util::PassKey<DialogModel>();
}
void AddDialogButton(int button, void AddDialogButton(int button,
base::string16 label, base::string16 label,
const DialogModelButton::Params& params); const DialogModelButton::Params& params);
// TODO(pbos): See if the hosts can just return back the field pointer instead
// so we don't need to do lookup.
DialogModelField* GetFieldFromModelFieldId(int field_id);
DialogModelButton* GetButtonFromModelFieldId(int field_id);
DialogModelCombobox* GetComboboxFromModelFieldId(int field_id);
DialogModelTextfield* GetTextfieldFromModelFieldId(int field_id);
DialogModelField::Reservation ReserveField();
std::unique_ptr<DialogModelDelegate> delegate_; std::unique_ptr<DialogModelDelegate> delegate_;
DialogModelHost* host_ = nullptr; DialogModelHost* host_ = nullptr;
...@@ -235,12 +239,13 @@ class COMPONENT_EXPORT(UI_BASE) DialogModel final { ...@@ -235,12 +239,13 @@ class COMPONENT_EXPORT(UI_BASE) DialogModel final {
base::string16 title_; base::string16 title_;
static constexpr int kExtraButtonId = DIALOG_BUTTON_LAST + 1; static constexpr int kExtraButtonId = DIALOG_BUTTON_LAST + 1;
// kExtraButtonId is the last reserved id (ui::DialogButton are also reserved
// IDs).
int next_field_id_ = kExtraButtonId + 1;
std::vector<std::unique_ptr<DialogModelField>> fields_; std::vector<std::unique_ptr<DialogModelField>> fields_;
base::Optional<int> initially_focused_field_; base::Optional<int> initially_focused_field_;
base::Optional<DialogModelButton> ok_button_;
base::Optional<DialogModelButton> cancel_button_;
base::Optional<DialogModelButton> extra_button_;
base::OnceClosure accept_callback_; base::OnceClosure accept_callback_;
base::OnceClosure cancel_callback_; base::OnceClosure cancel_callback_;
base::OnceClosure close_callback_; base::OnceClosure close_callback_;
......
...@@ -7,13 +7,12 @@ ...@@ -7,13 +7,12 @@
namespace ui { namespace ui {
DialogModelField::DialogModelField( DialogModelField::DialogModelField(util::PassKey<DialogModel>,
const DialogModelField::Reservation& reservation, DialogModel* model,
DialogModelField::Type type, Type type,
int unique_id, int unique_id,
base::flat_set<Accelerator> accelerators) base::flat_set<Accelerator> accelerators)
: model_(reservation.model), : model_(model),
model_field_id_(reservation.model_field_id),
type_(type), type_(type),
unique_id_(unique_id), unique_id_(unique_id),
accelerators_(std::move(accelerators)) { accelerators_(std::move(accelerators)) {
...@@ -22,9 +21,6 @@ DialogModelField::DialogModelField( ...@@ -22,9 +21,6 @@ DialogModelField::DialogModelField(
DialogModelField::~DialogModelField() = default; DialogModelField::~DialogModelField() = default;
DialogModelField::Reservation::Reservation(DialogModel* model,
int model_field_id)
: model(model), model_field_id(model_field_id) {}
DialogModelButton::Params::Params() = default; DialogModelButton::Params::Params() = default;
DialogModelButton::Params::~Params() = default; DialogModelButton::Params::~Params() = default;
...@@ -41,11 +37,12 @@ DialogModelButton::Params& DialogModelButton::Params::SetCallback( ...@@ -41,11 +37,12 @@ DialogModelButton::Params& DialogModelButton::Params::SetCallback(
return *this; return *this;
} }
DialogModelButton::DialogModelButton( DialogModelButton::DialogModelButton(util::PassKey<DialogModel> pass_key,
const DialogModelField::Reservation& reservation, DialogModel* model,
base::string16 label, base::string16 label,
const DialogModelButton::Params& params) const DialogModelButton::Params& params)
: DialogModelField(reservation, : DialogModelField(pass_key,
model,
kButton, kButton,
params.unique_id_, params.unique_id_,
params.accelerators_), params.accelerators_),
...@@ -83,11 +80,13 @@ DialogModelCombobox::Params& DialogModelCombobox::Params::SetAccessibleName( ...@@ -83,11 +80,13 @@ DialogModelCombobox::Params& DialogModelCombobox::Params::SetAccessibleName(
} }
DialogModelCombobox::DialogModelCombobox( DialogModelCombobox::DialogModelCombobox(
const DialogModelField::Reservation& reservation, util::PassKey<DialogModel> pass_key,
DialogModel* model,
base::string16 label, base::string16 label,
std::unique_ptr<ui::ComboboxModel> combobox_model, std::unique_ptr<ui::ComboboxModel> combobox_model,
const DialogModelCombobox::Params& params) const DialogModelCombobox::Params& params)
: DialogModelField(reservation, : DialogModelField(pass_key,
model,
kCombobox, kCombobox,
params.unique_id_, params.unique_id_,
params.accelerators_), params.accelerators_),
...@@ -122,11 +121,13 @@ DialogModelTextfield::Params& DialogModelTextfield::Params::SetAccessibleName( ...@@ -122,11 +121,13 @@ DialogModelTextfield::Params& DialogModelTextfield::Params::SetAccessibleName(
} }
DialogModelTextfield::DialogModelTextfield( DialogModelTextfield::DialogModelTextfield(
const DialogModelField::Reservation& reservation, util::PassKey<DialogModel> pass_key,
DialogModel* model,
base::string16 label, base::string16 label,
base::string16 text, base::string16 text,
const ui::DialogModelTextfield::Params& params) const ui::DialogModelTextfield::Params& params)
: DialogModelField(reservation, : DialogModelField(pass_key,
model,
kTextfield, kTextfield,
params.unique_id_, params.unique_id_,
params.accelerators_), params.accelerators_),
......
...@@ -36,59 +36,26 @@ class COMPONENT_EXPORT(UI_BASE) DialogModelField { ...@@ -36,59 +36,26 @@ class COMPONENT_EXPORT(UI_BASE) DialogModelField {
// Accessors with util::PassKey<DialogModelHost> are only intended to be read // Accessors with util::PassKey<DialogModelHost> are only intended to be read
// by the DialogModelHost implementation. // by the DialogModelHost implementation.
Type type(util::PassKey<DialogModelHost>) const { return type_; }
const base::flat_set<Accelerator>& accelerators( const base::flat_set<Accelerator>& accelerators(
util::PassKey<DialogModelHost>) const { util::PassKey<DialogModelHost>) const {
return accelerators_; return accelerators_;
} }
// Reserved ID generated by the model. This ID is generated for every field
// and used to map from DialogModelHost fields (like views::Textfield) to
// DialogModelFields (like DialogModelTextfield).
// WARNING: This should not be confused with the ID set by subclasses'
// Params::SetUniqueId() methods.
// TODO(pbos): See if this int-to-field mapping can be replaced with using
// DialogModelField pointers in DialogModelHost. This is currently only used
// because views has a convenient views::View::SetID() function.
int model_field_id(util::PassKey<DialogModelHost>) const {
return model_field_id_;
}
Type type(util::PassKey<DialogModelHost>) const { return type_; }
protected: protected:
// Struct that holds a reserved ID for the field in the model. This is // Children of this class need to be constructed through DialogModel to help
// protected to be able to be passed from DialogModelField children to the // enforce that they're added to the model.
// parent constructor. Its members are private because only DialogModel, DialogModelField(util::PassKey<DialogModel>,
// DialogModelField and DialogModelHost should be able to read them. DialogModel* model,
// TODO(pbos): Reconsider whether this |model_field_id| can be avoided. This
// would take rewiring DialogModelHost to own a mapping between
// "DialogModelField*" and host classes (such as View) and not rely on things
// like View::SetID(model_field_id) to maintain that mapping. It would also
// require special handling of special buttons like DIALOG_BUTTON_OK.
struct Reservation {
private:
friend class DialogModel;
friend class DialogModelField;
// This is only to be constructed by DialogModel who makes the actual
// ID assignment.
Reservation(DialogModel* model, int model_field_id);
DialogModel* const model;
const int model_field_id;
};
DialogModelField(const Reservation& reservation,
Type type, Type type,
int unique_id, int unique_id,
base::flat_set<Accelerator> accelerators); base::flat_set<Accelerator> accelerators);
int model_field_id() const { return model_field_id_; }
private: private:
friend class DialogModel; friend class DialogModel;
DialogModel* const model_; DialogModel* const model_;
const int model_field_id_;
const Type type_; const Type type_;
const int unique_id_; const int unique_id_;
const base::flat_set<Accelerator> accelerators_; const base::flat_set<Accelerator> accelerators_;
...@@ -124,9 +91,10 @@ class COMPONENT_EXPORT(UI_BASE) DialogModelButton : public DialogModelField { ...@@ -124,9 +91,10 @@ class COMPONENT_EXPORT(UI_BASE) DialogModelButton : public DialogModelField {
base::flat_set<Accelerator> accelerators_; base::flat_set<Accelerator> accelerators_;
}; };
// Note that this is constructed through a DialogModel (Reservation can't // Note that this is constructed through a DialogModel which adds it to model
// be created without one). // fields.
DialogModelButton(const Reservation& reservation, DialogModelButton(util::PassKey<DialogModel> pass_key,
DialogModel* model,
base::string16 label, base::string16 label,
const Params& params); const Params& params);
DialogModelButton(const DialogModelButton&) = delete; DialogModelButton(const DialogModelButton&) = delete;
...@@ -178,9 +146,10 @@ class COMPONENT_EXPORT(UI_BASE) DialogModelCombobox : public DialogModelField { ...@@ -178,9 +146,10 @@ class COMPONENT_EXPORT(UI_BASE) DialogModelCombobox : public DialogModelField {
base::flat_set<Accelerator> accelerators_; base::flat_set<Accelerator> accelerators_;
}; };
// Note that this is constructed through a DialogModel (Reservation can't // Note that this is constructed through a DialogModel which adds it to model
// be created without one). // fields.
DialogModelCombobox(const Reservation& reservation, DialogModelCombobox(util::PassKey<DialogModel> pass_key,
DialogModel* model,
base::string16 label, base::string16 label,
std::unique_ptr<ui::ComboboxModel> combobox_model, std::unique_ptr<ui::ComboboxModel> combobox_model,
const Params& params); const Params& params);
...@@ -230,9 +199,10 @@ class COMPONENT_EXPORT(UI_BASE) DialogModelTextfield : public DialogModelField { ...@@ -230,9 +199,10 @@ class COMPONENT_EXPORT(UI_BASE) DialogModelTextfield : public DialogModelField {
base::flat_set<Accelerator> accelerators_; base::flat_set<Accelerator> accelerators_;
}; };
// Note that this is constructed through a DialogModel (Reservation can't // Note that this is constructed through a DialogModel which adds it to model
// be created without one). // fields.
DialogModelTextfield(const DialogModelField::Reservation& reservation, DialogModelTextfield(util::PassKey<DialogModel> pass_key,
DialogModel* model,
base::string16 label, base::string16 label,
base::string16 text, base::string16 text,
const Params& params); const Params& params);
......
...@@ -37,7 +37,7 @@ class COMPONENT_EXPORT(UI_BASE) DialogModelHost { ...@@ -37,7 +37,7 @@ class COMPONENT_EXPORT(UI_BASE) DialogModelHost {
// Called when various parts of the model changes. // Called when various parts of the model changes.
// TODO(pbos): Break this down to API that says what was added/removed/changed // TODO(pbos): Break this down to API that says what was added/removed/changed
// to not have to reset everything. // to not have to reset everything.
virtual void OnModelChanged(DialogModel* model) = 0; virtual void OnFieldAdded(DialogModelField* field) = 0;
}; };
} // namespace ui } // namespace ui
......
...@@ -56,35 +56,34 @@ BubbleDialogModelHost::BubbleDialogModelHost( ...@@ -56,35 +56,34 @@ BubbleDialogModelHost::BubbleDialogModelHost(
base::Unretained(model_.get()), GetPassKey())); base::Unretained(model_.get()), GetPassKey()));
int button_mask = ui::DIALOG_BUTTON_NONE; int button_mask = ui::DIALOG_BUTTON_NONE;
auto* ok_button = model_->ok_button(GetPassKey());
if (ok_button) {
button_mask |= ui::DIALOG_BUTTON_OK;
if (!ok_button->label().empty())
SetButtonLabel(ui::DIALOG_BUTTON_OK, ok_button->label());
}
// TODO(pbos): Separate dialog buttons from fields. This is not nice. auto* cancel_button = model_->cancel_button(GetPassKey());
for (const auto& field : model_->fields(GetPassKey())) { if (cancel_button) {
if (field->type(GetPassKey()) != ui::DialogModelField::kButton) button_mask |= ui::DIALOG_BUTTON_CANCEL;
continue; if (!cancel_button->label().empty())
SetButtonLabel(ui::DIALOG_BUTTON_CANCEL, cancel_button->label());
}
const auto* button = static_cast<const ui::DialogModelButton*>(field.get()); auto* extra_button = model_->extra_button(GetPassKey());
if (field->model_field_id(GetPassKey()) > ui::DIALOG_BUTTON_LAST) { if (extra_button) {
DCHECK_EQ(button, model_->GetExtraButton()); auto extra_view =
auto extra_button = std::make_unique<views::MdTextButton>(this, extra_button->label());
std::make_unique<views::MdTextButton>(this, button->label()); view_to_field_[extra_view.get()] = extra_button;
extra_button->SetID(field->model_field_id(GetPassKey())); SetExtraView(std::move(extra_view));
SetExtraView(std::move(extra_button)); }
continue; SetButtons(button_mask);
}
button_mask |= field->model_field_id(GetPassKey()); WidgetDelegate::SetTitle(model_->title(GetPassKey()));
SetButtons(button_mask); WidgetDelegate::SetShowCloseButton(model_->show_close_button(GetPassKey()));
if (!button->label().empty()) {
SetButtonLabel(
static_cast<ui::DialogButton>(field->model_field_id(GetPassKey())),
button->label());
}
}
// Populate dialog using the observer functions to make sure they use the same AddInitialFields();
// code path as updates.
OnModelChanged(model_.get());
} }
BubbleDialogModelHost::~BubbleDialogModelHost() { BubbleDialogModelHost::~BubbleDialogModelHost() {
...@@ -93,21 +92,25 @@ BubbleDialogModelHost::~BubbleDialogModelHost() { ...@@ -93,21 +92,25 @@ BubbleDialogModelHost::~BubbleDialogModelHost() {
} }
View* BubbleDialogModelHost::GetInitiallyFocusedView() { View* BubbleDialogModelHost::GetInitiallyFocusedView() {
if (model_->initially_focused_field(GetPassKey())) { ui::DialogModelField* focused_field = model_->GetTextfieldByUniqueId(
// TODO(pbos): Update this so that it works for dialog buttons. *model_->initially_focused_field(GetPassKey()));
View* focused_view = GetViewByID(
model_ if (!focused_field)
->GetFieldByUniqueId(*model_->initially_focused_field(GetPassKey())) return BubbleDialogDelegateView::GetInitiallyFocusedView();
->model_field_id(GetPassKey()));
// The dialog should be populated now so this should correspond to a view return FieldToView(focused_field);
// with this ID.
DCHECK(focused_view);
return focused_view;
}
return BubbleDialogDelegateView::GetInitiallyFocusedView();
} }
void BubbleDialogModelHost::OnDialogInitialized() { void BubbleDialogModelHost::OnDialogInitialized() {
// Dialog buttons are added on dialog initialization.
auto* ok_button = model_->ok_button(GetPassKey());
if (ok_button)
view_to_field_[GetOkButton()] = ok_button;
auto* cancel_button = model_->cancel_button(GetPassKey());
if (cancel_button)
view_to_field_[GetCancelButton()] = cancel_button;
UpdateAccelerators(); UpdateAccelerators();
} }
...@@ -119,24 +122,22 @@ void BubbleDialogModelHost::Close() { ...@@ -119,24 +122,22 @@ void BubbleDialogModelHost::Close() {
void BubbleDialogModelHost::SelectAllText(int unique_id) { void BubbleDialogModelHost::SelectAllText(int unique_id) {
static_cast<Textfield*>( static_cast<Textfield*>(
GetViewByID(model_->GetTextfieldByUniqueId(unique_id)->model_field_id( FieldToView(model_->GetTextfieldByUniqueId(unique_id)))
GetPassKey())))
->SelectAll(false); ->SelectAll(false);
} }
void BubbleDialogModelHost::OnModelChanged(ui::DialogModel* model) { void BubbleDialogModelHost::OnFieldAdded(ui::DialogModelField* field) {
DCHECK(model == model_.get()); // TODO(pbos): Add support for adding fields while the model is hosted.
WidgetDelegate::SetTitle(model->title(GetPassKey())); NOTREACHED();
WidgetDelegate::SetShowCloseButton(model->show_close_button(GetPassKey())); }
void BubbleDialogModelHost::AddInitialFields() {
// TODO(pbos): Turn this method into consecutive OnFieldAdded(field) calls.
// TODO(pbos): When fixing the DCHECK below, keep views and update them. This DCHECK(children().empty()) << "This should only be called once.";
// is required to maintain view focus, for instance. Do not remove all
// children and recreate. Needs to dynamically insert/remove GridLayout rows.
DCHECK(children().empty()) << "TODO(pbos): Support changing the model after "
"host creation...";
bool first_row = true; bool first_row = true;
const auto& fields = model->fields(GetPassKey()); const auto& fields = model_->fields(GetPassKey());
const DialogContentType first_field_content_type = const DialogContentType first_field_content_type =
fields.empty() fields.empty()
? DialogContentType::CONTROL ? DialogContentType::CONTROL
...@@ -151,32 +152,29 @@ void BubbleDialogModelHost::OnModelChanged(ui::DialogModel* model) { ...@@ -151,32 +152,29 @@ void BubbleDialogModelHost::OnModelChanged(ui::DialogModel* model) {
GetGridLayout()->AddPaddingRow(GridLayout::kFixedSize, 12); GetGridLayout()->AddPaddingRow(GridLayout::kFixedSize, 12);
} }
View* last_field = nullptr; View* last_view = nullptr;
switch (field->type(GetPassKey())) { switch (field->type(GetPassKey())) {
case ui::DialogModelField::kButton: case ui::DialogModelField::kButton:
// TODO(pbos): Add support for buttons that are part of content area. // TODO(pbos): Add support for buttons that are part of content area.
continue; continue;
case ui::DialogModelField::kTextfield: case ui::DialogModelField::kTextfield:
last_field = AddOrUpdateTextfield( last_view = AddOrUpdateTextfield(FieldAsTextfield(field.get()));
static_cast<const ui::DialogModelTextfield&>(*field));
break; break;
case ui::DialogModelField::kCombobox: case ui::DialogModelField::kCombobox:
last_field = AddOrUpdateCombobox( last_view = AddOrUpdateCombobox(FieldAsCombobox(field.get()));
static_cast<ui::DialogModelCombobox*>(field.get()));
break; break;
} }
DCHECK(last_field); DCHECK(last_view);
last_field->SetID(field->model_field_id(GetPassKey())); view_to_field_[last_view] = field.get();
last_field_content_type = FieldTypeToContentType(field->type(GetPassKey())); last_field_content_type = FieldTypeToContentType(field->type(GetPassKey()));
// TODO(pbos): Update logic here when mixing types. // TODO(pbos): Update logic here when mixing types.
first_row = false; first_row = false;
} }
set_margins(LayoutProvider::Get()->GetDialogInsetsForContentType( set_margins(LayoutProvider::Get()->GetDialogInsetsForContentType(
first_field_content_type, last_field_content_type)); first_field_content_type, last_field_content_type));
UpdateAccelerators();
} }
GridLayout* BubbleDialogModelHost::GetGridLayout() { GridLayout* BubbleDialogModelHost::GetGridLayout() {
...@@ -200,24 +198,21 @@ void BubbleDialogModelHost::ConfigureGridLayout() { ...@@ -200,24 +198,21 @@ void BubbleDialogModelHost::ConfigureGridLayout() {
} }
Textfield* BubbleDialogModelHost::AddOrUpdateTextfield( Textfield* BubbleDialogModelHost::AddOrUpdateTextfield(
const ui::DialogModelTextfield& model) { ui::DialogModelTextfield* model) {
// TODO(pbos): Handle updating existing field. // TODO(pbos): Support updates to the existing model.
DCHECK(!GetViewByID(model.model_field_id(GetPassKey())))
<< "BubbleDialogModelHost doesn't yet support updates to the model";
auto textfield = std::make_unique<Textfield>(); auto textfield = std::make_unique<Textfield>();
textfield->SetAccessibleName( textfield->SetAccessibleName(model->accessible_name().empty()
model.accessible_name().empty() ? model.text() : model.accessible_name()); ? model->text()
textfield->SetText(model.text()); : model->accessible_name());
textfield->SetText(model->text());
property_changed_subscriptions_.push_back( property_changed_subscriptions_.push_back(textfield->AddTextChangedCallback(
textfield->AddTextChangedCallback(base::BindRepeating( base::BindRepeating(&BubbleDialogModelHost::NotifyTextfieldTextChanged,
&BubbleDialogModelHost::NotifyTextfieldTextChanged, base::Unretained(this), textfield.get())));
base::Unretained(this), model.model_field_id(GetPassKey()),
textfield.get())));
auto* textfield_ptr = textfield.get(); auto* textfield_ptr = textfield.get();
AddLabelAndField(model.label(), std::move(textfield), AddLabelAndField(model->label(), std::move(textfield),
textfield_ptr->GetFontList()); textfield_ptr->GetFontList());
return textfield_ptr; return textfield_ptr;
...@@ -226,8 +221,6 @@ Textfield* BubbleDialogModelHost::AddOrUpdateTextfield( ...@@ -226,8 +221,6 @@ Textfield* BubbleDialogModelHost::AddOrUpdateTextfield(
Combobox* BubbleDialogModelHost::AddOrUpdateCombobox( Combobox* BubbleDialogModelHost::AddOrUpdateCombobox(
ui::DialogModelCombobox* model) { ui::DialogModelCombobox* model) {
// TODO(pbos): Handle updating existing field. // TODO(pbos): Handle updating existing field.
DCHECK(!GetViewByID(model->model_field_id(GetPassKey())))
<< "BubbleDialogModelHost doesn't yet support updates to the model";
auto combobox = std::make_unique<Combobox>(model->combobox_model()); auto combobox = std::make_unique<Combobox>(model->combobox_model());
combobox->SetAccessibleName(model->accessible_name().empty() combobox->SetAccessibleName(model->accessible_name().empty()
...@@ -257,29 +250,32 @@ void BubbleDialogModelHost::AddLabelAndField(const base::string16& label_text, ...@@ -257,29 +250,32 @@ void BubbleDialogModelHost::AddLabelAndField(const base::string16& label_text,
layout->AddView(std::move(field)); layout->AddView(std::move(field));
} }
void BubbleDialogModelHost::NotifyTextfieldTextChanged(int id, void BubbleDialogModelHost::NotifyTextfieldTextChanged(Textfield* textfield) {
Textfield* textfield) { model_->OnTextfieldTextChanged(GetPassKey(),
model_->OnTextfieldTextChanged(GetPassKey(), id, textfield->GetText()); FieldAsTextfield(view_to_field_[textfield]),
textfield->GetText());
} }
void BubbleDialogModelHost::NotifyComboboxSelectedIndexChanged( void BubbleDialogModelHost::NotifyComboboxSelectedIndexChanged(
int id,
Combobox* combobox) { Combobox* combobox) {
model_->OnComboboxSelectedIndexChanged(GetPassKey(), id, model_->OnComboboxSelectedIndexChanged(
combobox->GetSelectedIndex()); GetPassKey(), FieldAsCombobox(view_to_field_[combobox]),
combobox->GetSelectedIndex());
} }
void BubbleDialogModelHost::ButtonPressed(Button* sender, void BubbleDialogModelHost::ButtonPressed(Button* sender,
const ui::Event& event) { const ui::Event& event) {
model_->OnButtonPressed(GetPassKey(), sender->GetID(), event); model_->OnButtonPressed(GetPassKey(), FieldAsButton(view_to_field_[sender]),
event);
} }
void BubbleDialogModelHost::OnPerformAction(Combobox* combobox) { void BubbleDialogModelHost::OnPerformAction(Combobox* combobox) {
// TODO(pbos): This should be a subscription through the Combobox directly, // TODO(pbos): This should be a subscription through the Combobox directly,
// but Combobox right now doesn't support listening to selected-index changes. // but Combobox right now doesn't support listening to selected-index changes.
NotifyComboboxSelectedIndexChanged(combobox->GetID(), combobox); NotifyComboboxSelectedIndexChanged(combobox);
model_->OnComboboxPerformAction(GetPassKey(), combobox->GetID()); model_->OnComboboxPerformAction(GetPassKey(),
FieldAsCombobox(view_to_field_[combobox]));
} }
void BubbleDialogModelHost::UpdateAccelerators() { void BubbleDialogModelHost::UpdateAccelerators() {
...@@ -287,25 +283,45 @@ void BubbleDialogModelHost::UpdateAccelerators() { ...@@ -287,25 +283,45 @@ void BubbleDialogModelHost::UpdateAccelerators() {
// ::OnDialogInitialized(). // ::OnDialogInitialized().
if (!GetWidget()) if (!GetWidget())
return; return;
for (const auto& field : model_->fields(GetPassKey())) {
if (field->accelerators(GetPassKey()).empty()) for (auto& kv : view_to_field_) {
continue; View* const view = kv.first;
View* view = nullptr;
if (field->model_field_id(GetPassKey()) == ui::DIALOG_BUTTON_OK) {
view = GetOkButton();
} else if (field->model_field_id(GetPassKey()) ==
ui::DIALOG_BUTTON_CANCEL) {
view = GetCancelButton();
} else if (field.get() == model_->GetExtraButton()) {
view = GetExtraView();
} else {
view = GetViewByID(field->model_field_id(GetPassKey()));
}
DCHECK(view);
view->ResetAccelerators(); view->ResetAccelerators();
for (const auto& accelerator : field->accelerators(GetPassKey())) for (const auto& accelerator : kv.second->accelerators(GetPassKey()))
view->AddAccelerator(accelerator); view->AddAccelerator(accelerator);
} }
} }
View* BubbleDialogModelHost::FieldToView(ui::DialogModelField* field) {
DCHECK(field);
for (auto& kv : view_to_field_) {
if (kv.second == field)
return kv.first;
}
NOTREACHED();
return nullptr;
}
ui::DialogModelButton* BubbleDialogModelHost::FieldAsButton(
ui::DialogModelField* field) {
DCHECK(field);
DCHECK_EQ(field->type(GetPassKey()), ui::DialogModelField::kButton);
return static_cast<ui::DialogModelButton*>(field);
}
ui::DialogModelCombobox* BubbleDialogModelHost::FieldAsCombobox(
ui::DialogModelField* field) {
DCHECK(field);
DCHECK_EQ(field->type(GetPassKey()), ui::DialogModelField::kCombobox);
return static_cast<ui::DialogModelCombobox*>(field);
}
ui::DialogModelTextfield* BubbleDialogModelHost::FieldAsTextfield(
ui::DialogModelField* field) {
DCHECK(field);
DCHECK_EQ(field->type(GetPassKey()), ui::DialogModelField::kTextfield);
return static_cast<ui::DialogModelTextfield*>(field);
}
} // namespace views } // namespace views
...@@ -20,7 +20,7 @@ class GridLayout; ...@@ -20,7 +20,7 @@ class GridLayout;
class Textfield; class Textfield;
// BubbleDialogModelHost is a views implementation of ui::DialogModelHost which // BubbleDialogModelHost is a views implementation of ui::DialogModelHost which
// hosts a ui::DialogModels as a BubbleDialogDelegateView. This exposes // hosts a ui::DialogModel as a BubbleDialogDelegateView. This exposes
// views-specific methods such as SetAnchorView(), SetArrow() and // views-specific methods such as SetAnchorView(), SetArrow() and
// SetHighlightedButton(). For methods that are reflected in ui::DialogModelHost // SetHighlightedButton(). For methods that are reflected in ui::DialogModelHost
// (such as ::Close()), preferusing the ui::DialogModelHost to avoid // (such as ::Close()), preferusing the ui::DialogModelHost to avoid
...@@ -49,8 +49,7 @@ class VIEWS_EXPORT BubbleDialogModelHost : public BubbleDialogDelegateView, ...@@ -49,8 +49,7 @@ class VIEWS_EXPORT BubbleDialogModelHost : public BubbleDialogDelegateView,
// ui::DialogModelHost: // ui::DialogModelHost:
void Close() override; void Close() override;
void SelectAllText(int unique_id) override; void SelectAllText(int unique_id) override;
void OnFieldAdded(ui::DialogModelField* field) override;
void OnModelChanged(ui::DialogModel* model) override;
// ButtonListener: // ButtonListener:
void ButtonPressed(views::Button* sender, const ui::Event& event) override; void ButtonPressed(views::Button* sender, const ui::Event& event) override;
...@@ -62,7 +61,8 @@ class VIEWS_EXPORT BubbleDialogModelHost : public BubbleDialogDelegateView, ...@@ -62,7 +61,8 @@ class VIEWS_EXPORT BubbleDialogModelHost : public BubbleDialogDelegateView,
GridLayout* GetGridLayout(); GridLayout* GetGridLayout();
void ConfigureGridLayout(); void ConfigureGridLayout();
Textfield* AddOrUpdateTextfield(const ui::DialogModelTextfield& field); void AddInitialFields();
Textfield* AddOrUpdateTextfield(ui::DialogModelTextfield* field);
Combobox* AddOrUpdateCombobox(ui::DialogModelCombobox* field); Combobox* AddOrUpdateCombobox(ui::DialogModelCombobox* field);
void AddLabelAndField(const base::string16& label_text, void AddLabelAndField(const base::string16& label_text,
std::unique_ptr<views::View> field, std::unique_ptr<views::View> field,
...@@ -70,10 +70,17 @@ class VIEWS_EXPORT BubbleDialogModelHost : public BubbleDialogDelegateView, ...@@ -70,10 +70,17 @@ class VIEWS_EXPORT BubbleDialogModelHost : public BubbleDialogDelegateView,
void UpdateAccelerators(); void UpdateAccelerators();
void NotifyTextfieldTextChanged(int id, views::Textfield* textfield); void NotifyTextfieldTextChanged(views::Textfield* textfield);
void NotifyComboboxSelectedIndexChanged(int id, views::Combobox* combobox); void NotifyComboboxSelectedIndexChanged(views::Combobox* combobox);
View* FieldToView(ui::DialogModelField* field);
ui::DialogModelButton* FieldAsButton(ui::DialogModelField* field);
ui::DialogModelCombobox* FieldAsCombobox(ui::DialogModelField* field);
ui::DialogModelTextfield* FieldAsTextfield(ui::DialogModelField* field);
std::unique_ptr<ui::DialogModel> model_; std::unique_ptr<ui::DialogModel> model_;
base::flat_map<View*, ui::DialogModelField*> view_to_field_;
std::vector<PropertyChangedSubscription> property_changed_subscriptions_; std::vector<PropertyChangedSubscription> property_changed_subscriptions_;
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment