blob: 34f484847554c904ec011f3730c94497d0d12a24 [file] [log] [blame]
// Copyright (c) 2012 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.
#include "ui/views/controls/combobox/combobox.h"
#include "base/logging.h"
#include "base/strings/utf_string_conversions.h"
#include "ui/base/accessibility/accessible_view_state.h"
#include "ui/base/events/event.h"
#include "ui/base/keycodes/keyboard_codes.h"
#include "ui/base/models/combobox_model.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/views/controls/combobox/combobox_listener.h"
#include "ui/views/controls/native/native_view_host.h"
#include "ui/views/controls/prefix_selector.h"
#include "ui/views/ime/input_method.h"
#include "ui/views/widget/widget.h"
namespace views {
// static
const char Combobox::kViewClassName[] = "Combobox";
////////////////////////////////////////////////////////////////////////////////
// Combobox, public:
Combobox::Combobox(ui::ComboboxModel* model)
: native_wrapper_(NULL),
model_(model),
listener_(NULL),
selected_index_(model_->GetDefaultIndex()),
invalid_(false) {
set_focusable(true);
}
Combobox::~Combobox() {
}
// static
const gfx::Font& Combobox::GetFont() {
ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
return rb.GetFont(ui::ResourceBundle::BaseFont);
}
void Combobox::ModelChanged() {
selected_index_ = std::min(0, model_->GetItemCount());
if (native_wrapper_)
native_wrapper_->UpdateFromModel();
PreferredSizeChanged();
}
void Combobox::SetSelectedIndex(int index) {
selected_index_ = index;
if (native_wrapper_)
native_wrapper_->UpdateSelectedIndex();
}
void Combobox::SelectionChanged() {
selected_index_ = native_wrapper_->GetSelectedIndex();
if (listener_)
listener_->OnSelectedIndexChanged(this);
NotifyAccessibilityEvent(ui::AccessibilityTypes::EVENT_VALUE_CHANGED, false);
}
void Combobox::SetAccessibleName(const string16& name) {
accessible_name_ = name;
}
void Combobox::SetInvalid(bool invalid) {
invalid_ = invalid;
if (native_wrapper_)
native_wrapper_->ValidityStateChanged();
}
ui::TextInputClient* Combobox::GetTextInputClient() {
if (!selector_)
selector_.reset(new PrefixSelector(this));
return selector_.get();
}
int Combobox::GetRowCount() {
return model()->GetItemCount();
}
int Combobox::GetSelectedRow() {
return selected_index_;
}
void Combobox::SetSelectedRow(int row) {
SetSelectedIndex(row);
}
string16 Combobox::GetTextForRow(int row) {
return model()->GetItemAt(row);
}
////////////////////////////////////////////////////////////////////////////////
// Combobox, View overrides:
gfx::Size Combobox::GetPreferredSize() {
if (native_wrapper_)
return native_wrapper_->GetPreferredSize();
return gfx::Size();
}
void Combobox::Layout() {
if (native_wrapper_) {
native_wrapper_->GetView()->SetBounds(0, 0, width(), height());
native_wrapper_->GetView()->Layout();
}
}
void Combobox::OnEnabledChanged() {
View::OnEnabledChanged();
if (native_wrapper_)
native_wrapper_->UpdateEnabled();
}
// VKEY_ESCAPE should be handled by this view when the drop down list is active.
// In other words, the list should be closed instead of the dialog.
bool Combobox::SkipDefaultKeyEventProcessing(const ui::KeyEvent& e) {
if (e.key_code() != ui::VKEY_ESCAPE ||
e.IsShiftDown() || e.IsControlDown() || e.IsAltDown()) {
return false;
}
return native_wrapper_ && native_wrapper_->IsDropdownOpen();
}
void Combobox::OnPaintFocusBorder(gfx::Canvas* canvas) {
if (NativeViewHost::kRenderNativeControlFocus)
View::OnPaintFocusBorder(canvas);
}
bool Combobox::OnKeyPressed(const ui::KeyEvent& e) {
return native_wrapper_ && native_wrapper_->HandleKeyPressed(e);
}
bool Combobox::OnKeyReleased(const ui::KeyEvent& e) {
return native_wrapper_ && native_wrapper_->HandleKeyReleased(e);
}
void Combobox::OnFocus() {
GetInputMethod()->OnFocus();
// Forward the focus to the wrapper.
if (native_wrapper_) {
native_wrapper_->SetFocus();
NotifyAccessibilityEvent(ui::AccessibilityTypes::EVENT_FOCUS, true);
} else {
View::OnFocus(); // Will focus the RootView window (so we still get
// keyboard messages).
}
}
void Combobox::OnBlur() {
GetInputMethod()->OnBlur();
if (selector_)
selector_->OnViewBlur();
if (native_wrapper_)
native_wrapper_->HandleBlur();
}
void Combobox::GetAccessibleState(ui::AccessibleViewState* state) {
state->role = ui::AccessibilityTypes::ROLE_COMBOBOX;
state->name = accessible_name_;
state->value = model_->GetItemAt(selected_index_);
state->index = selected_index_;
state->count = model_->GetItemCount();
}
void Combobox::ViewHierarchyChanged(
const ViewHierarchyChangedDetails& details) {
if (details.is_add && !native_wrapper_ && GetWidget()) {
// The native wrapper's lifetime will be managed by the view hierarchy after
// we call AddChildView.
native_wrapper_ = NativeComboboxWrapper::CreateWrapper(this);
AddChildView(native_wrapper_->GetView());
// The underlying native widget may not be created until the wrapper is
// parented. For this reason the wrapper is only updated after adding its
// view.
native_wrapper_->UpdateFromModel();
native_wrapper_->UpdateSelectedIndex();
native_wrapper_->UpdateEnabled();
}
}
const char* Combobox::GetClassName() const {
return kViewClassName;
}
} // namespace views