Home | History | Annotate | Download | only in views
      1 // Copyright (c) 2012 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/contents_view.h"
      6 
      7 #include <algorithm>
      8 #include <vector>
      9 
     10 #include "base/logging.h"
     11 #include "ui/app_list/app_list_constants.h"
     12 #include "ui/app_list/app_list_switches.h"
     13 #include "ui/app_list/app_list_view_delegate.h"
     14 #include "ui/app_list/views/app_list_folder_view.h"
     15 #include "ui/app_list/views/app_list_main_view.h"
     16 #include "ui/app_list/views/apps_container_view.h"
     17 #include "ui/app_list/views/apps_grid_view.h"
     18 #include "ui/app_list/views/contents_switcher_view.h"
     19 #include "ui/app_list/views/search_result_list_view.h"
     20 #include "ui/app_list/views/start_page_view.h"
     21 #include "ui/events/event.h"
     22 #include "ui/gfx/animation/tween.h"
     23 #include "ui/resources/grit/ui_resources.h"
     24 #include "ui/views/view_model.h"
     25 #include "ui/views/view_model_utils.h"
     26 
     27 namespace app_list {
     28 
     29 ContentsView::ContentsView(AppListMainView* app_list_main_view)
     30     : search_results_view_(NULL),
     31       start_page_view_(NULL),
     32       app_list_main_view_(app_list_main_view),
     33       contents_switcher_view_(NULL),
     34       view_model_(new views::ViewModel),
     35       page_before_search_(0) {
     36   pagination_model_.SetTransitionDurations(kPageTransitionDurationInMs,
     37                                            kOverscrollPageTransitionDurationMs);
     38   pagination_model_.AddObserver(this);
     39 }
     40 
     41 ContentsView::~ContentsView() {
     42   pagination_model_.RemoveObserver(this);
     43   if (contents_switcher_view_)
     44     pagination_model_.RemoveObserver(contents_switcher_view_);
     45 }
     46 
     47 void ContentsView::InitNamedPages(AppListModel* model,
     48                                   AppListViewDelegate* view_delegate) {
     49   DCHECK(model);
     50 
     51   if (app_list::switches::IsExperimentalAppListEnabled()) {
     52     std::vector<views::View*> custom_page_views =
     53         view_delegate->CreateCustomPageWebViews(GetLocalBounds().size());
     54     for (std::vector<views::View*>::const_iterator it =
     55              custom_page_views.begin();
     56          it != custom_page_views.end();
     57          ++it) {
     58       AddLauncherPage(*it, IDR_APP_LIST_NOTIFICATIONS_ICON);
     59     }
     60 
     61     start_page_view_ = new StartPageView(app_list_main_view_, view_delegate);
     62     AddLauncherPage(
     63         start_page_view_, IDR_APP_LIST_SEARCH_ICON, NAMED_PAGE_START);
     64   } else {
     65     search_results_view_ =
     66         new SearchResultListView(app_list_main_view_, view_delegate);
     67     AddLauncherPage(search_results_view_, 0, NAMED_PAGE_SEARCH_RESULTS);
     68     search_results_view_->SetResults(model->results());
     69   }
     70 
     71   apps_container_view_ = new AppsContainerView(app_list_main_view_, model);
     72 
     73   AddLauncherPage(
     74       apps_container_view_, IDR_APP_LIST_APPS_ICON, NAMED_PAGE_APPS);
     75 
     76   int initial_page_index = app_list::switches::IsExperimentalAppListEnabled()
     77                                ? GetPageIndexForNamedPage(NAMED_PAGE_START)
     78                                : GetPageIndexForNamedPage(NAMED_PAGE_APPS);
     79   DCHECK_GE(initial_page_index, 0);
     80 
     81   page_before_search_ = initial_page_index;
     82   pagination_model_.SelectPage(initial_page_index, false);
     83 
     84   // Needed to update the main search box visibility.
     85   ActivePageChanged(false);
     86 }
     87 
     88 void ContentsView::CancelDrag() {
     89   if (apps_container_view_->apps_grid_view()->has_dragged_view())
     90     apps_container_view_->apps_grid_view()->EndDrag(true);
     91   if (apps_container_view_->app_list_folder_view()
     92           ->items_grid_view()
     93           ->has_dragged_view()) {
     94     apps_container_view_->app_list_folder_view()->items_grid_view()->EndDrag(
     95         true);
     96   }
     97 }
     98 
     99 void ContentsView::SetDragAndDropHostOfCurrentAppList(
    100     ApplicationDragAndDropHost* drag_and_drop_host) {
    101   apps_container_view_->SetDragAndDropHostOfCurrentAppList(drag_and_drop_host);
    102 }
    103 
    104 void ContentsView::SetContentsSwitcherView(
    105     ContentsSwitcherView* contents_switcher_view) {
    106   DCHECK(!contents_switcher_view_);
    107   contents_switcher_view_ = contents_switcher_view;
    108   if (contents_switcher_view_)
    109     pagination_model_.AddObserver(contents_switcher_view_);
    110 }
    111 
    112 void ContentsView::SetActivePage(int page_index) {
    113   if (GetActivePageIndex() == page_index)
    114     return;
    115 
    116   SetActivePageInternal(page_index, false);
    117 }
    118 
    119 int ContentsView::GetActivePageIndex() const {
    120   // The active page is changed at the beginning of an animation, not the end.
    121   return pagination_model_.SelectedTargetPage();
    122 }
    123 
    124 bool ContentsView::IsNamedPageActive(NamedPage named_page) const {
    125   int active_page_index = GetActivePageIndex();
    126   return active_page_index >= 0 &&
    127          GetPageIndexForNamedPage(named_page) == active_page_index;
    128 }
    129 
    130 int ContentsView::GetPageIndexForNamedPage(NamedPage named_page) const {
    131   // Find the index of the view corresponding to the given named_page.
    132   std::map<NamedPage, int>::const_iterator it =
    133       named_page_to_view_.find(named_page);
    134   if (it == named_page_to_view_.end())
    135     return -1;
    136 
    137   return it->second;
    138 }
    139 
    140 int ContentsView::NumLauncherPages() const {
    141   return pagination_model_.total_pages();
    142 }
    143 
    144 void ContentsView::SetActivePageInternal(int page_index,
    145                                          bool show_search_results) {
    146   if (!show_search_results)
    147     page_before_search_ = page_index;
    148   // Start animating to the new page.
    149   pagination_model_.SelectPage(page_index, true);
    150   ActivePageChanged(show_search_results);
    151 }
    152 
    153 void ContentsView::ActivePageChanged(bool show_search_results) {
    154   // TODO(xiyuan): Highlight default match instead of the first.
    155   if (IsNamedPageActive(NAMED_PAGE_SEARCH_RESULTS) &&
    156       search_results_view_->visible()) {
    157     search_results_view_->SetSelectedIndex(0);
    158   }
    159   if (search_results_view_)
    160     search_results_view_->UpdateAutoLaunchState();
    161 
    162   if (IsNamedPageActive(NAMED_PAGE_START)) {
    163     if (show_search_results)
    164       start_page_view_->ShowSearchResults();
    165     else
    166       start_page_view_->Reset();
    167   }
    168 
    169   // Notify parent AppListMainView of the page change.
    170   app_list_main_view_->UpdateSearchBoxVisibility();
    171 }
    172 
    173 void ContentsView::ShowSearchResults(bool show) {
    174   int search_page = GetPageIndexForNamedPage(
    175       app_list::switches::IsExperimentalAppListEnabled()
    176           ? NAMED_PAGE_START
    177           : NAMED_PAGE_SEARCH_RESULTS);
    178   DCHECK_GE(search_page, 0);
    179 
    180   SetActivePageInternal(show ? search_page : page_before_search_, show);
    181 }
    182 
    183 bool ContentsView::IsShowingSearchResults() const {
    184   return app_list::switches::IsExperimentalAppListEnabled()
    185              ? IsNamedPageActive(NAMED_PAGE_START) &&
    186                    start_page_view_->IsShowingSearchResults()
    187              : IsNamedPageActive(NAMED_PAGE_SEARCH_RESULTS);
    188 }
    189 
    190 gfx::Rect ContentsView::GetOffscreenPageBounds(int page_index) const {
    191   gfx::Rect bounds(GetContentsBounds());
    192   // The start page and search page origins are above; all other pages' origins
    193   // are below.
    194   int page_height = bounds.height();
    195   bool origin_above =
    196       GetPageIndexForNamedPage(NAMED_PAGE_START) == page_index ||
    197       GetPageIndexForNamedPage(NAMED_PAGE_SEARCH_RESULTS) == page_index;
    198   bounds.set_y(origin_above ? -page_height : page_height);
    199   return bounds;
    200 }
    201 
    202 void ContentsView::UpdatePageBounds() {
    203   // The bounds calculations will potentially be mid-transition (depending on
    204   // the state of the PaginationModel).
    205   int current_page = std::max(0, pagination_model_.selected_page());
    206   int target_page = current_page;
    207   double progress = 1;
    208   if (pagination_model_.has_transition()) {
    209     const PaginationModel::Transition& transition =
    210         pagination_model_.transition();
    211     if (pagination_model_.is_valid_page(transition.target_page)) {
    212       target_page = transition.target_page;
    213       progress = transition.progress;
    214     }
    215   }
    216 
    217   // Move |current_page| from 0 to its origin. Move |target_page| from its
    218   // origin to 0.
    219   gfx::Rect on_screen(GetContentsBounds());
    220   gfx::Rect current_page_origin(GetOffscreenPageBounds(current_page));
    221   gfx::Rect target_page_origin(GetOffscreenPageBounds(target_page));
    222   gfx::Rect current_page_rect(
    223       gfx::Tween::RectValueBetween(progress, on_screen, current_page_origin));
    224   gfx::Rect target_page_rect(
    225       gfx::Tween::RectValueBetween(progress, target_page_origin, on_screen));
    226 
    227   view_model_->view_at(current_page)->SetBoundsRect(current_page_rect);
    228   view_model_->view_at(target_page)->SetBoundsRect(target_page_rect);
    229 }
    230 
    231 PaginationModel* ContentsView::GetAppsPaginationModel() {
    232   return apps_container_view_->apps_grid_view()->pagination_model();
    233 }
    234 
    235 void ContentsView::ShowFolderContent(AppListFolderItem* item) {
    236   apps_container_view_->ShowActiveFolder(item);
    237 }
    238 
    239 void ContentsView::Prerender() {
    240   apps_container_view_->apps_grid_view()->Prerender();
    241 }
    242 
    243 views::View* ContentsView::GetPageView(int index) {
    244   return view_model_->view_at(index);
    245 }
    246 
    247 void ContentsView::AddBlankPageForTesting() {
    248   AddLauncherPage(new views::View, 0);
    249 }
    250 
    251 int ContentsView::AddLauncherPage(views::View* view, int resource_id) {
    252   int page_index = view_model_->view_size();
    253   AddChildView(view);
    254   view_model_->Add(view, page_index);
    255   if (contents_switcher_view_ && resource_id)
    256     contents_switcher_view_->AddSwitcherButton(resource_id, page_index);
    257   pagination_model_.SetTotalPages(view_model_->view_size());
    258   return page_index;
    259 }
    260 
    261 int ContentsView::AddLauncherPage(views::View* view,
    262                                   int resource_id,
    263                                   NamedPage named_page) {
    264   int page_index = AddLauncherPage(view, resource_id);
    265   named_page_to_view_.insert(std::pair<NamedPage, int>(named_page, page_index));
    266   return page_index;
    267 }
    268 
    269 gfx::Size ContentsView::GetPreferredSize() const {
    270   const gfx::Size container_size =
    271       apps_container_view_->apps_grid_view()->GetPreferredSize();
    272   const gfx::Size results_size = search_results_view_
    273                                      ? search_results_view_->GetPreferredSize()
    274                                      : gfx::Size();
    275 
    276   int width = std::max(container_size.width(), results_size.width());
    277   int height = std::max(container_size.height(), results_size.height());
    278   return gfx::Size(width, height);
    279 }
    280 
    281 void ContentsView::Layout() {
    282   // Immediately finish all current animations.
    283   pagination_model_.FinishAnimation();
    284 
    285   // Move the current view onto the screen, and all other views off screen to
    286   // the left. (Since we are not animating, we don't need to be careful about
    287   // which side we place the off-screen views onto.)
    288   gfx::Rect rect(GetContentsBounds());
    289   if (rect.IsEmpty())
    290     return;
    291 
    292   gfx::Rect offscreen_target(rect);
    293   offscreen_target.set_x(-rect.width());
    294 
    295   for (int i = 0; i < view_model_->view_size(); ++i) {
    296     view_model_->view_at(i)->SetBoundsRect(
    297         i == pagination_model_.SelectedTargetPage() ? rect : offscreen_target);
    298   }
    299 }
    300 
    301 bool ContentsView::OnKeyPressed(const ui::KeyEvent& event) {
    302   return view_model_->view_at(GetActivePageIndex())->OnKeyPressed(event);
    303 }
    304 
    305 void ContentsView::TotalPagesChanged() {
    306 }
    307 
    308 void ContentsView::SelectedPageChanged(int old_selected, int new_selected) {
    309 }
    310 
    311 void ContentsView::TransitionStarted() {
    312 }
    313 
    314 void ContentsView::TransitionChanged() {
    315   UpdatePageBounds();
    316 }
    317 
    318 }  // namespace app_list
    319