text: // 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/button/radio_button.h"
  
  #include "base/logging.h"
  #include "grit/ui_resources.h"
  #include "ui/base/accessibility/accessible_view_state.h"
  #include "ui/base/resource/resource_bundle.h"
  #include "ui/views/widget/widget.h"
  
  namespace views {
  
  // static
  const char RadioButton::kViewClassName[] = "RadioButton";
  
  RadioButton::RadioButton(const base::string16& label, int group_id)
      : Checkbox(label) {
    SetGroup(group_id);
  
    ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
  
    // Unchecked/Unfocused images.
    SetCustomImage(false, false, STATE_NORMAL,
                   *rb.GetImageSkiaNamed(IDR_RADIO));
    SetCustomImage(false, false, STATE_HOVERED,
                   *rb.GetImageSkiaNamed(IDR_RADIO_HOVER));
    SetCustomImage(false, false, STATE_PRESSED,
                   *rb.GetImageSkiaNamed(IDR_RADIO_PRESSED));
    SetCustomImage(false, false, STATE_DISABLED,
                   *rb.GetImageSkiaNamed(IDR_RADIO_DISABLED));
  
    // Checked/Unfocused images.
    SetCustomImage(true, false, STATE_NORMAL,
                   *rb.GetImageSkiaNamed(IDR_RADIO_CHECKED));
    SetCustomImage(true, false, STATE_HOVERED,
                   *rb.GetImageSkiaNamed(IDR_RADIO_CHECKED_HOVER));
    SetCustomImage(true, false, STATE_PRESSED,
                   *rb.GetImageSkiaNamed(IDR_RADIO_CHECKED_PRESSED));
    SetCustomImage(true, false, STATE_DISABLED,
                   *rb.GetImageSkiaNamed(IDR_RADIO_CHECKED_DISABLED));
  
    // Unchecked/Focused images.
    SetCustomImage(false, true, STATE_NORMAL,
                   *rb.GetImageSkiaNamed(IDR_RADIO_FOCUSED));
    SetCustomImage(false, true, STATE_HOVERED,
                   *rb.GetImageSkiaNamed(IDR_RADIO_FOCUSED_HOVER));
    SetCustomImage(false, true, STATE_PRESSED,
                   *rb.GetImageSkiaNamed(IDR_RADIO_FOCUSED_PRESSED));
  
    // Checked/Focused images.
    SetCustomImage(true, true, STATE_NORMAL,
                   *rb.GetImageSkiaNamed(IDR_RADIO_FOCUSED_CHECKED));
    SetCustomImage(true, true, STATE_HOVERED,
                   *rb.GetImageSkiaNamed(IDR_RADIO_FOCUSED_CHECKED_HOVER));
    SetCustomImage(true, true, STATE_PRESSED,
                   *rb.GetImageSkiaNamed(IDR_RADIO_FOCUSED_CHECKED_PRESSED));
  }
  
  RadioButton::~RadioButton() {
  }
  
  void RadioButton::SetChecked(bool checked) {
    if (checked == RadioButton::checked())
      return;
    if (checked) {
      // We can't just get the root view here because sometimes the radio
      // button isn't attached to a root view (e.g., if it's part of a tab page
      // that is currently not active).
      View* container = parent();
      while (container && container->parent())
        container = container->parent();
      if (container) {
        Views other;
        container->GetViewsInGroup(GetGroup(), &other);
        for (Views::iterator i(other.begin()); i != other.end(); ++i) {
          if (*i != this) {
            if (strcmp((*i)->GetClassName(), kViewClassName)) {
              NOTREACHED() << "radio-button-nt has same group as other non "
                              "radio-button-nt views.";
              continue;
            }
            RadioButton* peer = static_cast<RadioButton*>(*i);
            peer->SetChecked(false);
          }
        }
      }
    }
    Checkbox::SetChecked(checked);
  }
  
  const char* RadioButton::GetClassName() const {
    return kViewClassName;
  }
  
  void RadioButton::GetAccessibleState(ui::AccessibleViewState* state) {
    Checkbox::GetAccessibleState(state);
    state->role = ui::AccessibilityTypes::ROLE_RADIOBUTTON;
  }
  
  View* RadioButton::GetSelectedViewForGroup(int group) {
    Views views;
    GetWidget()->GetRootView()->GetViewsInGroup(group, &views);
    if (views.empty())
      return NULL;
  
    for (Views::const_iterator i(views.begin()); i != views.end(); ++i) {
      // REVIEW: why don't we check the runtime type like is done above?
      RadioButton* radio_button = static_cast<RadioButton*>(*i);
      if (radio_button->checked())
        return radio_button;
    }
    return NULL;
  }
  
  bool RadioButton::IsGroupFocusTraversable() const {
    // When focusing a radio button with tab/shift+tab, only the selected button
    // from the group should be focused.
    return false;
  }
  
  void RadioButton::OnFocus() {
    Checkbox::OnFocus();
    SetChecked(true);
    ui::MouseEvent event(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(), 0, 0);
    LabelButton::NotifyClick(event);
  }
  
  void RadioButton::NotifyClick(const ui::Event& event) {
    // Set the checked state to true only if we are unchecked, since we can't
    // be toggled on and off like a checkbox.
    if (!checked())
      SetChecked(true);
    RequestFocus();
    LabelButton::NotifyClick(event);
  }
  
  ui::NativeTheme::Part RadioButton::GetThemePart() const {
    return ui::NativeTheme::kRadio;
  }
  
  }  // namespace views
  