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