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