app_list_view_controller.mm revision 4e180b6a0b4720a9b8e9e959a882386f690f08ff
1e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu// Copyright 2013 The Chromium Authors. All rights reserved.
2e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu// Use of this source code is governed by a BSD-style license that can be
3e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu// found in the LICENSE file.
4e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu
5e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu#import "ui/app_list/cocoa/app_list_view_controller.h"
6e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu
7e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu#include "base/mac/foundation_util.h"
8e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu#include "base/strings/string_util.h"
9e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu#include "base/strings/sys_string_conversions.h"
10e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu#include "skia/ext/skia_utils_mac.h"
11e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu#include "ui/app_list/app_list_constants.h"
12e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu#include "ui/app_list/app_list_model.h"
13e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu#include "ui/app_list/app_list_model_observer.h"
14e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu#include "ui/app_list/app_list_view_delegate.h"
15e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu#include "ui/app_list/signin_delegate.h"
16e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu#import "ui/app_list/cocoa/app_list_pager_view.h"
17e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu#import "ui/app_list/cocoa/apps_grid_controller.h"
18e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu#import "ui/app_list/cocoa/signin_view_controller.h"
19e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu#import "ui/base/cocoa/flipped_view.h"
20e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu#include "ui/app_list/search_box_model.h"
21e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu#include "ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h"
22e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu
23e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugunamespace {
24e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu
25e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu// The roundedness of the corners of the bubble.
26e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modaduguconst CGFloat kBubbleCornerRadius = 3;
27e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu
28e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu// Height of the pager.
29e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modaduguconst CGFloat kPagerPreferredHeight = 57;
30e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu
31e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu// Height of separator line drawn between the searchbox and grid view.
32e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modaduguconst CGFloat kTopSeparatorSize = 1;
33e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu
34e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu// Height of the search input.
35e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modaduguconst CGFloat kSearchInputHeight = 48;
36e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu
37e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu// Minimum margin on either side of the pager. If the pager grows beyond this,
38e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu// the segment size is reduced.
39e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modaduguconst CGFloat kMinPagerMargin = 40;
40e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu// Maximum width of a single segment.
41e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modaduguconst CGFloat kMaxSegmentWidth = 80;
42e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu
43e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu// Duration of the animation for sliding in and out search results.
44e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modaduguconst NSTimeInterval kResultsAnimationDuration = 0.2;
45e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu
46e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu}  // namespace
47e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu
48e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu@interface BackgroundView : FlippedView;
49e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu@end
50e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu
51e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu@implementation BackgroundView
52e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu
53e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu- (void)drawRect:(NSRect)dirtyRect {
54e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  gfx::ScopedNSGraphicsContextSaveGState context;
55e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  NSRect boundsRect = [self bounds];
56e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  NSRect searchAreaRect = NSMakeRect(0, 0,
57e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu                                     NSWidth(boundsRect), kSearchInputHeight);
58e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  NSRect separatorRect = NSMakeRect(0, NSMaxY(searchAreaRect),
59e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu                                    NSWidth(boundsRect), kTopSeparatorSize);
60e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu
61e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  [[NSBezierPath bezierPathWithRoundedRect:boundsRect
62e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu                                   xRadius:kBubbleCornerRadius
63e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu                                   yRadius:kBubbleCornerRadius] addClip];
64e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu
65e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  [gfx::SkColorToSRGBNSColor(app_list::kContentsBackgroundColor) set];
66e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  NSRectFill(boundsRect);
67e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  [gfx::SkColorToSRGBNSColor(app_list::kSearchBoxBackground) set];
68e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  NSRectFill(searchAreaRect);
69e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  [gfx::SkColorToSRGBNSColor(app_list::kTopSeparatorColor) set];
70e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  NSRectFill(separatorRect);
71e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu}
72e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu
73e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu@end
74e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu
75e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu@interface AppListViewController ()
76e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu
77e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu- (void)loadAndSetView;
78e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu- (void)revealSearchResults:(BOOL)show;
79e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu
80e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu@end
81e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu
82e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugunamespace app_list {
83e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu
84e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modaduguclass AppListModelObserverBridge : public AppListModelObserver {
85e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu public:
86e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  AppListModelObserverBridge(AppListViewController* parent);
87e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  virtual ~AppListModelObserverBridge();
88e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu
89e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu private:
90e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  // Overridden from app_list::AppListModelObserver:
91e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  virtual void OnAppListModelUsersChanged() OVERRIDE;
92e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  virtual void OnAppListModelSigninStatusChanged() OVERRIDE;
93e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu
94e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  AppListViewController* parent_;  // Weak. Owns us.
95e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu
96e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  DISALLOW_COPY_AND_ASSIGN(AppListModelObserverBridge);
97e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu};
98e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu
99e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra ModaduguAppListModelObserverBridge::AppListModelObserverBridge(
100e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu    AppListViewController* parent)
101e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu    : parent_(parent) {
102e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  [[parent_ appsGridController] model]->AddObserver(this);
103e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu}
104e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu
105e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra ModaduguAppListModelObserverBridge::~AppListModelObserverBridge() {
106e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  [[parent_ appsGridController] model]->RemoveObserver(this);
107e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu}
108e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu
109e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modaduguvoid AppListModelObserverBridge::OnAppListModelUsersChanged() {
110e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  [parent_ onSigninStatusChanged];
111e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu}
112e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu
113e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modaduguvoid AppListModelObserverBridge::OnAppListModelSigninStatusChanged() {
114e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  [parent_ onSigninStatusChanged];
115e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu}
116e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu
117e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu}  // namespace app_list
118e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu
119e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu@implementation AppListViewController
120e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu
121e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu- (id)init {
122e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  if ((self = [super init])) {
123e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu    appsGridController_.reset([[AppsGridController alloc] init]);
124e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu    [self loadAndSetView];
125e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu
126e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu    [self totalPagesChanged];
127e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu    [self selectedPageChanged:0];
128e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu    [appsGridController_ setPaginationObserver:self];
129e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  }
130e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  return self;
131e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu}
132e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu
133e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu- (void)dealloc {
134e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  // Ensure that setDelegate(NULL) has been called before destruction, because
135e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  // dealloc can be called at odd times, and Objective C destruction order does
136221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom  // not properly tear down these dependencies.
137e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  DCHECK(delegate_ == NULL);
138e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  [appsGridController_ setPaginationObserver:nil];
139e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  [super dealloc];
140e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu}
141e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu
142e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu- (AppsGridController*)appsGridController {
143e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  return appsGridController_;
144e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu}
145e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu
146e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu- (NSSegmentedControl*)pagerControl {
147e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  return pagerControl_;
148e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu}
149e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu
150e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu- (NSView*)backgroundView {
151e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  return backgroundView_;
152e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu}
153e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu
154e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu- (app_list::AppListViewDelegate*)delegate {
155e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  return delegate_.get();
156e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu}
157e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu
158e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu- (void)setDelegate:(scoped_ptr<app_list::AppListViewDelegate>)newDelegate
159e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu      withTestModel:(scoped_ptr<app_list::AppListModel>)newModel {
160e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  if (delegate_) {
161e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu    // First clean up, in reverse order.
162e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu    app_list_model_observer_bridge_.reset();
163e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu    [appsSearchResultsController_ setDelegate:nil];
164e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu    [appsSearchBoxController_ setDelegate:nil];
165e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  }
166e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  delegate_.reset(newDelegate.release());
167e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  [appsGridController_ setDelegate:delegate_.get()];
168e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  if (newModel.get())
169e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu    [appsGridController_ setModel:newModel.Pass()];
170e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  [appsSearchBoxController_ setDelegate:self];
171e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  [appsSearchResultsController_ setDelegate:self];
172e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  app_list_model_observer_bridge_.reset(
173e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu      new app_list::AppListModelObserverBridge(self));
174221304ee937bc0910948a8be1320cb8cc4eb6d36Brian Carlstrom  [self onSigninStatusChanged];
175e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu}
176e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu
177e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu- (void)setDelegate:(scoped_ptr<app_list::AppListViewDelegate>)newDelegate {
178e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  [self setDelegate:newDelegate.Pass()
179e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu      withTestModel:scoped_ptr<app_list::AppListModel>()];
180e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu}
181e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu
182e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu-(void)loadAndSetView {
183e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  pagerControl_.reset([[AppListPagerView alloc] init]);
184e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  [pagerControl_ setTarget:appsGridController_];
185e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  [pagerControl_ setAction:@selector(onPagerClicked:)];
186e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu
187e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  NSRect gridFrame = [[appsGridController_ view] frame];
188e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  NSRect contentsRect = NSMakeRect(0, kSearchInputHeight + kTopSeparatorSize,
189e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu      NSWidth(gridFrame), NSHeight(gridFrame) + kPagerPreferredHeight -
190e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu          [AppsGridController scrollerPadding]);
191e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu
192e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  contentsView_.reset([[FlippedView alloc] initWithFrame:contentsRect]);
193e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  backgroundView_.reset(
194e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu      [[BackgroundView alloc] initWithFrame:
195e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu              NSMakeRect(0, 0, NSMaxX(contentsRect), NSMaxY(contentsRect))]);
196e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  appsSearchBoxController_.reset(
197e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu      [[AppsSearchBoxController alloc] initWithFrame:
198e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu          NSMakeRect(0, 0, NSWidth(contentsRect), kSearchInputHeight)]);
199e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  appsSearchResultsController_.reset(
200e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu      [[AppsSearchResultsController alloc] initWithAppsSearchResultsFrameSize:
201e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu          [contentsView_ bounds].size]);
202e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  base::scoped_nsobject<NSView> containerView(
203e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu      [[NSView alloc] initWithFrame:[backgroundView_ frame]]);
204e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu
205e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  [contentsView_ addSubview:[appsGridController_ view]];
206e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  [contentsView_ addSubview:pagerControl_];
207e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  [backgroundView_ addSubview:contentsView_];
208e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  [backgroundView_ addSubview:[appsSearchResultsController_ view]];
209e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  [backgroundView_ addSubview:[appsSearchBoxController_ view]];
210e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  [containerView addSubview:backgroundView_];
211e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  [self setView:containerView];
212e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu}
213e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu
214e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu- (void)revealSearchResults:(BOOL)show {
215e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  if (show == showingSearchResults_)
216e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu    return;
217e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu
218e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  showingSearchResults_ = show;
219e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  NSSize contentsSize = [contentsView_ frame].size;
220e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  NSRect resultsTargetRect = NSMakeRect(
221e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu      0, kSearchInputHeight + kTopSeparatorSize,
222e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu      contentsSize.width, contentsSize.height);
223e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  NSRect contentsTargetRect = resultsTargetRect;
224e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu
225e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  // Shows results by sliding the grid and pager down to the bottom of the view.
226e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  // Hides results by collapsing the search results container to a height of 0.
227e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  if (show)
228e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu    contentsTargetRect.origin.y += NSHeight(contentsTargetRect);
229e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  else
230e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu    resultsTargetRect.size.height = 0;
231e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu
232e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  [[NSAnimationContext currentContext] setDuration:kResultsAnimationDuration];
233e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  [[contentsView_ animator] setFrame:contentsTargetRect];
234e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  [[[appsSearchResultsController_ view] animator] setFrame:resultsTargetRect];
235e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu}
236e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu
237e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu- (void)totalPagesChanged {
238e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  size_t pageCount = [appsGridController_ pageCount];
239e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  [pagerControl_ setSegmentCount:pageCount];
240e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu
241e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  NSRect viewFrame = [[pagerControl_ superview] bounds];
242e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  CGFloat segmentWidth = std::min(
243e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu      kMaxSegmentWidth,
244e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu      (viewFrame.size.width - 2 * kMinPagerMargin) / pageCount);
245e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu
246e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  for (size_t i = 0; i < pageCount; ++i) {
247e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu    [pagerControl_ setWidth:segmentWidth
248e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu                 forSegment:i];
249e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu    [[pagerControl_ cell] setTag:i
250e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu                      forSegment:i];
251e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  }
252e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu
253e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  // Center in view.
254e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  [pagerControl_ sizeToFit];
255e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  [pagerControl_ setFrame:
256e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu      NSMakeRect(NSMidX(viewFrame) - NSMidX([pagerControl_ bounds]),
257e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu                 viewFrame.size.height - kPagerPreferredHeight,
258e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu                 [pagerControl_ bounds].size.width,
259e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu                 kPagerPreferredHeight)];
260e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu}
261e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu
262e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu- (void)selectedPageChanged:(int)newSelected {
263e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  [pagerControl_ selectSegmentWithTag:newSelected];
264e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu}
265e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu
266e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu- (void)pageVisibilityChanged {
267e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  [pagerControl_ setNeedsDisplay:YES];
268e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu}
269e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu
270e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu- (NSInteger)pagerSegmentAtLocation:(NSPoint)locationInWindow {
271e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  return [pagerControl_ findAndHighlightSegmentAtLocation:locationInWindow];
272e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu}
273e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu
274e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu- (app_list::SearchBoxModel*)searchBoxModel {
275e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  app_list::AppListModel* appListModel = [appsGridController_ model];
276e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  return appListModel ? appListModel->search_box() : NULL;
277e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu}
278e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu
279e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu- (app_list::AppListViewDelegate*)appListDelegate {
280e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  return [self delegate];
281e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu}
282e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu
283e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu- (BOOL)control:(NSControl*)control
284e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu               textView:(NSTextView*)textView
285976a034585c7e8ff9dda5ebe032f399b78887f70Brian Carlstrom    doCommandBySelector:(SEL)command {
286976a034585c7e8ff9dda5ebe032f399b78887f70Brian Carlstrom  if (showingSearchResults_)
287976a034585c7e8ff9dda5ebe032f399b78887f70Brian Carlstrom    return [appsSearchResultsController_ handleCommandBySelector:command];
288976a034585c7e8ff9dda5ebe032f399b78887f70Brian Carlstrom
289976a034585c7e8ff9dda5ebe032f399b78887f70Brian Carlstrom  // If anything has been written, let the search view handle it.
290976a034585c7e8ff9dda5ebe032f399b78887f70Brian Carlstrom  if ([[control stringValue] length] > 0)
291976a034585c7e8ff9dda5ebe032f399b78887f70Brian Carlstrom    return NO;
292976a034585c7e8ff9dda5ebe032f399b78887f70Brian Carlstrom
293976a034585c7e8ff9dda5ebe032f399b78887f70Brian Carlstrom  // Handle escape.
294976a034585c7e8ff9dda5ebe032f399b78887f70Brian Carlstrom  if (command == @selector(complete:) ||
295976a034585c7e8ff9dda5ebe032f399b78887f70Brian Carlstrom      command == @selector(cancel:) ||
296976a034585c7e8ff9dda5ebe032f399b78887f70Brian Carlstrom      command == @selector(cancelOperation:)) {
297976a034585c7e8ff9dda5ebe032f399b78887f70Brian Carlstrom    if (delegate_)
298976a034585c7e8ff9dda5ebe032f399b78887f70Brian Carlstrom      delegate_->Dismiss();
299976a034585c7e8ff9dda5ebe032f399b78887f70Brian Carlstrom    return YES;
300976a034585c7e8ff9dda5ebe032f399b78887f70Brian Carlstrom  }
301976a034585c7e8ff9dda5ebe032f399b78887f70Brian Carlstrom
302e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  // Possibly handle grid navigation.
303e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  return [appsGridController_ handleCommandBySelector:command];
304976a034585c7e8ff9dda5ebe032f399b78887f70Brian Carlstrom}
305976a034585c7e8ff9dda5ebe032f399b78887f70Brian Carlstrom
306976a034585c7e8ff9dda5ebe032f399b78887f70Brian Carlstrom- (void)modelTextDidChange {
307976a034585c7e8ff9dda5ebe032f399b78887f70Brian Carlstrom  app_list::SearchBoxModel* searchBoxModel = [self searchBoxModel];
308976a034585c7e8ff9dda5ebe032f399b78887f70Brian Carlstrom  if (!searchBoxModel || !delegate_)
309976a034585c7e8ff9dda5ebe032f399b78887f70Brian Carlstrom    return;
310976a034585c7e8ff9dda5ebe032f399b78887f70Brian Carlstrom
311976a034585c7e8ff9dda5ebe032f399b78887f70Brian Carlstrom  base::string16 query;
312976a034585c7e8ff9dda5ebe032f399b78887f70Brian Carlstrom  TrimWhitespace(searchBoxModel->text(), TRIM_ALL, &query);
313976a034585c7e8ff9dda5ebe032f399b78887f70Brian Carlstrom  BOOL shouldShowSearch = !query.empty();
314976a034585c7e8ff9dda5ebe032f399b78887f70Brian Carlstrom  [self revealSearchResults:shouldShowSearch];
315976a034585c7e8ff9dda5ebe032f399b78887f70Brian Carlstrom  if (shouldShowSearch)
316e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu    delegate_->StartSearch();
317e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  else
318e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu    delegate_->StopSearch();
319e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu}
320e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu
321e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu- (app_list::AppListModel*)appListModel {
322e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  return [appsGridController_ model];
323e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu}
324e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu
325e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu- (void)openResult:(app_list::SearchResult*)result {
326e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  if (delegate_)
327e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu    delegate_->OpenSearchResult(result, 0 /* event flags */);
328e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu
329e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  [appsSearchBoxController_ clearSearch];
330e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu}
331e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu
332e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu- (void)redoSearch {
333e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  [self modelTextDidChange];
334e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu}
335e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu
336e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu- (void)onSigninStatusChanged {
337e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  [appsSearchBoxController_ rebuildMenu];
338e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  app_list::SigninDelegate* signinDelegate =
339e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu      delegate_ ? delegate_->GetSigninDelegate() : NULL;
340e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  BOOL show_signin_view =
341e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu      signinDelegate && ![appsGridController_ model]->signed_in();
342e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu
343e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  [[signinViewController_ view] removeFromSuperview];
344e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  signinViewController_.reset();
345e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu
346e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  if (!show_signin_view) {
347e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu    [backgroundView_ setHidden:NO];
348e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu    return;
349e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  }
350e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu
351e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  [backgroundView_ setHidden:YES];
352e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  signinViewController_.reset(
353e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu      [[SigninViewController alloc] initWithFrame:[backgroundView_ frame]
354e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu                                     cornerRadius:kBubbleCornerRadius
355e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu                                         delegate:signinDelegate]);
356e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu  [[self view] addSubview:[signinViewController_ view]];
357e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu}
358e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu
359e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu@end
360e45f106cb6b47af1f21efe76e933bdea2f5dd1caNagendra Modadugu