Home | History | Annotate | Download | only in views
      1 // Copyright 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/app_list_main_view.h"
      6 
      7 #include <algorithm>
      8 
      9 #include "base/callback.h"
     10 #include "base/files/file_path.h"
     11 #include "base/strings/string_util.h"
     12 #include "ui/app_list/app_list_constants.h"
     13 #include "ui/app_list/app_list_item_model.h"
     14 #include "ui/app_list/app_list_model.h"
     15 #include "ui/app_list/app_list_view_delegate.h"
     16 #include "ui/app_list/pagination_model.h"
     17 #include "ui/app_list/search_box_model.h"
     18 #include "ui/app_list/views/app_list_item_view.h"
     19 #include "ui/app_list/views/contents_view.h"
     20 #include "ui/app_list/views/search_box_view.h"
     21 #include "ui/views/controls/textfield/textfield.h"
     22 #include "ui/views/layout/box_layout.h"
     23 #include "ui/views/widget/widget.h"
     24 
     25 namespace app_list {
     26 
     27 namespace {
     28 
     29 // Inner padding space in pixels of bubble contents.
     30 const int kInnerPadding = 1;
     31 
     32 // The maximum allowed time to wait for icon loading in milliseconds.
     33 const int kMaxIconLoadingWaitTimeInMs = 50;
     34 
     35 }  // namespace
     36 
     37 ////////////////////////////////////////////////////////////////////////////////
     38 // AppListMainView::IconLoader
     39 
     40 class AppListMainView::IconLoader : public AppListItemModelObserver {
     41  public:
     42   IconLoader(AppListMainView* owner,
     43              AppListItemModel* item,
     44              ui::ScaleFactor scale_factor)
     45       : owner_(owner),
     46         item_(item) {
     47     item_->AddObserver(this);
     48 
     49     // Triggers icon loading for given |scale_factor|.
     50     item_->icon().GetRepresentation(scale_factor);
     51   }
     52 
     53   virtual ~IconLoader() {
     54     item_->RemoveObserver(this);
     55   }
     56 
     57  private:
     58   // AppListItemModelObserver overrides:
     59   virtual void ItemIconChanged() OVERRIDE {
     60     owner_->OnItemIconLoaded(this);
     61     // Note that IconLoader is released here.
     62   }
     63   virtual void ItemTitleChanged() OVERRIDE {}
     64   virtual void ItemHighlightedChanged() OVERRIDE {}
     65   virtual void ItemIsInstallingChanged() OVERRIDE {}
     66   virtual void ItemPercentDownloadedChanged() OVERRIDE {}
     67 
     68   AppListMainView* owner_;
     69   AppListItemModel* item_;
     70 
     71   DISALLOW_COPY_AND_ASSIGN(IconLoader);
     72 };
     73 
     74 ////////////////////////////////////////////////////////////////////////////////
     75 // AppListMainView:
     76 
     77 AppListMainView::AppListMainView(AppListViewDelegate* delegate,
     78                                  AppListModel* model,
     79                                  PaginationModel* pagination_model,
     80                                  views::View* anchor)
     81     : delegate_(delegate),
     82       model_(model),
     83       search_box_view_(NULL),
     84       contents_view_(NULL) {
     85   // Starts icon loading early.
     86   PreloadIcons(pagination_model, anchor);
     87 
     88   SetLayoutManager(new views::BoxLayout(views::BoxLayout::kVertical,
     89                                         kInnerPadding,
     90                                         kInnerPadding,
     91                                         kInnerPadding));
     92 
     93   search_box_view_ = new SearchBoxView(this, delegate, model_);
     94   AddChildView(search_box_view_);
     95 
     96   contents_view_ = new ContentsView(this, pagination_model, model_);
     97   AddChildView(contents_view_);
     98 
     99   search_box_view_->set_contents_view(contents_view_);
    100 
    101 #if defined(USE_AURA)
    102   contents_view_->SetPaintToLayer(true);
    103   contents_view_->SetFillsBoundsOpaquely(false);
    104   contents_view_->layer()->SetMasksToBounds(true);
    105 #endif
    106 }
    107 
    108 AppListMainView::~AppListMainView() {
    109   pending_icon_loaders_.clear();
    110 }
    111 
    112 void AppListMainView::ShowAppListWhenReady() {
    113   if (pending_icon_loaders_.empty()) {
    114     icon_loading_wait_timer_.Stop();
    115     GetWidget()->Show();
    116     return;
    117   }
    118 
    119   if (icon_loading_wait_timer_.IsRunning())
    120     return;
    121 
    122   icon_loading_wait_timer_.Start(
    123       FROM_HERE,
    124       base::TimeDelta::FromMilliseconds(kMaxIconLoadingWaitTimeInMs),
    125       this, &AppListMainView::OnIconLoadingWaitTimer);
    126 }
    127 
    128 void AppListMainView::Close() {
    129   icon_loading_wait_timer_.Stop();
    130 }
    131 
    132 void AppListMainView::Prerender() {
    133   contents_view_->Prerender();
    134 }
    135 
    136 void AppListMainView::SetDragAndDropHostOfCurrentAppList(
    137     app_list::ApplicationDragAndDropHost* drag_and_drop_host) {
    138   contents_view_->SetDragAndDropHostOfCurrentAppList(drag_and_drop_host);
    139 }
    140 
    141 void AppListMainView::PreloadIcons(PaginationModel* pagination_model,
    142                                    views::View* anchor) {
    143   ui::ScaleFactor scale_factor = ui::SCALE_FACTOR_100P;
    144   if (anchor && anchor->GetWidget()) {
    145     scale_factor = ui::GetScaleFactorForNativeView(
    146         anchor->GetWidget()->GetNativeView());
    147   }
    148 
    149   // |pagination_model| could have -1 as the initial selected page and
    150   // assumes first page (i.e. index 0) will be used in this case.
    151   const int selected_page = std::max(0, pagination_model->selected_page());
    152 
    153   const int tiles_per_page = kPreferredCols * kPreferredRows;
    154   const int start_model_index = selected_page * tiles_per_page;
    155   const int end_model_index = std::min(
    156       static_cast<int>(model_->apps()->item_count()),
    157       start_model_index + tiles_per_page);
    158 
    159   pending_icon_loaders_.clear();
    160   for (int i = start_model_index; i < end_model_index; ++i) {
    161     AppListItemModel* item = model_->apps()->GetItemAt(i);
    162     if (item->icon().HasRepresentation(scale_factor))
    163       continue;
    164 
    165     pending_icon_loaders_.push_back(new IconLoader(this, item, scale_factor));
    166   }
    167 }
    168 
    169 void AppListMainView::OnIconLoadingWaitTimer() {
    170   GetWidget()->Show();
    171 }
    172 
    173 void AppListMainView::OnItemIconLoaded(IconLoader* loader) {
    174   ScopedVector<IconLoader>::iterator it = std::find(
    175       pending_icon_loaders_.begin(), pending_icon_loaders_.end(), loader);
    176   DCHECK(it != pending_icon_loaders_.end());
    177   pending_icon_loaders_.erase(it);
    178 
    179   if (pending_icon_loaders_.empty() && icon_loading_wait_timer_.IsRunning()) {
    180     icon_loading_wait_timer_.Stop();
    181     GetWidget()->Show();
    182   }
    183 }
    184 
    185 void AppListMainView::ActivateApp(AppListItemModel* item, int event_flags) {
    186   if (delegate_)
    187     delegate_->ActivateAppListItem(item, event_flags);
    188 }
    189 
    190 void AppListMainView::GetShortcutPathForApp(
    191     const std::string& app_id,
    192     const base::Callback<void(const base::FilePath&)>& callback) {
    193   if (delegate_) {
    194     delegate_->GetShortcutPathForApp(app_id, callback);
    195     return;
    196   }
    197   callback.Run(base::FilePath());
    198 }
    199 
    200 void AppListMainView::QueryChanged(SearchBoxView* sender) {
    201   base::string16 query;
    202   TrimWhitespace(model_->search_box()->text(), TRIM_ALL, &query);
    203   bool should_show_search = !query.empty();
    204   contents_view_->ShowSearchResults(should_show_search);
    205 
    206   if (delegate_) {
    207     if (should_show_search)
    208       delegate_->StartSearch();
    209     else
    210       delegate_->StopSearch();
    211   }
    212 }
    213 
    214 void AppListMainView::OpenResult(SearchResult* result, int event_flags) {
    215   if (delegate_)
    216     delegate_->OpenSearchResult(result, event_flags);
    217 }
    218 
    219 void AppListMainView::InvokeResultAction(SearchResult* result,
    220                                          int action_index,
    221                                          int event_flags) {
    222   if (delegate_)
    223     delegate_->InvokeSearchResultAction(result, action_index, event_flags);
    224 }
    225 
    226 void AppListMainView::OnResultInstalled(SearchResult* result) {
    227   // Clears the search to show the apps grid. The last installed app
    228   // should be highlighted and made visible already.
    229   search_box_view_->ClearSearch();
    230 }
    231 
    232 void AppListMainView::OnResultUninstalled(SearchResult* result) {
    233   QueryChanged(search_box_view_);
    234 }
    235 
    236 }  // namespace app_list
    237