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