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