apps_search_results_model_bridge.mm revision 3551c9c881056c480085172ff9840cab31610854
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#import "ui/app_list/cocoa/apps_search_results_model_bridge.h"
6
7#import <Cocoa/Cocoa.h>
8
9#include "base/strings/sys_string_conversions.h"
10#include "ui/app_list/app_list_model.h"
11#import "ui/app_list/cocoa/apps_search_results_controller.h"
12#include "ui/app_list/search_result.h"
13#include "ui/app_list/search_result_observer.h"
14#import "ui/base/cocoa/menu_controller.h"
15
16namespace app_list {
17
18class AppsSearchResultsModelBridge::ItemObserver : public SearchResultObserver {
19 public:
20  ItemObserver(AppsSearchResultsModelBridge* bridge, size_t index)
21      : bridge_(bridge), row_in_view_(index) {
22    // Cache the result, because the results array is updated before notifying
23    // observers (which happens before deleting the SearchResult).
24    result_ = [bridge_->parent_ results]->GetItemAt(index);
25    result_->AddObserver(this);
26  }
27
28  virtual ~ItemObserver() {
29    result_->RemoveObserver(this);
30  }
31
32  NSMenu* GetContextMenu() {
33    if (!context_menu_controller_) {
34      context_menu_controller_.reset(
35          [[MenuController alloc] initWithModel:result_->GetContextMenuModel()
36                         useWithPopUpButtonCell:NO]);
37    }
38    return [context_menu_controller_ menu];
39  }
40
41  // SearchResultObserver overrides:
42  virtual void OnIconChanged() OVERRIDE {
43    bridge_->ReloadDataForItems(row_in_view_, 1);
44  }
45  virtual void OnActionsChanged() OVERRIDE {}
46  virtual void OnIsInstallingChanged() OVERRIDE {}
47  virtual void OnPercentDownloadedChanged() OVERRIDE {}
48  virtual void OnItemInstalled() OVERRIDE {}
49  virtual void OnItemUninstalled() OVERRIDE;
50
51 private:
52  AppsSearchResultsModelBridge* bridge_;  // Weak. Owns us.
53  SearchResult* result_;  // Weak. Owned by AppListModel::SearchResults.
54  size_t row_in_view_;
55  base::scoped_nsobject<MenuController> context_menu_controller_;
56
57  DISALLOW_COPY_AND_ASSIGN(ItemObserver);
58};
59
60void AppsSearchResultsModelBridge::ItemObserver::OnItemUninstalled() {
61  // Performing the search again will destroy |this|, so post a task. This also
62  // ensures that the AppSearchProvider has observed the uninstall before
63  // performing the search again, otherwise it will provide a NULL result.
64  [[bridge_->parent_ delegate] performSelector:@selector(redoSearch)
65                                    withObject:nil
66                                    afterDelay:0];
67}
68
69AppsSearchResultsModelBridge::AppsSearchResultsModelBridge(
70    AppsSearchResultsController* results_controller)
71    : parent_(results_controller) {
72  UpdateItemObservers();
73  [parent_ results]->AddObserver(this);
74}
75
76AppsSearchResultsModelBridge::~AppsSearchResultsModelBridge() {
77  [parent_ results]->RemoveObserver(this);
78}
79
80NSMenu* AppsSearchResultsModelBridge::MenuForItem(size_t index) {
81  DCHECK_LT(index, item_observers_.size());
82  return item_observers_[index]->GetContextMenu();
83}
84
85void AppsSearchResultsModelBridge::UpdateItemObservers() {
86  DCHECK(item_observers_.empty());
87  const size_t itemCount = [parent_ results]->item_count();
88  for (size_t i = 0 ; i < itemCount; ++i)
89    item_observers_.push_back(new ItemObserver(this, i));
90}
91
92void AppsSearchResultsModelBridge::ReloadDataForItems(
93    size_t start, size_t count) const {
94  NSIndexSet* column = [NSIndexSet indexSetWithIndex:0];
95  NSIndexSet* rows =
96      [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(start, count)];
97  [[parent_ tableView] reloadDataForRowIndexes:rows
98                                 columnIndexes:column];
99}
100
101void AppsSearchResultsModelBridge::ListItemsAdded(
102    size_t start, size_t count) {
103  item_observers_.clear();
104  if (start == static_cast<size_t>([[parent_ tableView] numberOfRows]))
105    [[parent_ tableView] noteNumberOfRowsChanged];
106  else
107    [[parent_ tableView] reloadData];
108  UpdateItemObservers();
109}
110
111void AppsSearchResultsModelBridge::ListItemsRemoved(
112    size_t start, size_t count) {
113  item_observers_.clear();
114  if (start == [parent_ results]->item_count())
115    [[parent_ tableView] noteNumberOfRowsChanged];
116  else
117    [[parent_ tableView] reloadData];
118  UpdateItemObservers();
119}
120
121void AppsSearchResultsModelBridge::ListItemMoved(
122    size_t index, size_t target_index) {
123  NOTREACHED();
124}
125
126void AppsSearchResultsModelBridge::ListItemsChanged(
127    size_t start, size_t count) {
128  item_observers_.clear();
129  ReloadDataForItems(start, count);
130  UpdateItemObservers();
131}
132
133}  // namespace app_list
134