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,
base::string16 text,
const DialogModelTextfield::Params& params) {
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_)
host_->OnModelChanged(this);
host_->OnFieldAdded(fields_.back().get());
}
void DialogModel::AddCombobox(base::string16 label,
std::unique_ptr<ui::ComboboxModel> combobox_model,
const DialogModelCombobox::Params& params) {
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_)
host_->OnModelChanged(this);
host_->OnFieldAdded(fields_.back().get());
}
DialogModelField* DialogModel::GetFieldByUniqueId(int unique_id) {
......@@ -150,20 +150,10 @@ DialogModelTextfield* DialogModel::GetTextfieldByUniqueId(int unique_id) {
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>,
int id,
DialogModelButton* button,
const Event& event) {
DCHECK_GT(id, DIALOG_BUTTON_LAST);
auto* button = GetButtonFromModelFieldId(id);
DCHECK_EQ(button->model_, this);
if (button->callback_)
button->callback_.Run(event);
}
......@@ -184,22 +174,24 @@ void DialogModel::OnDialogClosed(util::PassKey<DialogModelHost>) {
}
void DialogModel::OnComboboxSelectedIndexChanged(util::PassKey<DialogModelHost>,
int id,
DialogModelCombobox* combobox,
int index) {
GetComboboxFromModelFieldId(id)->selected_index_ = index;
DCHECK_EQ(combobox->model_, this);
combobox->selected_index_ = index;
}
void DialogModel::OnComboboxPerformAction(util::PassKey<DialogModelHost>,
int id) {
auto* model = GetComboboxFromModelFieldId(id);
if (model->callback_)
model->callback_.Run();
DialogModelCombobox* combobox) {
DCHECK_EQ(combobox->model_, this);
if (combobox->callback_)
combobox->callback_.Run();
}
void DialogModel::OnTextfieldTextChanged(util::PassKey<DialogModelHost>,
int id,
DialogModelTextfield* textfield,
base::string16 text) {
GetTextfieldFromModelFieldId(id)->text_ = text;
DCHECK_EQ(textfield->model_, this);
textfield->text_ = std::move(text);
}
void DialogModel::OnWindowClosing(util::PassKey<DialogModelHost>) {
......@@ -207,52 +199,26 @@ void DialogModel::OnWindowClosing(util::PassKey<DialogModelHost>) {
std::move(window_closing_callback_).Run();
}
void DialogModel::AddDialogButton(int button,
void DialogModel::AddDialogButton(int button_id,
base::string16 label,
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(!GetFieldFromModelFieldId(button));
fields_.push_back(std::make_unique<DialogModelButton>(
DialogModelField::Reservation(this, button), std::move(label), params));
}
DialogModelField* DialogModel::GetFieldFromModelFieldId(int id) {
for (const auto& field : fields_) {
if (id == field->model_field_id_)
return field.get();
base::Optional<DialogModelButton>* button = nullptr;
switch (button_id) {
case ui::DIALOG_BUTTON_OK:
button = &ok_button_;
break;
case ui::DIALOG_BUTTON_CANCEL:
button = &cancel_button_;
break;
case kExtraButtonId:
button = &extra_button_;
break;
default:
NOTREACHED();
}
return nullptr;
}
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);
DCHECK(!button->has_value());
button->emplace(GetPassKey(), this, std::move(label), params);
}
} // namespace ui
\ No newline at end of file
......@@ -167,24 +167,21 @@ class COMPONENT_EXPORT(UI_BASE) DialogModel final {
DialogModelCombobox* GetComboboxByUniqueId(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
// only.
void OnButtonPressed(util::PassKey<DialogModelHost>,
int id,
DialogModelButton* field,
const Event& event);
void OnDialogAccepted(util::PassKey<DialogModelHost>);
void OnDialogCancelled(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>,
int id,
DialogModelCombobox* combobox,
int index);
void OnTextfieldTextChanged(util::PassKey<DialogModelHost>,
int id,
DialogModelTextfield* textfield,
base::string16 text);
void OnWindowClosing(util::PassKey<DialogModelHost>);
......@@ -206,6 +203,18 @@ class COMPONENT_EXPORT(UI_BASE) DialogModel final {
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
// though they should be handled separately (OK button has fixed position in
// dialog).
......@@ -215,19 +224,14 @@ class COMPONENT_EXPORT(UI_BASE) DialogModel final {
}
private:
util::PassKey<DialogModel> GetPassKey() {
return util::PassKey<DialogModel>();
}
void AddDialogButton(int button,
base::string16 label,
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_;
DialogModelHost* host_ = nullptr;
......@@ -235,12 +239,13 @@ class COMPONENT_EXPORT(UI_BASE) DialogModel final {
base::string16 title_;
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_;
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 cancel_callback_;
base::OnceClosure close_callback_;
......
......@@ -7,13 +7,12 @@
namespace ui {
DialogModelField::DialogModelField(
const DialogModelField::Reservation& reservation,
DialogModelField::Type type,
DialogModelField::DialogModelField(util::PassKey<DialogModel>,
DialogModel* model,
Type type,
int unique_id,
base::flat_set<Accelerator> accelerators)
: model_(reservation.model),
model_field_id_(reservation.model_field_id),
: model_(model),
type_(type),
unique_id_(unique_id),
accelerators_(std::move(accelerators)) {
......@@ -22,9 +21,6 @@ DialogModelField::DialogModelField(
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;
......@@ -41,11 +37,12 @@ DialogModelButton::Params& DialogModelButton::Params::SetCallback(
return *this;
}
DialogModelButton::DialogModelButton(
const DialogModelField::Reservation& reservation,
DialogModelButton::DialogModelButton(util::PassKey<DialogModel> pass_key,
DialogModel* model,
base::string16 label,
const DialogModelButton::Params& params)
: DialogModelField(reservation,
: DialogModelField(pass_key,
model,
kButton,
params.unique_id_,
params.accelerators_),
......@@ -83,11 +80,13 @@ DialogModelCombobox::Params& DialogModelCombobox::Params::SetAccessibleName(
}
DialogModelCombobox::DialogModelCombobox(
const DialogModelField::Reservation& reservation,
util::PassKey<DialogModel> pass_key,
DialogModel* model,
base::string16 label,
std::unique_ptr<ui::ComboboxModel> combobox_model,
const DialogModelCombobox::Params& params)
: DialogModelField(reservation,
: DialogModelField(pass_key,
model,
kCombobox,
params.unique_id_,
params.accelerators_),
......@@ -122,11 +121,13 @@ DialogModelTextfield::Params& DialogModelTextfield::Params::SetAccessibleName(
}
DialogModelTextfield::DialogModelTextfield(
const DialogModelField::Reservation& reservation,
util::PassKey<DialogModel> pass_key,
DialogModel* model,
base::string16 label,
base::string16 text,
const ui::DialogModelTextfield::Params& params)
: DialogModelField(reservation,
: DialogModelField(pass_key,
model,
kTextfield,
params.unique_id_,
params.accelerators_),
......
......@@ -36,59 +36,26 @@ class COMPONENT_EXPORT(UI_BASE) DialogModelField {
// Accessors with util::PassKey<DialogModelHost> are only intended to be read
// by the DialogModelHost implementation.
Type type(util::PassKey<DialogModelHost>) const { return type_; }
const base::flat_set<Accelerator>& accelerators(
util::PassKey<DialogModelHost>) const {
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:
// Struct that holds a reserved ID for the field in the model. This is
// protected to be able to be passed from DialogModelField children to the
// parent constructor. Its members are private because only DialogModel,
// DialogModelField and DialogModelHost should be able to read them.
// 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,
// Children of this class need to be constructed through DialogModel to help
// enforce that they're added to the model.
DialogModelField(util::PassKey<DialogModel>,
DialogModel* model,
Type type,
int unique_id,
base::flat_set<Accelerator> accelerators);
int model_field_id() const { return model_field_id_; }
private:
friend class DialogModel;
DialogModel* const model_;
const int model_field_id_;
const Type type_;
const int unique_id_;
const base::flat_set<Accelerator> accelerators_;
......@@ -124,9 +91,10 @@ class COMPONENT_EXPORT(UI_BASE) DialogModelButton : public DialogModelField {
base::flat_set<Accelerator> accelerators_;
};
// Note that this is constructed through a DialogModel (Reservation can't
// be created without one).
DialogModelButton(const Reservation& reservation,
// Note that this is constructed through a DialogModel which adds it to model
// fields.
DialogModelButton(util::PassKey<DialogModel> pass_key,
DialogModel* model,
base::string16 label,
const Params& params);
DialogModelButton(const DialogModelButton&) = delete;
......@@ -178,9 +146,10 @@ class COMPONENT_EXPORT(UI_BASE) DialogModelCombobox : public DialogModelField {
base::flat_set<Accelerator> accelerators_;
};
// Note that this is constructed through a DialogModel (Reservation can't
// be created without one).
DialogModelCombobox(const Reservation& reservation,
// Note that this is constructed through a DialogModel which adds it to model
// fields.
DialogModelCombobox(util::PassKey<DialogModel> pass_key,
DialogModel* model,
base::string16 label,
std::unique_ptr<ui::ComboboxModel> combobox_model,
const Params& params);
......@@ -230,9 +199,10 @@ class COMPONENT_EXPORT(UI_BASE) DialogModelTextfield : public DialogModelField {
base::flat_set<Accelerator> accelerators_;
};
// Note that this is constructed through a DialogModel (Reservation can't
// be created without one).
DialogModelTextfield(const DialogModelField::Reservation& reservation,
// Note that this is constructed through a DialogModel which adds it to model
// fields.
DialogModelTextfield(util::PassKey<DialogModel> pass_key,
DialogModel* model,
base::string16 label,
base::string16 text,
const Params& params);
......
......@@ -37,7 +37,7 @@ class COMPONENT_EXPORT(UI_BASE) DialogModelHost {
// Called when various parts of the model changes.
// TODO(pbos): Break this down to API that says what was added/removed/changed
// to not have to reset everything.
virtual void OnModelChanged(DialogModel* model) = 0;
virtual void OnFieldAdded(DialogModelField* field) = 0;
};
} // namespace ui
......
......@@ -56,35 +56,34 @@ BubbleDialogModelHost::BubbleDialogModelHost(
base::Unretained(model_.get()), GetPassKey()));
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.
for (const auto& field : model_->fields(GetPassKey())) {
if (field->type(GetPassKey()) != ui::DialogModelField::kButton)
continue;
const auto* button = static_cast<const ui::DialogModelButton*>(field.get());
if (field->model_field_id(GetPassKey()) > ui::DIALOG_BUTTON_LAST) {
DCHECK_EQ(button, model_->GetExtraButton());
auto extra_button =
std::make_unique<views::MdTextButton>(this, button->label());
extra_button->SetID(field->model_field_id(GetPassKey()));
SetExtraView(std::move(extra_button));
auto* cancel_button = model_->cancel_button(GetPassKey());
if (cancel_button) {
button_mask |= ui::DIALOG_BUTTON_CANCEL;
if (!cancel_button->label().empty())
SetButtonLabel(ui::DIALOG_BUTTON_CANCEL, cancel_button->label());
}
continue;
auto* extra_button = model_->extra_button(GetPassKey());
if (extra_button) {
auto extra_view =
std::make_unique<views::MdTextButton>(this, extra_button->label());
view_to_field_[extra_view.get()] = extra_button;
SetExtraView(std::move(extra_view));
}
button_mask |= field->model_field_id(GetPassKey());
SetButtons(button_mask);
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
// code path as updates.
OnModelChanged(model_.get());
WidgetDelegate::SetTitle(model_->title(GetPassKey()));
WidgetDelegate::SetShowCloseButton(model_->show_close_button(GetPassKey()));
AddInitialFields();
}
BubbleDialogModelHost::~BubbleDialogModelHost() {
......@@ -93,21 +92,25 @@ BubbleDialogModelHost::~BubbleDialogModelHost() {
}
View* BubbleDialogModelHost::GetInitiallyFocusedView() {
if (model_->initially_focused_field(GetPassKey())) {
// TODO(pbos): Update this so that it works for dialog buttons.
View* focused_view = GetViewByID(
model_
->GetFieldByUniqueId(*model_->initially_focused_field(GetPassKey()))
->model_field_id(GetPassKey()));
// The dialog should be populated now so this should correspond to a view
// with this ID.
DCHECK(focused_view);
return focused_view;
}
ui::DialogModelField* focused_field = model_->GetTextfieldByUniqueId(
*model_->initially_focused_field(GetPassKey()));
if (!focused_field)
return BubbleDialogDelegateView::GetInitiallyFocusedView();
return FieldToView(focused_field);
}
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();
}
......@@ -119,24 +122,22 @@ void BubbleDialogModelHost::Close() {
void BubbleDialogModelHost::SelectAllText(int unique_id) {
static_cast<Textfield*>(
GetViewByID(model_->GetTextfieldByUniqueId(unique_id)->model_field_id(
GetPassKey())))
FieldToView(model_->GetTextfieldByUniqueId(unique_id)))
->SelectAll(false);
}
void BubbleDialogModelHost::OnModelChanged(ui::DialogModel* model) {
DCHECK(model == model_.get());
WidgetDelegate::SetTitle(model->title(GetPassKey()));
WidgetDelegate::SetShowCloseButton(model->show_close_button(GetPassKey()));
void BubbleDialogModelHost::OnFieldAdded(ui::DialogModelField* field) {
// TODO(pbos): Add support for adding fields while the model is hosted.
NOTREACHED();
}
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
// 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...";
DCHECK(children().empty()) << "This should only be called once.";
bool first_row = true;
const auto& fields = model->fields(GetPassKey());
const auto& fields = model_->fields(GetPassKey());
const DialogContentType first_field_content_type =
fields.empty()
? DialogContentType::CONTROL
......@@ -151,32 +152,29 @@ void BubbleDialogModelHost::OnModelChanged(ui::DialogModel* model) {
GetGridLayout()->AddPaddingRow(GridLayout::kFixedSize, 12);
}
View* last_field = nullptr;
View* last_view = nullptr;
switch (field->type(GetPassKey())) {
case ui::DialogModelField::kButton:
// TODO(pbos): Add support for buttons that are part of content area.
continue;
case ui::DialogModelField::kTextfield:
last_field = AddOrUpdateTextfield(
static_cast<const ui::DialogModelTextfield&>(*field));
last_view = AddOrUpdateTextfield(FieldAsTextfield(field.get()));
break;
case ui::DialogModelField::kCombobox:
last_field = AddOrUpdateCombobox(
static_cast<ui::DialogModelCombobox*>(field.get()));
last_view = AddOrUpdateCombobox(FieldAsCombobox(field.get()));
break;
}
DCHECK(last_field);
last_field->SetID(field->model_field_id(GetPassKey()));
DCHECK(last_view);
view_to_field_[last_view] = field.get();
last_field_content_type = FieldTypeToContentType(field->type(GetPassKey()));
// TODO(pbos): Update logic here when mixing types.
first_row = false;
}
set_margins(LayoutProvider::Get()->GetDialogInsetsForContentType(
first_field_content_type, last_field_content_type));
UpdateAccelerators();
}
GridLayout* BubbleDialogModelHost::GetGridLayout() {
......@@ -200,24 +198,21 @@ void BubbleDialogModelHost::ConfigureGridLayout() {
}
Textfield* BubbleDialogModelHost::AddOrUpdateTextfield(
const ui::DialogModelTextfield& model) {
// TODO(pbos): Handle updating existing field.
DCHECK(!GetViewByID(model.model_field_id(GetPassKey())))
<< "BubbleDialogModelHost doesn't yet support updates to the model";
ui::DialogModelTextfield* model) {
// TODO(pbos): Support updates to the existing model.
auto textfield = std::make_unique<Textfield>();
textfield->SetAccessibleName(
model.accessible_name().empty() ? model.text() : model.accessible_name());
textfield->SetText(model.text());
textfield->SetAccessibleName(model->accessible_name().empty()
? model->text()
: model->accessible_name());
textfield->SetText(model->text());
property_changed_subscriptions_.push_back(
textfield->AddTextChangedCallback(base::BindRepeating(
&BubbleDialogModelHost::NotifyTextfieldTextChanged,
base::Unretained(this), model.model_field_id(GetPassKey()),
textfield.get())));
property_changed_subscriptions_.push_back(textfield->AddTextChangedCallback(
base::BindRepeating(&BubbleDialogModelHost::NotifyTextfieldTextChanged,
base::Unretained(this), textfield.get())));
auto* textfield_ptr = textfield.get();
AddLabelAndField(model.label(), std::move(textfield),
AddLabelAndField(model->label(), std::move(textfield),
textfield_ptr->GetFontList());
return textfield_ptr;
......@@ -226,8 +221,6 @@ Textfield* BubbleDialogModelHost::AddOrUpdateTextfield(
Combobox* BubbleDialogModelHost::AddOrUpdateCombobox(
ui::DialogModelCombobox* model) {
// 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());
combobox->SetAccessibleName(model->accessible_name().empty()
......@@ -257,29 +250,32 @@ void BubbleDialogModelHost::AddLabelAndField(const base::string16& label_text,
layout->AddView(std::move(field));
}
void BubbleDialogModelHost::NotifyTextfieldTextChanged(int id,
Textfield* textfield) {
model_->OnTextfieldTextChanged(GetPassKey(), id, textfield->GetText());
void BubbleDialogModelHost::NotifyTextfieldTextChanged(Textfield* textfield) {
model_->OnTextfieldTextChanged(GetPassKey(),
FieldAsTextfield(view_to_field_[textfield]),
textfield->GetText());
}
void BubbleDialogModelHost::NotifyComboboxSelectedIndexChanged(
int id,
Combobox* combobox) {
model_->OnComboboxSelectedIndexChanged(GetPassKey(), id,
model_->OnComboboxSelectedIndexChanged(
GetPassKey(), FieldAsCombobox(view_to_field_[combobox]),
combobox->GetSelectedIndex());
}
void BubbleDialogModelHost::ButtonPressed(Button* sender,
const ui::Event& event) {
model_->OnButtonPressed(GetPassKey(), sender->GetID(), event);
model_->OnButtonPressed(GetPassKey(), FieldAsButton(view_to_field_[sender]),
event);
}
void BubbleDialogModelHost::OnPerformAction(Combobox* combobox) {
// TODO(pbos): This should be a subscription through the Combobox directly,
// 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() {
......@@ -287,25 +283,45 @@ void BubbleDialogModelHost::UpdateAccelerators() {
// ::OnDialogInitialized().
if (!GetWidget())
return;
for (const auto& field : model_->fields(GetPassKey())) {
if (field->accelerators(GetPassKey()).empty())
continue;
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);
for (auto& kv : view_to_field_) {
View* const view = kv.first;
view->ResetAccelerators();
for (const auto& accelerator : field->accelerators(GetPassKey()))
for (const auto& accelerator : kv.second->accelerators(GetPassKey()))
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
......@@ -20,7 +20,7 @@ class GridLayout;
class Textfield;
// 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
// SetHighlightedButton(). For methods that are reflected in ui::DialogModelHost
// (such as ::Close()), preferusing the ui::DialogModelHost to avoid
......@@ -49,8 +49,7 @@ class VIEWS_EXPORT BubbleDialogModelHost : public BubbleDialogDelegateView,
// ui::DialogModelHost:
void Close() override;
void SelectAllText(int unique_id) override;
void OnModelChanged(ui::DialogModel* model) override;
void OnFieldAdded(ui::DialogModelField* field) override;
// ButtonListener:
void ButtonPressed(views::Button* sender, const ui::Event& event) override;
......@@ -62,7 +61,8 @@ class VIEWS_EXPORT BubbleDialogModelHost : public BubbleDialogDelegateView,
GridLayout* GetGridLayout();
void ConfigureGridLayout();
Textfield* AddOrUpdateTextfield(const ui::DialogModelTextfield& field);
void AddInitialFields();
Textfield* AddOrUpdateTextfield(ui::DialogModelTextfield* field);
Combobox* AddOrUpdateCombobox(ui::DialogModelCombobox* field);
void AddLabelAndField(const base::string16& label_text,
std::unique_ptr<views::View> field,
......@@ -70,10 +70,17 @@ class VIEWS_EXPORT BubbleDialogModelHost : public BubbleDialogDelegateView,
void UpdateAccelerators();
void NotifyTextfieldTextChanged(int id, views::Textfield* textfield);
void NotifyComboboxSelectedIndexChanged(int id, views::Combobox* combobox);
void NotifyTextfieldTextChanged(views::Textfield* textfield);
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_;
base::flat_map<View*, ui::DialogModelField*> view_to_field_;
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