| Index: ui/app_list/cocoa/apps_search_results_controller.mm
|
| diff --git a/ui/app_list/cocoa/apps_search_results_controller.mm b/ui/app_list/cocoa/apps_search_results_controller.mm
|
| deleted file mode 100644
|
| index 95f293f0d71ce473cf207208a4304076ca97b60c..0000000000000000000000000000000000000000
|
| --- a/ui/app_list/cocoa/apps_search_results_controller.mm
|
| +++ /dev/null
|
| @@ -1,464 +0,0 @@
|
| -// Copyright 2013 The Chromium Authors. All rights reserved.
|
| -// Use of this source code is governed by a BSD-style license that can be
|
| -// found in the LICENSE file.
|
| -
|
| -#import "ui/app_list/cocoa/apps_search_results_controller.h"
|
| -
|
| -#include "base/mac/foundation_util.h"
|
| -#include "base/mac/mac_util.h"
|
| -#include "base/message_loop/message_loop.h"
|
| -#include "base/strings/sys_string_conversions.h"
|
| -#include "skia/ext/skia_utils_mac.h"
|
| -#include "ui/app_list/app_list_constants.h"
|
| -#include "ui/app_list/app_list_model.h"
|
| -#import "ui/app_list/cocoa/apps_search_results_model_bridge.h"
|
| -#include "ui/app_list/search_result.h"
|
| -#import "ui/base/cocoa/flipped_view.h"
|
| -#include "ui/gfx/image/image_skia_util_mac.h"
|
| -
|
| -namespace {
|
| -
|
| -const CGFloat kPreferredRowHeight = 52;
|
| -const CGFloat kIconDimension = 32;
|
| -const CGFloat kIconPadding = 14;
|
| -const CGFloat kIconViewWidth = kIconDimension + 2 * kIconPadding;
|
| -const CGFloat kTextTrailPadding = kIconPadding;
|
| -
|
| -// Map background styles to represent selection and hover in the results list.
|
| -const NSBackgroundStyle kBackgroundNormal = NSBackgroundStyleLight;
|
| -const NSBackgroundStyle kBackgroundSelected = NSBackgroundStyleDark;
|
| -const NSBackgroundStyle kBackgroundHovered = NSBackgroundStyleRaised;
|
| -
|
| -} // namespace
|
| -
|
| -@interface AppsSearchResultsController ()
|
| -
|
| -- (void)loadAndSetViewWithResultsFrameSize:(NSSize)size;
|
| -- (void)mouseDown:(NSEvent*)theEvent;
|
| -- (void)tableViewClicked:(id)sender;
|
| -- (app_list::AppListModel::SearchResults*)searchResults;
|
| -- (void)activateSelection;
|
| -- (BOOL)moveSelectionByDelta:(NSInteger)delta;
|
| -- (NSMenu*)contextMenuForRow:(NSInteger)rowIndex;
|
| -
|
| -@end
|
| -
|
| -@interface AppsSearchResultsCell : NSTextFieldCell
|
| -@end
|
| -
|
| -// Immutable class representing a search result in the NSTableView.
|
| -@interface AppsSearchResultRep : NSObject<NSCopying> {
|
| - @private
|
| - base::scoped_nsobject<NSAttributedString> attributedStringValue_;
|
| - base::scoped_nsobject<NSImage> resultIcon_;
|
| -}
|
| -
|
| -@property(readonly, nonatomic) NSAttributedString* attributedStringValue;
|
| -@property(readonly, nonatomic) NSImage* resultIcon;
|
| -
|
| -- (id)initWithSearchResult:(app_list::SearchResult*)result;
|
| -
|
| -- (NSMutableAttributedString*)createRenderText:(const base::string16&)content
|
| - tags:(const app_list::SearchResult::Tags&)tags;
|
| -
|
| -- (NSAttributedString*)createResultsAttributedStringWithModel
|
| - :(app_list::SearchResult*)result;
|
| -
|
| -@end
|
| -
|
| -// Simple extension to NSTableView that passes mouseDown events to the
|
| -// delegate so that drag events can be detected, and forwards requests for
|
| -// context menus.
|
| -@interface AppsSearchResultsTableView : NSTableView
|
| -
|
| -- (AppsSearchResultsController*)controller;
|
| -
|
| -@end
|
| -
|
| -@implementation AppsSearchResultsController
|
| -
|
| -@synthesize delegate = delegate_;
|
| -
|
| -- (id)initWithAppsSearchResultsFrameSize:(NSSize)size {
|
| - if ((self = [super init])) {
|
| - hoveredRowIndex_ = -1;
|
| - [self loadAndSetViewWithResultsFrameSize:size];
|
| - }
|
| - return self;
|
| -}
|
| -
|
| -- (app_list::AppListModel::SearchResults*)results {
|
| - DCHECK([delegate_ appListModel]);
|
| - return [delegate_ appListModel]->results();
|
| -}
|
| -
|
| -- (NSTableView*)tableView {
|
| - return tableView_;
|
| -}
|
| -
|
| -- (void)setDelegate:(id<AppsSearchResultsDelegate>)newDelegate {
|
| - bridge_.reset();
|
| - delegate_ = newDelegate;
|
| - app_list::AppListModel* appListModel = [delegate_ appListModel];
|
| - if (!appListModel || !appListModel->results()) {
|
| - [tableView_ reloadData];
|
| - return;
|
| - }
|
| -
|
| - bridge_.reset(new app_list::AppsSearchResultsModelBridge(self));
|
| - [tableView_ reloadData];
|
| -}
|
| -
|
| -- (BOOL)handleCommandBySelector:(SEL)command {
|
| - if (command == @selector(insertNewline:) ||
|
| - command == @selector(insertLineBreak:)) {
|
| - [self activateSelection];
|
| - return YES;
|
| - }
|
| -
|
| - if (command == @selector(moveUp:))
|
| - return [self moveSelectionByDelta:-1];
|
| -
|
| - if (command == @selector(moveDown:))
|
| - return [self moveSelectionByDelta:1];
|
| -
|
| - return NO;
|
| -}
|
| -
|
| -- (void)loadAndSetViewWithResultsFrameSize:(NSSize)size {
|
| - tableView_.reset(
|
| - [[AppsSearchResultsTableView alloc] initWithFrame:NSZeroRect]);
|
| - // Refuse first responder so that focus stays with the search text field.
|
| - [tableView_ setRefusesFirstResponder:YES];
|
| - [tableView_ setRowHeight:kPreferredRowHeight];
|
| - [tableView_ setGridStyleMask:NSTableViewSolidHorizontalGridLineMask];
|
| - [tableView_ setGridColor:
|
| - gfx::SkColorToSRGBNSColor(app_list::kResultBorderColor)];
|
| - [tableView_ setBackgroundColor:[NSColor clearColor]];
|
| - [tableView_ setAction:@selector(tableViewClicked:)];
|
| - [tableView_ setDelegate:self];
|
| - [tableView_ setDataSource:self];
|
| - [tableView_ setTarget:self];
|
| -
|
| - // Tracking to highlight an individual row on mouseover.
|
| - trackingArea_.reset(
|
| - [[CrTrackingArea alloc] initWithRect:NSZeroRect
|
| - options:NSTrackingInVisibleRect |
|
| - NSTrackingMouseEnteredAndExited |
|
| - NSTrackingMouseMoved |
|
| - NSTrackingActiveInKeyWindow
|
| - owner:self
|
| - userInfo:nil]);
|
| - [tableView_ addTrackingArea:trackingArea_.get()];
|
| -
|
| - base::scoped_nsobject<NSTableColumn> resultsColumn(
|
| - [[NSTableColumn alloc] initWithIdentifier:@""]);
|
| - base::scoped_nsobject<NSCell> resultsDataCell(
|
| - [[AppsSearchResultsCell alloc] initTextCell:@""]);
|
| - [resultsColumn setDataCell:resultsDataCell];
|
| - [resultsColumn setWidth:size.width];
|
| - [tableView_ addTableColumn:resultsColumn];
|
| -
|
| - // An NSTableView is normally put in a NSScrollView, but scrolling is not
|
| - // used for the app list. Instead, place it in a container with the desired
|
| - // size; flipped so the table is anchored to the top-left.
|
| - base::scoped_nsobject<FlippedView> containerView([[FlippedView alloc]
|
| - initWithFrame:NSMakeRect(0, 0, size.width, size.height)]);
|
| -
|
| - // The container is then anchored in an un-flipped view, initially hidden,
|
| - // so that |containerView| slides in from the top when showing results.
|
| - base::scoped_nsobject<NSView> clipView(
|
| - [[NSView alloc] initWithFrame:NSMakeRect(0, 0, size.width, 0)]);
|
| -
|
| - [containerView addSubview:tableView_];
|
| - [clipView addSubview:containerView];
|
| - [self setView:clipView];
|
| -}
|
| -
|
| -- (void)mouseDown:(NSEvent*)theEvent {
|
| - lastMouseDownInView_ = [tableView_ convertPoint:[theEvent locationInWindow]
|
| - fromView:nil];
|
| -}
|
| -
|
| -- (void)tableViewClicked:(id)sender {
|
| - const CGFloat kDragThreshold = 5;
|
| - // If the user clicked and then dragged elsewhere, ignore the click.
|
| - NSEvent* event = [[tableView_ window] currentEvent];
|
| - NSPoint pointInView = [tableView_ convertPoint:[event locationInWindow]
|
| - fromView:nil];
|
| - CGFloat deltaX = pointInView.x - lastMouseDownInView_.x;
|
| - CGFloat deltaY = pointInView.y - lastMouseDownInView_.y;
|
| - if (deltaX * deltaX + deltaY * deltaY <= kDragThreshold * kDragThreshold)
|
| - [self activateSelection];
|
| -
|
| - // Mouse tracking is suppressed by the NSTableView during a drag, so ensure
|
| - // any hover state is cleaned up.
|
| - [self mouseMoved:event];
|
| -}
|
| -
|
| -- (app_list::AppListModel::SearchResults*)searchResults {
|
| - app_list::AppListModel* appListModel = [delegate_ appListModel];
|
| - DCHECK(bridge_);
|
| - DCHECK(appListModel);
|
| - DCHECK(appListModel->results());
|
| - return appListModel->results();
|
| -}
|
| -
|
| -- (void)activateSelection {
|
| - NSInteger selectedRow = [tableView_ selectedRow];
|
| - if (!bridge_ || selectedRow < 0)
|
| - return;
|
| -
|
| - [delegate_ openResult:[self searchResults]->GetItemAt(selectedRow)];
|
| -}
|
| -
|
| -- (BOOL)moveSelectionByDelta:(NSInteger)delta {
|
| - NSInteger rowCount = [tableView_ numberOfRows];
|
| - if (rowCount <= 0)
|
| - return NO;
|
| -
|
| - NSInteger selectedRow = [tableView_ selectedRow];
|
| - NSInteger targetRow;
|
| - if (selectedRow == -1) {
|
| - // No selection. Select first or last, based on direction.
|
| - targetRow = delta > 0 ? 0 : rowCount - 1;
|
| - } else {
|
| - targetRow = (selectedRow + delta) % rowCount;
|
| - if (targetRow < 0)
|
| - targetRow += rowCount;
|
| - }
|
| -
|
| - [tableView_ selectRowIndexes:[NSIndexSet indexSetWithIndex:targetRow]
|
| - byExtendingSelection:NO];
|
| - return YES;
|
| -}
|
| -
|
| -- (NSMenu*)contextMenuForRow:(NSInteger)rowIndex {
|
| - DCHECK(bridge_);
|
| - if (rowIndex < 0)
|
| - return nil;
|
| -
|
| - [tableView_ selectRowIndexes:[NSIndexSet indexSetWithIndex:rowIndex]
|
| - byExtendingSelection:NO];
|
| - return bridge_->MenuForItem(rowIndex);
|
| -}
|
| -
|
| -- (NSInteger)numberOfRowsInTableView:(NSTableView*)aTableView {
|
| - return bridge_ ? [self searchResults]->item_count() : 0;
|
| -}
|
| -
|
| -- (id)tableView:(NSTableView*)aTableView
|
| - objectValueForTableColumn:(NSTableColumn*)aTableColumn
|
| - row:(NSInteger)rowIndex {
|
| - // When the results were previously cleared, nothing will be selected. For
|
| - // that case, select the first row when it appears.
|
| - if (rowIndex == 0 && [tableView_ selectedRow] == -1) {
|
| - [tableView_ selectRowIndexes:[NSIndexSet indexSetWithIndex:0]
|
| - byExtendingSelection:NO];
|
| - }
|
| -
|
| - base::scoped_nsobject<AppsSearchResultRep> resultRep(
|
| - [[AppsSearchResultRep alloc]
|
| - initWithSearchResult:[self searchResults]->GetItemAt(rowIndex)]);
|
| - return resultRep.autorelease();
|
| -}
|
| -
|
| -- (void)tableView:(NSTableView*)tableView
|
| - willDisplayCell:(id)cell
|
| - forTableColumn:(NSTableColumn*)tableColumn
|
| - row:(NSInteger)rowIndex {
|
| - if (rowIndex == [tableView selectedRow])
|
| - [cell setBackgroundStyle:kBackgroundSelected];
|
| - else if (rowIndex == hoveredRowIndex_)
|
| - [cell setBackgroundStyle:kBackgroundHovered];
|
| - else
|
| - [cell setBackgroundStyle:kBackgroundNormal];
|
| -}
|
| -
|
| -- (void)mouseExited:(NSEvent*)theEvent {
|
| - if (hoveredRowIndex_ == -1)
|
| - return;
|
| -
|
| - [tableView_ setNeedsDisplayInRect:[tableView_ rectOfRow:hoveredRowIndex_]];
|
| - hoveredRowIndex_ = -1;
|
| -}
|
| -
|
| -- (void)mouseMoved:(NSEvent*)theEvent {
|
| - NSPoint pointInView = [tableView_ convertPoint:[theEvent locationInWindow]
|
| - fromView:nil];
|
| - NSInteger newIndex = [tableView_ rowAtPoint:pointInView];
|
| - if (newIndex == hoveredRowIndex_)
|
| - return;
|
| -
|
| - if (newIndex != -1)
|
| - [tableView_ setNeedsDisplayInRect:[tableView_ rectOfRow:newIndex]];
|
| - if (hoveredRowIndex_ != -1)
|
| - [tableView_ setNeedsDisplayInRect:[tableView_ rectOfRow:hoveredRowIndex_]];
|
| - hoveredRowIndex_ = newIndex;
|
| -}
|
| -
|
| -@end
|
| -
|
| -@implementation AppsSearchResultRep
|
| -
|
| -- (NSAttributedString*)attributedStringValue {
|
| - return attributedStringValue_;
|
| -}
|
| -
|
| -- (NSImage*)resultIcon {
|
| - return resultIcon_;
|
| -}
|
| -
|
| -- (id)initWithSearchResult:(app_list::SearchResult*)result {
|
| - if ((self = [super init])) {
|
| - attributedStringValue_.reset(
|
| - [[self createResultsAttributedStringWithModel:result] retain]);
|
| - if (!result->icon().isNull()) {
|
| - resultIcon_.reset([gfx::NSImageFromImageSkiaWithColorSpace(
|
| - result->icon(), base::mac::GetSRGBColorSpace()) retain]);
|
| - }
|
| - }
|
| - return self;
|
| -}
|
| -
|
| -- (NSMutableAttributedString*)createRenderText:(const base::string16&)content
|
| - tags:(const app_list::SearchResult::Tags&)tags {
|
| - NSFont* boldFont = nil;
|
| - base::scoped_nsobject<NSMutableParagraphStyle> paragraphStyle(
|
| - [[NSMutableParagraphStyle alloc] init]);
|
| - [paragraphStyle setLineBreakMode:NSLineBreakByTruncatingTail];
|
| - NSDictionary* defaultAttributes = @{
|
| - NSForegroundColorAttributeName:
|
| - gfx::SkColorToSRGBNSColor(app_list::kResultDefaultTextColor),
|
| - NSParagraphStyleAttributeName: paragraphStyle
|
| - };
|
| -
|
| - base::scoped_nsobject<NSMutableAttributedString> text(
|
| - [[NSMutableAttributedString alloc]
|
| - initWithString:base::SysUTF16ToNSString(content)
|
| - attributes:defaultAttributes]);
|
| -
|
| - for (app_list::SearchResult::Tags::const_iterator it = tags.begin();
|
| - it != tags.end(); ++it) {
|
| - if (it->styles == app_list::SearchResult::Tag::NONE)
|
| - continue;
|
| -
|
| - if (it->styles & app_list::SearchResult::Tag::MATCH) {
|
| - if (!boldFont) {
|
| - NSFontManager* fontManager = [NSFontManager sharedFontManager];
|
| - boldFont = [fontManager convertFont:[NSFont controlContentFontOfSize:0]
|
| - toHaveTrait:NSBoldFontMask];
|
| - }
|
| - [text addAttribute:NSFontAttributeName
|
| - value:boldFont
|
| - range:it->range.ToNSRange()];
|
| - }
|
| -
|
| - if (it->styles & app_list::SearchResult::Tag::DIM) {
|
| - NSColor* dimmedColor =
|
| - gfx::SkColorToSRGBNSColor(app_list::kResultDimmedTextColor);
|
| - [text addAttribute:NSForegroundColorAttributeName
|
| - value:dimmedColor
|
| - range:it->range.ToNSRange()];
|
| - } else if (it->styles & app_list::SearchResult::Tag::URL) {
|
| - NSColor* urlColor =
|
| - gfx::SkColorToSRGBNSColor(app_list::kResultURLTextColor);
|
| - [text addAttribute:NSForegroundColorAttributeName
|
| - value:urlColor
|
| - range:it->range.ToNSRange()];
|
| - }
|
| - }
|
| -
|
| - return text.autorelease();
|
| -}
|
| -
|
| -- (NSAttributedString*)createResultsAttributedStringWithModel
|
| - :(app_list::SearchResult*)result {
|
| - NSMutableAttributedString* titleText =
|
| - [self createRenderText:result->title()
|
| - tags:result->title_tags()];
|
| - if (!result->details().empty()) {
|
| - NSMutableAttributedString* detailText =
|
| - [self createRenderText:result->details()
|
| - tags:result->details_tags()];
|
| - base::scoped_nsobject<NSAttributedString> lineBreak(
|
| - [[NSAttributedString alloc] initWithString:@"\n"]);
|
| - [titleText appendAttributedString:lineBreak];
|
| - [titleText appendAttributedString:detailText];
|
| - }
|
| - return titleText;
|
| -}
|
| -
|
| -- (id)copyWithZone:(NSZone*)zone {
|
| - return [self retain];
|
| -}
|
| -
|
| -@end
|
| -
|
| -@implementation AppsSearchResultsTableView
|
| -
|
| -- (AppsSearchResultsController*)controller {
|
| - return base::mac::ObjCCastStrict<AppsSearchResultsController>(
|
| - [self delegate]);
|
| -}
|
| -
|
| -- (void)mouseDown:(NSEvent*)theEvent {
|
| - [[self controller] mouseDown:theEvent];
|
| - [super mouseDown:theEvent];
|
| -}
|
| -
|
| -- (NSMenu*)menuForEvent:(NSEvent*)theEvent {
|
| - NSPoint pointInView = [self convertPoint:[theEvent locationInWindow]
|
| - fromView:nil];
|
| - return [[self controller] contextMenuForRow:[self rowAtPoint:pointInView]];
|
| -}
|
| -
|
| -@end
|
| -
|
| -@implementation AppsSearchResultsCell
|
| -
|
| -- (void)drawWithFrame:(NSRect)cellFrame
|
| - inView:(NSView*)controlView {
|
| - if ([self backgroundStyle] != kBackgroundNormal) {
|
| - if ([self backgroundStyle] == kBackgroundSelected)
|
| - [gfx::SkColorToSRGBNSColor(app_list::kSelectedColor) set];
|
| - else
|
| - [gfx::SkColorToSRGBNSColor(app_list::kHighlightedColor) set];
|
| -
|
| - // Extend up by one pixel to draw over cell border.
|
| - NSRect backgroundRect = cellFrame;
|
| - backgroundRect.origin.y -= 1;
|
| - backgroundRect.size.height += 1;
|
| - NSRectFill(backgroundRect);
|
| - }
|
| -
|
| - NSAttributedString* titleText = [self attributedStringValue];
|
| - NSRect titleRect = cellFrame;
|
| - titleRect.size.width -= kTextTrailPadding + kIconViewWidth;
|
| - titleRect.origin.x += kIconViewWidth;
|
| - titleRect.origin.y +=
|
| - floor(NSHeight(cellFrame) / 2 - [titleText size].height / 2);
|
| - // Ensure no drawing occurs outside of the cell.
|
| - titleRect = NSIntersectionRect(titleRect, cellFrame);
|
| -
|
| - [titleText drawInRect:titleRect];
|
| -
|
| - NSImage* resultIcon = [[self objectValue] resultIcon];
|
| - if (!resultIcon)
|
| - return;
|
| -
|
| - NSSize iconSize = [resultIcon size];
|
| - NSRect iconRect = NSMakeRect(
|
| - floor(NSMinX(cellFrame) + kIconViewWidth / 2 - iconSize.width / 2),
|
| - floor(NSMinY(cellFrame) + kPreferredRowHeight / 2 - iconSize.height / 2),
|
| - std::min(iconSize.width, kIconDimension),
|
| - std::min(iconSize.height, kIconDimension));
|
| - [resultIcon drawInRect:iconRect
|
| - fromRect:NSZeroRect
|
| - operation:NSCompositeSourceOver
|
| - fraction:1.0
|
| - respectFlipped:YES
|
| - hints:nil];
|
| -}
|
| -
|
| -@end
|
|
|