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:
FolderNameView()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
~FolderNameView()48 virtual ~FolderNameView() {
49 }
50
51 private:
52 DISALLOW_COPY_AND_ASSIGN(FolderNameView);
53 };
54
FolderHeaderView(FolderHeaderViewDelegate * delegate)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
~FolderHeaderView()85 FolderHeaderView::~FolderHeaderView() {
86 if (folder_item_)
87 folder_item_->RemoveObserver(this);
88 }
89
SetFolderItem(AppListFolderItem * folder_item)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
UpdateFolderNameVisibility(bool visible)105 void FolderHeaderView::UpdateFolderNameVisibility(bool visible) {
106 folder_name_visible_ = visible;
107 Update();
108 SchedulePaint();
109 }
110
OnFolderItemRemoved()111 void FolderHeaderView::OnFolderItemRemoved() {
112 folder_item_ = NULL;
113 }
114
Update()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
UpdateFolderNameAccessibleName()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
GetFolderNameForTest()139 const base::string16& FolderHeaderView::GetFolderNameForTest() {
140 return folder_name_view_->text();
141 }
142
SetFolderNameForTest(const base::string16 & name)143 void FolderHeaderView::SetFolderNameForTest(const base::string16& name) {
144 folder_name_view_->SetText(name);
145 }
146
IsFolderNameEnabledForTest() const147 bool FolderHeaderView::IsFolderNameEnabledForTest() const {
148 return folder_name_view_->enabled();
149 }
150
GetPreferredSize() const151 gfx::Size FolderHeaderView::GetPreferredSize() const {
152 return gfx::Size(kPreferredWidth, kPreferredHeight);
153 }
154
Layout()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
OnKeyPressed(const ui::KeyEvent & event)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
OnPaint(gfx::Canvas * canvas)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
ContentsChanged(views::Textfield * sender,const base::string16 & new_contents)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
ButtonPressed(views::Button * sender,const ui::Event & event)220 void FolderHeaderView::ButtonPressed(views::Button* sender,
221 const ui::Event& event) {
222 delegate_->NavigateBack(folder_item_, event);
223 }
224
ItemIconChanged()225 void FolderHeaderView::ItemIconChanged() {
226 }
227
ItemNameChanged()228 void FolderHeaderView::ItemNameChanged() {
229 Update();
230 }
231
ItemHighlightedChanged()232 void FolderHeaderView::ItemHighlightedChanged() {
233 }
234
ItemIsInstallingChanged()235 void FolderHeaderView::ItemIsInstallingChanged() {
236 }
237
ItemPercentDownloadedChanged()238 void FolderHeaderView::ItemPercentDownloadedChanged() {
239 }
240
241 } // namespace app_list
242