Home | History | Annotate | Download | only in combobox
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "ui/views/controls/combobox/combobox.h"
      6 
      7 #include "base/logging.h"
      8 #include "base/strings/utf_string_conversions.h"
      9 #include "ui/base/accessibility/accessible_view_state.h"
     10 #include "ui/base/events/event.h"
     11 #include "ui/base/keycodes/keyboard_codes.h"
     12 #include "ui/base/models/combobox_model.h"
     13 #include "ui/base/resource/resource_bundle.h"
     14 #include "ui/views/controls/combobox/combobox_listener.h"
     15 #include "ui/views/controls/native/native_view_host.h"
     16 #include "ui/views/controls/prefix_selector.h"
     17 #include "ui/views/ime/input_method.h"
     18 #include "ui/views/widget/widget.h"
     19 
     20 namespace views {
     21 
     22 // static
     23 const char Combobox::kViewClassName[] = "Combobox";
     24 
     25 ////////////////////////////////////////////////////////////////////////////////
     26 // Combobox, public:
     27 
     28 Combobox::Combobox(ui::ComboboxModel* model)
     29     : native_wrapper_(NULL),
     30       model_(model),
     31       listener_(NULL),
     32       selected_index_(model_->GetDefaultIndex()),
     33       invalid_(false) {
     34   set_focusable(true);
     35 }
     36 
     37 Combobox::~Combobox() {
     38 }
     39 
     40 // static
     41 const gfx::Font& Combobox::GetFont() {
     42   ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
     43   return rb.GetFont(ui::ResourceBundle::BaseFont);
     44 }
     45 
     46 void Combobox::ModelChanged() {
     47   selected_index_ = std::min(0, model_->GetItemCount());
     48   if (native_wrapper_)
     49     native_wrapper_->UpdateFromModel();
     50   PreferredSizeChanged();
     51 }
     52 
     53 void Combobox::SetSelectedIndex(int index) {
     54   selected_index_ = index;
     55   if (native_wrapper_)
     56     native_wrapper_->UpdateSelectedIndex();
     57 }
     58 
     59 void Combobox::SelectionChanged() {
     60   selected_index_ = native_wrapper_->GetSelectedIndex();
     61   if (listener_)
     62     listener_->OnSelectedIndexChanged(this);
     63   NotifyAccessibilityEvent(ui::AccessibilityTypes::EVENT_VALUE_CHANGED, false);
     64 }
     65 
     66 void Combobox::SetAccessibleName(const string16& name) {
     67   accessible_name_ = name;
     68 }
     69 
     70 void Combobox::SetInvalid(bool invalid) {
     71   invalid_ = invalid;
     72   if (native_wrapper_)
     73     native_wrapper_->ValidityStateChanged();
     74 }
     75 
     76 ui::TextInputClient* Combobox::GetTextInputClient() {
     77   if (!selector_)
     78     selector_.reset(new PrefixSelector(this));
     79   return selector_.get();
     80 }
     81 
     82 int Combobox::GetRowCount() {
     83   return model()->GetItemCount();
     84 }
     85 
     86 int Combobox::GetSelectedRow() {
     87   return selected_index_;
     88 }
     89 
     90 void Combobox::SetSelectedRow(int row) {
     91   SetSelectedIndex(row);
     92 }
     93 
     94 string16 Combobox::GetTextForRow(int row) {
     95   return model()->GetItemAt(row);
     96 }
     97 
     98 ////////////////////////////////////////////////////////////////////////////////
     99 // Combobox, View overrides:
    100 
    101 gfx::Size Combobox::GetPreferredSize() {
    102   if (native_wrapper_)
    103     return native_wrapper_->GetPreferredSize();
    104   return gfx::Size();
    105 }
    106 
    107 void Combobox::Layout() {
    108   if (native_wrapper_) {
    109     native_wrapper_->GetView()->SetBounds(0, 0, width(), height());
    110     native_wrapper_->GetView()->Layout();
    111   }
    112 }
    113 
    114 void Combobox::OnEnabledChanged() {
    115   View::OnEnabledChanged();
    116   if (native_wrapper_)
    117     native_wrapper_->UpdateEnabled();
    118 }
    119 
    120 // VKEY_ESCAPE should be handled by this view when the drop down list is active.
    121 // In other words, the list should be closed instead of the dialog.
    122 bool Combobox::SkipDefaultKeyEventProcessing(const ui::KeyEvent& e) {
    123   if (e.key_code() != ui::VKEY_ESCAPE ||
    124       e.IsShiftDown() || e.IsControlDown() || e.IsAltDown()) {
    125     return false;
    126   }
    127   return native_wrapper_ && native_wrapper_->IsDropdownOpen();
    128 }
    129 
    130 void Combobox::OnPaintFocusBorder(gfx::Canvas* canvas) {
    131   if (NativeViewHost::kRenderNativeControlFocus)
    132     View::OnPaintFocusBorder(canvas);
    133 }
    134 
    135 bool Combobox::OnKeyPressed(const ui::KeyEvent& e) {
    136   return native_wrapper_ && native_wrapper_->HandleKeyPressed(e);
    137 }
    138 
    139 bool Combobox::OnKeyReleased(const ui::KeyEvent& e) {
    140   return native_wrapper_ && native_wrapper_->HandleKeyReleased(e);
    141 }
    142 
    143 void Combobox::OnFocus() {
    144   GetInputMethod()->OnFocus();
    145   // Forward the focus to the wrapper.
    146   if (native_wrapper_) {
    147     native_wrapper_->SetFocus();
    148     NotifyAccessibilityEvent(ui::AccessibilityTypes::EVENT_FOCUS, true);
    149   } else {
    150     View::OnFocus();  // Will focus the RootView window (so we still get
    151                       // keyboard messages).
    152   }
    153 }
    154 
    155 void Combobox::OnBlur() {
    156   GetInputMethod()->OnBlur();
    157   if (selector_)
    158     selector_->OnViewBlur();
    159   if (native_wrapper_)
    160     native_wrapper_->HandleBlur();
    161 }
    162 
    163 void Combobox::GetAccessibleState(ui::AccessibleViewState* state) {
    164   state->role = ui::AccessibilityTypes::ROLE_COMBOBOX;
    165   state->name = accessible_name_;
    166   state->value = model_->GetItemAt(selected_index_);
    167   state->index = selected_index_;
    168   state->count = model_->GetItemCount();
    169 }
    170 
    171 void Combobox::ViewHierarchyChanged(
    172     const ViewHierarchyChangedDetails& details) {
    173   if (details.is_add && !native_wrapper_ && GetWidget()) {
    174     // The native wrapper's lifetime will be managed by the view hierarchy after
    175     // we call AddChildView.
    176     native_wrapper_ = NativeComboboxWrapper::CreateWrapper(this);
    177     AddChildView(native_wrapper_->GetView());
    178     // The underlying native widget may not be created until the wrapper is
    179     // parented. For this reason the wrapper is only updated after adding its
    180     // view.
    181     native_wrapper_->UpdateFromModel();
    182     native_wrapper_->UpdateSelectedIndex();
    183     native_wrapper_->UpdateEnabled();
    184   }
    185 }
    186 
    187 const char* Combobox::GetClassName() const {
    188   return kViewClassName;
    189 }
    190 
    191 }  // namespace views
    192