cygprofile: increase timeouts to allow showing web contents
[chromium-blink-merge.git] / chrome / browser / ui / cocoa / omnibox / omnibox_popup_matrix.mm
blobc3dc7e6afd3619ad3405343af3e5c689df680a7c
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.
5 #import "chrome/browser/ui/cocoa/omnibox/omnibox_popup_matrix.h"
7 #include "base/logging.h"
8 #include "base/mac/foundation_util.h"
9 #import "chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.h"
10 #include "chrome/browser/ui/cocoa/omnibox/omnibox_popup_view_mac.h"
11 #include "chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.h"
12 #include "components/omnibox/browser/autocomplete_result.h"
14 namespace {
16 // NSEvent -buttonNumber for middle mouse button.
17 const NSInteger kMiddleButtonNumber = 2;
19 }  // namespace
21 @interface OmniboxPopupMatrix ()
22 - (OmniboxPopupTableController*)controller;
23 - (void)resetTrackingArea;
24 - (void)highlightRowUnder:(NSEvent*)theEvent;
25 - (BOOL)selectCellForEvent:(NSEvent*)theEvent;
26 @end
28 @implementation OmniboxPopupTableController
30 - (instancetype)initWithMatchResults:(const AutocompleteResult&)result
31                            tableView:(OmniboxPopupMatrix*)tableView
32                            popupView:(const OmniboxPopupViewMac&)popupView
33                          answerImage:(NSImage*)answerImage {
34   base::scoped_nsobject<NSMutableArray> array([[NSMutableArray alloc] init]);
35   CGFloat max_match_contents_width = 0.0f;
36   CGFloat contentsOffset = -1.0f;
37   for (const AutocompleteMatch& match : result) {
38     if (match.type == AutocompleteMatchType::SEARCH_SUGGEST_TAIL &&
39         contentsOffset < 0.0f)
40       contentsOffset = [OmniboxPopupCell computeContentsOffset:match];
41     base::scoped_nsobject<OmniboxPopupCellData> cellData(
42         [[OmniboxPopupCellData alloc]
43              initWithMatch:match
44             contentsOffset:contentsOffset
45                      image:popupView.ImageForMatch(match)
46                answerImage:(match.answer ? answerImage : nil)]);
47     [array addObject:cellData];
48     if (match.type == AutocompleteMatchType::SEARCH_SUGGEST_TAIL) {
49       max_match_contents_width =
50           std::max(max_match_contents_width, [cellData getMatchContentsWidth]);
51     }
52   }
54   [tableView setMaxMatchContentsWidth:max_match_contents_width];
55   return [self initWithArray:array];
58 - (instancetype)initWithArray:(NSArray*)array {
59   if ((self = [super init])) {
60     hoveredIndex_ = -1;
61     array_.reset([array copy]);
62   }
63   return self;
66 - (NSInteger)numberOfRowsInTableView:(NSTableView*)tableView {
67   return [array_ count];
70 - (id)tableView:(NSTableView*)tableView
71     objectValueForTableColumn:(NSTableColumn*)tableColumn
72                           row:(NSInteger)rowIndex {
73   return [array_ objectAtIndex:rowIndex];
76 - (void)tableView:(NSTableView*)tableView
77     setObjectValue:(id)object
78     forTableColumn:(NSTableColumn*)tableColumn
79                row:(NSInteger)rowIndex {
80   NOTREACHED();
83 - (void)tableView:(NSTableView*)tableView
84     willDisplayCell:(id)cell
85      forTableColumn:(NSTableColumn*)tableColumn
86                 row:(NSInteger)rowIndex {
87   OmniboxPopupCell* popupCell =
88       base::mac::ObjCCastStrict<OmniboxPopupCell>(cell);
89   [popupCell
90       setState:([tableView selectedRow] == rowIndex) ? NSOnState : NSOffState];
91   [popupCell highlight:(hoveredIndex_ == rowIndex)
92              withFrame:[tableView bounds]
93                 inView:tableView];
96 - (NSInteger)highlightedRow {
97   return hoveredIndex_;
100 - (void)setHighlightedRow:(NSInteger)rowIndex {
101   hoveredIndex_ = rowIndex;
104 - (CGFloat)tableView:(NSTableView*)tableView heightOfRow:(NSInteger)row {
105   CGFloat height = kContentLineHeight;
106   if ([[array_ objectAtIndex:row] isAnswer]) {
107     OmniboxPopupMatrix* matrix =
108         base::mac::ObjCCastStrict<OmniboxPopupMatrix>(tableView);
109     height += [matrix answerLineHeight];
110   }
111   return height;
114 @end
116 @implementation OmniboxPopupMatrix
118 @synthesize separator = separator_;
119 @synthesize maxMatchContentsWidth = maxMatchContentsWidth_;
120 @synthesize answerLineHeight = answerLineHeight_;
122 - (instancetype)initWithObserver:(OmniboxPopupMatrixObserver*)observer {
123   if ((self = [super initWithFrame:NSZeroRect])) {
124     observer_ = observer;
126     base::scoped_nsobject<NSTableColumn> column(
127         [[NSTableColumn alloc] initWithIdentifier:@"MainColumn"]);
128     [column setDataCell:[[[OmniboxPopupCell alloc] init] autorelease]];
129     [self addTableColumn:column];
131     // Cells pack with no spacing.
132     [self setIntercellSpacing:NSMakeSize(0.0, 0.0)];
134     [self setSelectionHighlightStyle:NSTableViewSelectionHighlightStyleNone];
135     [self setBackgroundColor:[NSColor controlBackgroundColor]];
136     [self setAllowsEmptySelection:YES];
137     [self deselectAll:self];
139     [self resetTrackingArea];
141     base::scoped_nsobject<NSLayoutManager> layoutManager(
142         [[NSLayoutManager alloc] init]);
143     answerLineHeight_ =
144         [layoutManager defaultLineHeightForFont:OmniboxViewMac::GetLargeFont(
145                                                     gfx::Font::NORMAL)];
146   }
147   return self;
150 - (OmniboxPopupTableController*)controller {
151   return base::mac::ObjCCastStrict<OmniboxPopupTableController>(
152       [self delegate]);
155 - (void)setObserver:(OmniboxPopupMatrixObserver*)observer {
156   observer_ = observer;
159 - (void)updateTrackingAreas {
160   [self resetTrackingArea];
161   [super updateTrackingAreas];
164 // Callbacks from tracking area.
165 - (void)mouseMoved:(NSEvent*)theEvent {
166   [self highlightRowUnder:theEvent];
169 - (void)mouseExited:(NSEvent*)theEvent {
170   [self highlightRowUnder:theEvent];
173 // The tracking area events aren't forwarded during a drag, so handle
174 // highlighting manually for middle-click and middle-drag.
175 - (void)otherMouseDown:(NSEvent*)theEvent {
176   if ([theEvent buttonNumber] == kMiddleButtonNumber) {
177     [self highlightRowUnder:theEvent];
178   }
179   [super otherMouseDown:theEvent];
182 - (void)otherMouseDragged:(NSEvent*)theEvent {
183   if ([theEvent buttonNumber] == kMiddleButtonNumber) {
184     [self highlightRowUnder:theEvent];
185   }
186   [super otherMouseDragged:theEvent];
189 - (void)otherMouseUp:(NSEvent*)theEvent {
190   // Only intercept middle button.
191   if ([theEvent buttonNumber] != kMiddleButtonNumber) {
192     [super otherMouseUp:theEvent];
193     return;
194   }
196   // -otherMouseDragged: should always have been called at this location, but
197   // make sure the user is getting the right feedback.
198   [self highlightRowUnder:theEvent];
200   const NSInteger highlightedRow = [[self controller] highlightedRow];
201   if (highlightedRow != -1) {
202     DCHECK(observer_);
203     observer_->OnMatrixRowMiddleClicked(self, highlightedRow);
204   }
207 // Track the mouse until released, keeping the cell under the mouse selected.
208 // If the mouse wanders off-view, revert to the originally-selected cell. If
209 // the mouse is released over a cell, call the delegate to open the row's URL.
210 - (void)mouseDown:(NSEvent*)theEvent {
211   NSCell* selectedCell = [self selectedCell];
213   // Clear any existing highlight.
214   [[self controller] setHighlightedRow:-1];
216   do {
217     if (![self selectCellForEvent:theEvent]) {
218       [self selectCell:selectedCell];
219     }
221     const NSUInteger mask = NSLeftMouseUpMask | NSLeftMouseDraggedMask;
222     theEvent = [[self window] nextEventMatchingMask:mask];
223   } while ([theEvent type] == NSLeftMouseDragged);
225   // Do not message the delegate if released outside view.
226   if (![self selectCellForEvent:theEvent]) {
227     [self selectCell:selectedCell];
228   } else {
229     const NSInteger selectedRow = [self selectedRow];
231     // No row could be selected if the model failed to update.
232     if (selectedRow == -1) {
233       NOTREACHED();
234       return;
235     }
237     DCHECK(observer_);
238     observer_->OnMatrixRowClicked(self, selectedRow);
239   }
242 - (void)selectRowIndex:(NSInteger)rowIndex {
243   NSIndexSet* indexSet = [NSIndexSet indexSetWithIndex:rowIndex];
244   [self selectRowIndexes:indexSet byExtendingSelection:NO];
247 - (NSInteger)highlightedRow {
248   return [[self controller] highlightedRow];
251 - (void)setController:(OmniboxPopupTableController*)controller {
252   matrixController_.reset([controller retain]);
253   [self setDelegate:controller];
254   [self setDataSource:controller];
255   [self reloadData];
258 - (void)resetTrackingArea {
259   if (trackingArea_.get())
260     [self removeTrackingArea:trackingArea_.get()];
262   trackingArea_.reset([[CrTrackingArea alloc]
263       initWithRect:[self frame]
264            options:NSTrackingMouseEnteredAndExited |
265                    NSTrackingMouseMoved |
266                    NSTrackingActiveInActiveApp |
267                    NSTrackingInVisibleRect
268              owner:self
269           userInfo:nil]);
270   [self addTrackingArea:trackingArea_.get()];
273 - (void)highlightRowUnder:(NSEvent*)theEvent {
274   NSPoint point = [self convertPoint:[theEvent locationInWindow] fromView:nil];
275   NSInteger oldRow = [[self controller] highlightedRow];
276   NSInteger newRow = [self rowAtPoint:point];
277   if (oldRow != newRow) {
278     [[self controller] setHighlightedRow:newRow];
279     [self setNeedsDisplayInRect:[self rectOfRow:oldRow]];
280     [self setNeedsDisplayInRect:[self rectOfRow:newRow]];
281   }
284 - (BOOL)selectCellForEvent:(NSEvent*)theEvent {
285   NSPoint point = [self convertPoint:[theEvent locationInWindow] fromView:nil];
287   NSInteger row = [self rowAtPoint:point];
288   [self selectRowIndex:row];
289   if (row != -1) {
290     DCHECK(observer_);
291     observer_->OnMatrixRowSelected(self, row);
292     return YES;
293   }
294   return NO;
297 @end