1 // Copyright 2014 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.
5 #include "ui/app_list/views/start_page_view.h"
7 #include "base/strings/utf_string_conversions.h"
8 #include "ui/app_list/app_list_constants.h"
9 #include "ui/app_list/app_list_item.h"
10 #include "ui/app_list/app_list_model.h"
11 #include "ui/app_list/app_list_view_delegate.h"
12 #include "ui/app_list/search_result.h"
13 #include "ui/app_list/views/app_list_main_view.h"
14 #include "ui/app_list/views/search_box_view.h"
15 #include "ui/app_list/views/search_result_list_view.h"
16 #include "ui/app_list/views/tile_item_view.h"
17 #include "ui/gfx/canvas.h"
18 #include "ui/views/background.h"
19 #include "ui/views/controls/image_view.h"
20 #include "ui/views/controls/label.h"
21 #include "ui/views/controls/textfield/textfield.h"
22 #include "ui/views/layout/box_layout.h"
23 #include "ui/views/widget/widget.h"
30 const int kTopMargin
= 30;
31 const int kInstantContainerSpacing
= 20;
34 const int kWebViewWidth
= 500;
35 const int kWebViewHeight
= 105;
37 // DummySearchBoxView constants.
38 const int kDummySearchBoxWidth
= 490;
40 // Tile container constants.
41 const size_t kNumStartPageTiles
= 5;
42 const int kTileSpacing
= 10;
44 // A placeholder search box which is sized to fit within the start page view.
45 class DummySearchBoxView
: public SearchBoxView
{
47 DummySearchBoxView(SearchBoxViewDelegate
* delegate
,
48 AppListViewDelegate
* view_delegate
)
49 : SearchBoxView(delegate
, view_delegate
) {
52 virtual ~DummySearchBoxView() {}
54 // Overridden from views::View:
55 virtual gfx::Size
GetPreferredSize() const OVERRIDE
{
56 gfx::Size
size(SearchBoxView::GetPreferredSize());
57 size
.set_width(kDummySearchBoxWidth
);
62 DISALLOW_COPY_AND_ASSIGN(DummySearchBoxView
);
67 StartPageView::StartPageView(AppListMainView
* app_list_main_view
,
68 AppListViewDelegate
* view_delegate
)
69 : app_list_main_view_(app_list_main_view
),
70 search_results_model_(NULL
),
71 view_delegate_(view_delegate
),
72 search_box_view_(new DummySearchBoxView(this, view_delegate_
)),
74 new SearchResultListView(app_list_main_view
, view_delegate
)),
75 instant_container_(new views::View
),
76 tiles_container_(new views::View
),
77 show_state_(SHOW_START_PAGE
),
78 update_factory_(this) {
79 // The view containing the start page WebContents and DummySearchBoxView.
80 InitInstantContainer();
81 AddChildView(instant_container_
);
83 // The view containing the search results.
84 AddChildView(results_view_
);
86 // The view containing the start page tiles.
88 AddChildView(tiles_container_
);
90 SetModel(view_delegate_
->GetModel());
91 view_delegate_
->AddObserver(this);
94 StartPageView::~StartPageView() {
95 view_delegate_
->RemoveObserver(this);
96 if (search_results_model_
)
97 search_results_model_
->RemoveObserver(this);
100 void StartPageView::InitInstantContainer() {
101 views::BoxLayout
* instant_layout_manager
= new views::BoxLayout(
102 views::BoxLayout::kVertical
, 0, 0, kInstantContainerSpacing
);
103 instant_layout_manager
->set_inside_border_insets(
104 gfx::Insets(kTopMargin
, 0, kInstantContainerSpacing
, 0));
105 instant_layout_manager
->set_main_axis_alignment(
106 views::BoxLayout::MAIN_AXIS_ALIGNMENT_END
);
107 instant_layout_manager
->set_cross_axis_alignment(
108 views::BoxLayout::CROSS_AXIS_ALIGNMENT_CENTER
);
109 instant_container_
->SetLayoutManager(instant_layout_manager
);
111 views::View
* web_view
= view_delegate_
->CreateStartPageWebView(
112 gfx::Size(kWebViewWidth
, kWebViewHeight
));
114 instant_container_
->AddChildView(web_view
);
116 // TODO(calamity): This container is needed to horizontally center the search
117 // box view. Remove this container once BoxLayout supports CrossAxisAlignment.
118 views::View
* search_box_container
= new views::View();
119 views::BoxLayout
* layout_manager
=
120 new views::BoxLayout(views::BoxLayout::kHorizontal
, 0, 0, 0);
121 layout_manager
->set_main_axis_alignment(
122 views::BoxLayout::MAIN_AXIS_ALIGNMENT_CENTER
);
123 search_box_container
->SetLayoutManager(layout_manager
);
124 search_box_container
->AddChildView(search_box_view_
);
126 instant_container_
->AddChildView(search_box_container
);
129 void StartPageView::InitTilesContainer() {
130 views::BoxLayout
* tiles_layout_manager
=
131 new views::BoxLayout(views::BoxLayout::kHorizontal
, 0, 0, kTileSpacing
);
132 tiles_layout_manager
->set_main_axis_alignment(
133 views::BoxLayout::MAIN_AXIS_ALIGNMENT_CENTER
);
134 tiles_container_
->SetLayoutManager(tiles_layout_manager
);
135 for (size_t i
= 0; i
< kNumStartPageTiles
; ++i
) {
136 TileItemView
* tile_item
= new TileItemView();
137 tiles_container_
->AddChildView(tile_item
);
138 tile_views_
.push_back(tile_item
);
142 void StartPageView::SetModel(AppListModel
* model
) {
144 if (search_results_model_
)
145 search_results_model_
->RemoveObserver(this);
146 search_results_model_
= model
->results();
147 search_results_model_
->AddObserver(this);
148 results_view_
->SetResults(search_results_model_
);
152 void StartPageView::Reset() {
153 SetShowState(SHOW_START_PAGE
);
157 void StartPageView::ShowSearchResults() {
158 SetShowState(SHOW_SEARCH_RESULTS
);
162 void StartPageView::SetShowState(ShowState show_state
) {
163 instant_container_
->SetVisible(show_state
== SHOW_START_PAGE
);
164 results_view_
->SetVisible(show_state
== SHOW_SEARCH_RESULTS
);
166 // This can be called when the app list is closing (widget is invisible). In
167 // that case, do not steal focus from other elements.
168 if (show_state
== SHOW_START_PAGE
&& GetWidget() && GetWidget()->IsVisible())
169 search_box_view_
->search_box()->RequestFocus();
171 if (show_state_
== show_state
)
174 show_state_
= show_state
;
176 if (show_state_
== SHOW_START_PAGE
)
177 search_box_view_
->ClearSearch();
179 results_view_
->UpdateAutoLaunchState();
180 if (show_state
== SHOW_SEARCH_RESULTS
)
181 results_view_
->SetSelectedIndex(0);
184 bool StartPageView::IsShowingSearchResults() const {
185 return show_state_
== SHOW_SEARCH_RESULTS
;
188 void StartPageView::UpdateForTesting() {
192 bool StartPageView::OnKeyPressed(const ui::KeyEvent
& event
) {
193 if (show_state_
== SHOW_SEARCH_RESULTS
)
194 return results_view_
->OnKeyPressed(event
);
199 void StartPageView::Layout() {
200 // Instant and search results take up the height of the instant container.
201 gfx::Rect
bounds(GetContentsBounds());
202 bounds
.set_height(instant_container_
->GetHeightForWidth(bounds
.width()));
203 instant_container_
->SetBoundsRect(bounds
);
204 results_view_
->SetBoundsRect(bounds
);
206 // Tiles begin where the instant container ends.
207 bounds
.set_y(bounds
.bottom());
208 bounds
.set_height(tiles_container_
->GetHeightForWidth(bounds
.width()));
209 tiles_container_
->SetBoundsRect(bounds
);
212 void StartPageView::Update() {
213 std::vector
<SearchResult
*> display_results
=
214 AppListModel::FilterSearchResultsByDisplayType(search_results_model_
,
215 SearchResult::DISPLAY_TILE
,
217 for (size_t i
= 0; i
< kNumStartPageTiles
; ++i
) {
218 SearchResult
* item
= NULL
;
219 if (i
< display_results
.size())
220 item
= display_results
[i
];
221 tile_views_
[i
]->SetSearchResult(item
);
223 tiles_container_
->Layout();
225 update_factory_
.InvalidateWeakPtrs();
228 void StartPageView::ScheduleUpdate() {
229 // When search results are added one by one, each addition generates an update
230 // request. Consolidates those update requests into one Update call.
231 if (!update_factory_
.HasWeakPtrs()) {
232 base::MessageLoop::current()->PostTask(
234 base::Bind(&StartPageView::Update
, update_factory_
.GetWeakPtr()));
238 void StartPageView::QueryChanged(SearchBoxView
* sender
) {
239 // Forward the search terms on to the real search box and clear the dummy
241 app_list_main_view_
->OnStartPageSearchTextfieldChanged(
242 sender
->search_box()->text());
243 sender
->search_box()->SetText(base::string16());
246 void StartPageView::OnProfilesChanged() {
247 SetModel(view_delegate_
->GetModel());
250 void StartPageView::ListItemsAdded(size_t start
, size_t count
) {
254 void StartPageView::ListItemsRemoved(size_t start
, size_t count
) {
258 void StartPageView::ListItemMoved(size_t index
, size_t target_index
) {
262 void StartPageView::ListItemsChanged(size_t start
, size_t count
) {
266 } // namespace app_list