Home | History | Annotate | Download | only in views
      1 // Copyright (c) 2013 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/app_list/views/folder_header_view.h"
      6 
      7 #include <algorithm>
      8 
      9 #include "base/strings/utf_string_conversions.h"
     10 #include "grit/ui_resources.h"
     11 #include "grit/ui_strings.h"
     12 #include "ui/app_list/app_list_constants.h"
     13 #include "ui/app_list/app_list_folder_item.h"
     14 #include "ui/app_list/views/app_list_folder_view.h"
     15 #include "ui/base/resource/resource_bundle.h"
     16 #include "ui/gfx/canvas.h"
     17 #include "ui/views/border.h"
     18 #include "ui/views/controls/button/image_button.h"
     19 #include "ui/views/controls/textfield/textfield.h"
     20 #include "ui/views/painter.h"
     21 
     22 namespace app_list {
     23 
     24 namespace {
     25 
     26 const int kPreferredWidth = 360;
     27 const int kPreferredHeight = 48;
     28 const int kIconDimension = 24;
     29 const int kPadding = 14;
     30 const int kBottomSeparatorWidth = 380;
     31 const int kBottomSeparatorHeight = 1;
     32 const int kMaxFolderNameWidth = 300;
     33 
     34 const SkColor kHintTextColor = SkColorSetRGB(0xA0, 0xA0, 0xA0);
     35 
     36 }  // namespace
     37 
     38 class FolderHeaderView::FolderNameView : public views::Textfield {
     39  public:
     40   FolderNameView() {
     41     SetBorder(views::Border::CreateEmptyBorder(1, 1, 1, 1));
     42     const SkColor kFocusBorderColor = SkColorSetRGB(64, 128, 250);
     43     SetFocusPainter(views::Painter::CreateSolidFocusPainter(
     44           kFocusBorderColor,
     45           gfx::Insets(0, 0, 1, 1)));
     46   }
     47 
     48   virtual ~FolderNameView() {
     49   }
     50 
     51  private:
     52   DISALLOW_COPY_AND_ASSIGN(FolderNameView);
     53 };
     54 
     55 FolderHeaderView::FolderHeaderView(FolderHeaderViewDelegate* delegate)
     56     : folder_item_(NULL),
     57       back_button_(new views::ImageButton(this)),
     58       folder_name_view_(new FolderNameView),
     59       folder_name_placeholder_text_(
     60           ui::ResourceBundle::GetSharedInstance().GetLocalizedString(
     61               IDS_APP_LIST_FOLDER_NAME_PLACEHOLDER)),
     62       delegate_(delegate),
     63       folder_name_visible_(true) {
     64   ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
     65   back_button_->SetImage(views::ImageButton::STATE_NORMAL,
     66       rb.GetImageSkiaNamed(IDR_APP_LIST_FOLDER_BACK_NORMAL));
     67   back_button_->SetImageAlignment(views::ImageButton::ALIGN_CENTER,
     68       views::ImageButton::ALIGN_MIDDLE);
     69   AddChildView(back_button_);
     70   back_button_->SetFocusable(true);
     71   back_button_->SetAccessibleName(
     72       ui::ResourceBundle::GetSharedInstance().GetLocalizedString(
     73           IDS_APP_LIST_FOLDER_CLOSE_FOLDER_ACCESSIBILE_NAME));
     74 
     75   folder_name_view_->SetFontList(
     76       rb.GetFontList(ui::ResourceBundle::MediumFont));
     77   folder_name_view_->set_placeholder_text_color(kHintTextColor);
     78   folder_name_view_->set_placeholder_text(folder_name_placeholder_text_);
     79   folder_name_view_->SetBorder(views::Border::NullBorder());
     80   folder_name_view_->SetBackgroundColor(kContentsBackgroundColor);
     81   folder_name_view_->set_controller(this);
     82   AddChildView(folder_name_view_);
     83 }
     84 
     85 FolderHeaderView::~FolderHeaderView() {
     86   if (folder_item_)
     87     folder_item_->RemoveObserver(this);
     88 }
     89 
     90 void FolderHeaderView::SetFolderItem(AppListFolderItem* folder_item) {
     91   if (folder_item_)
     92     folder_item_->RemoveObserver(this);
     93 
     94   folder_item_ = folder_item;
     95   if (!folder_item_)
     96     return;
     97   folder_item_->AddObserver(this);
     98 
     99   folder_name_view_->SetEnabled(folder_item_->folder_type() !=
    100                                 AppListFolderItem::FOLDER_TYPE_OEM);
    101 
    102   Update();
    103 }
    104 
    105 void FolderHeaderView::UpdateFolderNameVisibility(bool visible) {
    106   folder_name_visible_ = visible;
    107   Update();
    108   SchedulePaint();
    109 }
    110 
    111 void FolderHeaderView::OnFolderItemRemoved() {
    112   folder_item_ = NULL;
    113 }
    114 
    115 void FolderHeaderView::Update() {
    116   if (!folder_item_)
    117     return;
    118 
    119   folder_name_view_->SetVisible(folder_name_visible_);
    120   if (folder_name_visible_) {
    121     folder_name_view_->SetText(base::UTF8ToUTF16(folder_item_->name()));
    122     UpdateFolderNameAccessibleName();
    123   }
    124 
    125   Layout();
    126 }
    127 
    128 void FolderHeaderView::UpdateFolderNameAccessibleName() {
    129   // Sets |folder_name_view_|'s accessible name to the placeholder text if
    130   // |folder_name_view_| is blank; otherwise, clear the accessible name, the
    131   // accessible state's value is set to be folder_name_view_->text() by
    132   // TextField.
    133   base::string16 accessible_name = folder_name_view_->text().empty()
    134                                        ? folder_name_placeholder_text_
    135                                        : base::string16();
    136   folder_name_view_->SetAccessibleName(accessible_name);
    137 }
    138 
    139 const base::string16& FolderHeaderView::GetFolderNameForTest() {
    140   return folder_name_view_->text();
    141 }
    142 
    143 void FolderHeaderView::SetFolderNameForTest(const base::string16& name) {
    144   folder_name_view_->SetText(name);
    145 }
    146 
    147 bool FolderHeaderView::IsFolderNameEnabledForTest() const {
    148   return folder_name_view_->enabled();
    149 }
    150 
    151 gfx::Size FolderHeaderView::GetPreferredSize() const {
    152   return gfx::Size(kPreferredWidth, kPreferredHeight);
    153 }
    154 
    155 void FolderHeaderView::Layout() {
    156   gfx::Rect rect(GetContentsBounds());
    157   if (rect.IsEmpty())
    158     return;
    159 
    160   gfx::Rect back_bounds(rect);
    161   back_bounds.set_width(kIconDimension + 2 * kPadding);
    162   back_button_->SetBoundsRect(back_bounds);
    163 
    164   gfx::Rect text_bounds(rect);
    165   base::string16 text = folder_item_->name().empty()
    166                             ? folder_name_placeholder_text_
    167                             : base::UTF8ToUTF16(folder_item_->name());
    168   int text_width =
    169       gfx::Canvas::GetStringWidth(text, folder_name_view_->GetFontList()) +
    170       folder_name_view_->GetCaretBounds().width();
    171   text_width = std::min(text_width, kMaxFolderNameWidth);
    172   text_bounds.set_x(back_bounds.x() + (rect.width() - text_width) / 2);
    173   text_bounds.set_width(text_width);
    174   text_bounds.ClampToCenteredSize(gfx::Size(text_bounds.width(),
    175       folder_name_view_->GetPreferredSize().height()));
    176   folder_name_view_->SetBoundsRect(text_bounds);
    177 }
    178 
    179 bool FolderHeaderView::OnKeyPressed(const ui::KeyEvent& event) {
    180   if (event.key_code() == ui::VKEY_RETURN)
    181     delegate_->GiveBackFocusToSearchBox();
    182 
    183   return false;
    184 }
    185 
    186 void FolderHeaderView::OnPaint(gfx::Canvas* canvas) {
    187   views::View::OnPaint(canvas);
    188 
    189   gfx::Rect rect(GetContentsBounds());
    190   if (rect.IsEmpty() || !folder_name_visible_)
    191     return;
    192 
    193   // Draw bottom separator line.
    194   rect.set_x((rect.width() - kBottomSeparatorWidth) / 2 + rect.x());
    195   rect.set_y(rect.y() + rect.height() - kBottomSeparatorHeight);
    196   rect.set_width(kBottomSeparatorWidth);
    197   rect.set_height(kBottomSeparatorHeight);
    198   canvas->FillRect(rect, kTopSeparatorColor);
    199 }
    200 
    201 void FolderHeaderView::ContentsChanged(views::Textfield* sender,
    202                                        const base::string16& new_contents) {
    203   // Temporarily remove from observer to ignore data change caused by us.
    204   if (!folder_item_)
    205     return;
    206 
    207   folder_item_->RemoveObserver(this);
    208   // Enforce the maximum folder name length in UI.
    209   std::string name = base::UTF16ToUTF8(
    210       folder_name_view_->text().substr(0, kMaxFolderNameChars));
    211   if (name != folder_item_->name())
    212     delegate_->SetItemName(folder_item_, name);
    213   folder_item_->AddObserver(this);
    214 
    215   UpdateFolderNameAccessibleName();
    216 
    217   Layout();
    218 }
    219 
    220 void FolderHeaderView::ButtonPressed(views::Button* sender,
    221                                      const ui::Event& event) {
    222   delegate_->NavigateBack(folder_item_, event);
    223 }
    224 
    225 void FolderHeaderView::ItemIconChanged() {
    226 }
    227 
    228 void FolderHeaderView::ItemNameChanged() {
    229   Update();
    230 }
    231 
    232 void FolderHeaderView::ItemHighlightedChanged() {
    233 }
    234 
    235 void FolderHeaderView::ItemIsInstallingChanged() {
    236 }
    237 
    238 void FolderHeaderView::ItemPercentDownloadedChanged() {
    239 }
    240 
    241 }  // namespace app_list
    242