Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(537)

Side by Side Diff: chrome/browser/ui/cocoa/chooser_content_view_cocoa.mm

Issue 2595083002: Change ChooserContentView[Cocoa] class name to be DeviceChooserContentView[Cocoa] (Closed)
Patch Set: merge master Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 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 "chrome/browser/ui/cocoa/chooser_content_view_cocoa.h"
6
7 #include <algorithm>
8
9 #include "base/macros.h"
10 #include "base/strings/sys_string_conversions.h"
11 #include "chrome/browser/chooser_controller/chooser_controller.h"
12 #import "chrome/browser/ui/cocoa/constrained_window/constrained_window_button.h"
13 #include "chrome/browser/ui/cocoa/spinner_view.h"
14 #include "chrome/grit/generated_resources.h"
15 #include "skia/ext/skia_utils_mac.h"
16 #import "third_party/google_toolbox_for_mac/src/AppKit/GTMUILocalizerAndLayoutTw eaker.h"
17 #import "ui/base/cocoa/controls/hyperlink_button_cell.h"
18 #include "ui/base/l10n/l10n_util_mac.h"
19 #include "ui/base/resource/resource_bundle.h"
20 #include "ui/gfx/color_palette.h"
21 #include "ui/gfx/image/image_skia_util_mac.h"
22 #include "ui/gfx/paint_vector_icon.h"
23 #include "ui/gfx/vector_icons_public.h"
24 #include "ui/resources/grit/ui_resources.h"
25
26 namespace {
27
28 // Chooser width.
29 const CGFloat kChooserWidth = 390.0f;
30
31 // Chooser height.
32 const CGFloat kChooserHeight = 330.0f;
33
34 // Row view image size.
35 const CGFloat kRowViewImageSize = 20.0f;
36
37 // Table row view height.
38 const CGFloat kTableRowViewOneLineHeight = 23.0f;
39 const CGFloat kTableRowViewTwoLinesHeight = 39.0f;
40
41 // Spinner size.
42 const CGFloat kSpinnerSize = 24.0f;
43
44 // Distance between the chooser border and the view that is closest to the
45 // border.
46 const CGFloat kMarginX = 20.0f;
47 const CGFloat kMarginY = 20.0f;
48
49 // Distance between two views inside the chooser.
50 const CGFloat kHorizontalPadding = 10.0f;
51 const CGFloat kVerticalPadding = 10.0f;
52
53 // Separator alpha value.
54 const CGFloat kSeparatorAlphaValue = 0.6f;
55
56 // Separator height.
57 const CGFloat kSeparatorHeight = 1.0f;
58
59 // Distance between two views inside the table row view.
60 const CGFloat kTableRowViewHorizontalPadding = 5.0f;
61 const CGFloat kTableRowViewVerticalPadding = 1.0f;
62
63 // Distance between the adapter off help link and the scroll view boundaries.
64 const CGFloat kAdapterOffHelpLinkPadding = 5.0f;
65
66 // The lookup table for signal strength level image.
67 const int kSignalStrengthLevelImageIds[5] = {IDR_SIGNAL_0_BAR, IDR_SIGNAL_1_BAR,
68 IDR_SIGNAL_2_BAR, IDR_SIGNAL_3_BAR,
69 IDR_SIGNAL_4_BAR};
70 const int kSignalStrengthLevelImageSelectedIds[5] = {
71 IDR_SIGNAL_0_BAR_SELECTED, IDR_SIGNAL_1_BAR_SELECTED,
72 IDR_SIGNAL_2_BAR_SELECTED, IDR_SIGNAL_3_BAR_SELECTED,
73 IDR_SIGNAL_4_BAR_SELECTED};
74
75 // Creates a label with |text|.
76 base::scoped_nsobject<NSTextField> CreateLabel(NSString* text) {
77 base::scoped_nsobject<NSTextField> label(
78 [[NSTextField alloc] initWithFrame:NSZeroRect]);
79 [label setDrawsBackground:NO];
80 [label setBezeled:NO];
81 [label setEditable:NO];
82 [label setSelectable:NO];
83 [label setStringValue:text];
84 [label setFont:[NSFont systemFontOfSize:[NSFont systemFontSize]]];
85 [label setTextColor:[NSColor blackColor]];
86 [label sizeToFit];
87 return label;
88 }
89
90 } // namespace
91
92 // A table row view that contains one line of text, and optionally contains an
93 // image in front of the text.
94 @interface ChooserContentTableRowView : NSView {
95 @private
96 base::scoped_nsobject<NSImageView> image_;
97 base::scoped_nsobject<NSTextField> text_;
98 base::scoped_nsobject<NSTextField> pairedStatus_;
99 }
100
101 // Designated initializer.
102 // This initializer is used when the chooser needs to show the no-devices-found
103 // message.
104 - (instancetype)initWithText:(NSString*)text;
105
106 // Designated initializer.
107 - (instancetype)initWithText:(NSString*)text
108 signalStrengthLevel:(NSInteger)level
109 isConnected:(bool)isConnected
110 isPaired:(bool)isPaired
111 rowHeight:(CGFloat)rowHeight
112 textNeedIndentation:(bool)textNeedIndentation;
113
114 // Gets the image in front of the text.
115 - (NSImageView*)image;
116
117 // Gets the text.
118 - (NSTextField*)text;
119
120 // Gets the paired status.
121 - (NSTextField*)pairedStatus;
122
123 @end
124
125 @implementation ChooserContentTableRowView
126
127 - (instancetype)initWithText:(NSString*)text {
128 if ((self = [super initWithFrame:NSZeroRect])) {
129 text_ = CreateLabel(text);
130 CGFloat textHeight = NSHeight([text_ frame]);
131 CGFloat textOriginX = kTableRowViewHorizontalPadding;
132 CGFloat textOriginY = (kTableRowViewOneLineHeight - textHeight) / 2;
133 [text_ setFrameOrigin:NSMakePoint(textOriginX, textOriginY)];
134 [self addSubview:text_];
135 }
136
137 return self;
138 }
139
140 - (instancetype)initWithText:(NSString*)text
141 signalStrengthLevel:(NSInteger)level
142 isConnected:(bool)isConnected
143 isPaired:(bool)isPaired
144 rowHeight:(CGFloat)rowHeight
145 textNeedIndentation:(bool)textNeedIndentation {
146 if ((self = [super initWithFrame:NSZeroRect])) {
147 // Create the views.
148 // Image.
149 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
150 NSImage* image = nullptr;
151 if (isConnected) {
152 image = gfx::NSImageFromImageSkia(gfx::CreateVectorIcon(
153 gfx::VectorIconId::BLUETOOTH_CONNECTED, gfx::kChromeIconGrey));
154 } else if (level != -1) {
155 DCHECK_GE(level, 0);
156 DCHECK_LT(level, base::checked_cast<NSInteger>(
157 arraysize(kSignalStrengthLevelImageIds)));
158 image = rb.GetNativeImageNamed(kSignalStrengthLevelImageIds[level])
159 .ToNSImage();
160 }
161
162 CGFloat imageOriginX = kTableRowViewHorizontalPadding;
163 CGFloat imageOriginY = (rowHeight - kRowViewImageSize) / 2;
164 if (image) {
165 image_.reset([[NSImageView alloc]
166 initWithFrame:NSMakeRect(imageOriginX, imageOriginY,
167 kRowViewImageSize, kRowViewImageSize)]);
168 [image_ setImage:image];
169 [self addSubview:image_];
170 }
171
172 // Text.
173 text_ = CreateLabel(text);
174 CGFloat textHeight = NSHeight([text_ frame]);
175
176 // Paired status.
177 CGFloat pairedStatusHeight = 0.0f;
178 if (isPaired) {
179 pairedStatus_ = CreateLabel(
180 l10n_util::GetNSString(IDS_DEVICE_CHOOSER_PAIRED_STATUS_TEXT));
181 [pairedStatus_
182 setTextColor:skia::SkColorToCalibratedNSColor(gfx::kGoogleGreen700)];
183 pairedStatusHeight = NSHeight([pairedStatus_ frame]);
184 }
185
186 // Lay out the views.
187 // Text.
188 CGFloat textOriginX = kTableRowViewHorizontalPadding;
189 if (textNeedIndentation)
190 textOriginX += imageOriginX + kRowViewImageSize;
191 CGFloat textOriginY;
192 if (isPaired) {
193 textOriginY = pairedStatusHeight +
194 (rowHeight - textHeight - pairedStatusHeight -
195 kTableRowViewVerticalPadding) /
196 2 +
197 kTableRowViewVerticalPadding;
198 } else {
199 textOriginY = (rowHeight - textHeight) / 2;
200 }
201
202 [text_ setFrameOrigin:NSMakePoint(textOriginX, textOriginY)];
203 [self addSubview:text_];
204
205 // Paired status.
206 if (isPaired) {
207 CGFloat pairedStatusOriginX = textOriginX;
208 CGFloat pairedStatusOriginY =
209 (rowHeight - textHeight - pairedStatusHeight -
210 kTableRowViewVerticalPadding) /
211 2;
212 [pairedStatus_
213 setFrameOrigin:NSMakePoint(pairedStatusOriginX, pairedStatusOriginY)];
214 [self addSubview:pairedStatus_];
215 }
216 }
217
218 return self;
219 }
220
221 - (NSImageView*)image {
222 return image_.get();
223 }
224
225 - (NSTextField*)text {
226 return text_.get();
227 }
228
229 - (NSTextField*)pairedStatus {
230 return pairedStatus_.get();
231 }
232
233 @end
234
235 class ChooserContentViewController : public ChooserController::View {
236 public:
237 ChooserContentViewController(ChooserController* chooser_controller,
238 NSButton* adapter_off_help_button,
239 NSTextField* adapter_off_message,
240 NSTableView* table_view,
241 SpinnerView* spinner,
242 NSTextField* scanning_message,
243 NSTextField* word_connector,
244 NSButton* rescan_button);
245 ~ChooserContentViewController() override;
246
247 // ChooserController::View:
248 void OnOptionsInitialized() override;
249 void OnOptionAdded(size_t index) override;
250 void OnOptionRemoved(size_t index) override;
251 void OnOptionUpdated(size_t index) override;
252 void OnAdapterEnabledChanged(bool enabled) override;
253 void OnRefreshStateChanged(bool refreshing) override;
254
255 void UpdateTableView();
256
257 private:
258 ChooserController* chooser_controller_;
259 NSButton* adapter_off_help_button_;
260 NSTextField* adapter_off_message_;
261 NSTableView* table_view_;
262 SpinnerView* spinner_;
263 NSTextField* scanning_message_;
264 NSTextField* word_connector_;
265 NSButton* rescan_button_;
266
267 DISALLOW_COPY_AND_ASSIGN(ChooserContentViewController);
268 };
269
270 ChooserContentViewController::ChooserContentViewController(
271 ChooserController* chooser_controller,
272 NSButton* adapter_off_help_button,
273 NSTextField* adapter_off_message,
274 NSTableView* table_view,
275 SpinnerView* spinner,
276 NSTextField* scanning_message,
277 NSTextField* word_connector,
278 NSButton* rescan_button)
279 : chooser_controller_(chooser_controller),
280 adapter_off_help_button_(adapter_off_help_button),
281 adapter_off_message_(adapter_off_message),
282 table_view_(table_view),
283 spinner_(spinner),
284 scanning_message_(scanning_message),
285 word_connector_(word_connector),
286 rescan_button_(rescan_button) {
287 DCHECK(chooser_controller_);
288 DCHECK(adapter_off_help_button_);
289 DCHECK(adapter_off_message_);
290 DCHECK(table_view_);
291 DCHECK(spinner_);
292 DCHECK(scanning_message_);
293 DCHECK(word_connector_);
294 DCHECK(rescan_button_);
295 chooser_controller_->set_view(this);
296 }
297
298 ChooserContentViewController::~ChooserContentViewController() {
299 chooser_controller_->set_view(nullptr);
300 }
301
302 void ChooserContentViewController::OnOptionsInitialized() {
303 UpdateTableView();
304 }
305
306 void ChooserContentViewController::OnOptionAdded(size_t index) {
307 UpdateTableView();
308 [table_view_ setHidden:NO];
309 [spinner_ setHidden:YES];
310 }
311
312 void ChooserContentViewController::OnOptionRemoved(size_t index) {
313 // |table_view_| will automatically select the removed item's next item.
314 // So here it tracks if the removed item is the item that was currently
315 // selected, if so, deselect it. Also if the removed item is before the
316 // currently selected item, the currently selected item's index needs to
317 // be adjusted by one.
318 NSIndexSet* selected_rows = [table_view_ selectedRowIndexes];
319 NSMutableIndexSet* updated_selected_rows = [NSMutableIndexSet indexSet];
320 NSUInteger row = [selected_rows firstIndex];
321 while (row != NSNotFound) {
322 if (row < index)
323 [updated_selected_rows addIndex:row];
324 else if (row > index)
325 [updated_selected_rows addIndex:row - 1];
326 row = [selected_rows indexGreaterThanIndex:row];
327 }
328
329 [table_view_ selectRowIndexes:updated_selected_rows byExtendingSelection:NO];
330
331 UpdateTableView();
332 }
333
334 void ChooserContentViewController::OnOptionUpdated(size_t index) {
335 UpdateTableView();
336 }
337
338 void ChooserContentViewController::OnAdapterEnabledChanged(bool enabled) {
339 // No row is selected since the adapter status has changed.
340 // This will also disable the OK button if it was enabled because
341 // of a previously selected row.
342 [table_view_ deselectAll:nil];
343 UpdateTableView();
344 [table_view_ setHidden:enabled ? NO : YES];
345 [adapter_off_help_button_ setHidden:enabled ? YES : NO];
346 [adapter_off_message_ setHidden:enabled ? YES : NO];
347
348 [spinner_ setHidden:YES];
349
350 [scanning_message_ setHidden:YES];
351 // When adapter is enabled, show |word_connector_| and |rescan_button_|;
352 // otherwise hide them.
353 [word_connector_ setHidden:enabled ? NO : YES];
354 [rescan_button_ setHidden:enabled ? NO : YES];
355 }
356
357 void ChooserContentViewController::OnRefreshStateChanged(bool refreshing) {
358 if (refreshing) {
359 // No row is selected since the chooser is refreshing.
360 // This will also disable the OK button if it was enabled because
361 // of a previously selected row.
362 [table_view_ deselectAll:nil];
363 UpdateTableView();
364 }
365
366 // When refreshing and no option available yet, hide |table_view_| and show
367 // |spinner_|. Otherwise show |table_view_| and hide |spinner_|.
368 bool table_view_hidden =
369 refreshing && (chooser_controller_->NumOptions() == 0);
370 [table_view_ setHidden:table_view_hidden ? YES : NO];
371 [spinner_ setHidden:table_view_hidden ? NO : YES];
372
373 // When refreshing, show |scanning_message_| and hide |word_connector_| and
374 // |rescan_button_|.
375 // When complete, show |word_connector_| and |rescan_button_| and hide
376 // |scanning_message_|.
377 [scanning_message_ setHidden:refreshing ? NO : YES];
378 [word_connector_ setHidden:refreshing ? YES : NO];
379 [rescan_button_ setHidden:refreshing ? YES : NO];
380 }
381
382 void ChooserContentViewController::UpdateTableView() {
383 [table_view_ setEnabled:chooser_controller_->NumOptions() > 0];
384 // For NSView-based table views, calling reloadData will deselect the
385 // currently selected row, so |selected_rows| stores the currently selected
386 // rows in order to select them again.
387 NSIndexSet* selected_rows = [table_view_ selectedRowIndexes];
388 [table_view_ reloadData];
389 [table_view_ selectRowIndexes:selected_rows byExtendingSelection:NO];
390 }
391
392 @implementation ChooserContentViewCocoa
393
394 // TODO(juncai): restructure this function to be some smaller methods to
395 // create the pieces for the view. By doing so, the methods that calculate
396 // the frame and origins can be moved into those methods, rather than as
397 // helper functions.
398 - (instancetype)initWithChooserTitle:(NSString*)chooserTitle
399 chooserController:
400 (std::unique_ptr<ChooserController>)chooserController {
401 // ------------------------------------
402 // | Chooser title |
403 // | -------------------------------- |
404 // | | option 0 | |
405 // | | option 1 | |
406 // | | option 2 | |
407 // | | | |
408 // | | | |
409 // | | | |
410 // | -------------------------------- |
411 // | [ Connect ] [ Cancel ] |
412 // |----------------------------------|
413 // | Get help |
414 // ------------------------------------
415
416 // Determine the dimensions of the chooser.
417 // Once the height and width are set, the buttons and permission menus can
418 // be laid out correctly.
419 NSRect chooserFrame = NSMakeRect(0, 0, kChooserWidth, kChooserHeight);
420
421 if ((self = [super initWithFrame:chooserFrame])) {
422 chooserController_ = std::move(chooserController);
423
424 // Create the views.
425 // Title.
426 titleView_ = [self createChooserTitle:chooserTitle];
427 CGFloat titleHeight = NSHeight([titleView_ frame]);
428
429 // Adapter turned off help button.
430 adapterOffHelpButton_ = [self
431 createHyperlinkButtonWithText:
432 l10n_util::GetNSString(
433 IDS_BLUETOOTH_DEVICE_CHOOSER_TURN_ON_BLUETOOTH_LINK_TEXT)];
434 CGFloat adapterOffHelpButtonWidth = NSWidth([adapterOffHelpButton_ frame]);
435 CGFloat adapterOffHelpButtonHeight =
436 NSHeight([adapterOffHelpButton_ frame]);
437
438 // Adapter turned off message.
439 adapterOffMessage_ = CreateLabel(l10n_util::GetNSStringF(
440 IDS_BLUETOOTH_DEVICE_CHOOSER_TURN_ADAPTER_OFF, base::string16()));
441
442 // Connect button.
443 connectButton_ = [self createConnectButton];
444 CGFloat connectButtonWidth = NSWidth([connectButton_ frame]);
445 CGFloat connectButtonHeight = NSHeight([connectButton_ frame]);
446
447 // Cancel button.
448 cancelButton_ = [self createCancelButton];
449 CGFloat cancelButtonWidth = NSWidth([cancelButton_ frame]);
450
451 // Separator.
452 separator_ = [self createSeparator];
453
454 // Help button.
455 CGFloat helpButtonWidth = 0.0f;
456 CGFloat helpButtonHeight = 0.0f;
457 if (chooserController_->ShouldShowFootnoteView()) {
458 helpButton_ =
459 [self createHyperlinkButtonWithText:
460 l10n_util::GetNSStringF(
461 IDS_DEVICE_CHOOSER_GET_HELP_LINK_WITH_SCANNING_STATUS,
462 base::string16())];
463 helpButtonWidth = NSWidth([helpButton_ frame]);
464 helpButtonHeight = NSHeight([helpButton_ frame]);
465 }
466
467 // Scanning message.
468 scanningMessage_ = CreateLabel(
469 l10n_util::GetNSString(IDS_BLUETOOTH_DEVICE_CHOOSER_SCANNING));
470
471 // Word connector.
472 wordConnector_ = CreateLabel(l10n_util::GetNSStringF(
473 IDS_DEVICE_CHOOSER_GET_HELP_LINK_WITH_RE_SCAN_LINK, base::string16(),
474 base::string16()));
475 CGFloat wordConnectorWidth = NSWidth([wordConnector_ frame]);
476
477 // Re-scan button.
478 rescanButton_ =
479 [self createHyperlinkButtonWithText:
480 l10n_util::GetNSString(IDS_BLUETOOTH_DEVICE_CHOOSER_RE_SCAN)];
481
482 // ScollView embedding with TableView.
483 CGFloat scrollViewWidth = kChooserWidth - 2 * kMarginX;
484 CGFloat scrollViewHeight =
485 kChooserHeight - 2 * kMarginY -
486 (chooserController_->ShouldShowFootnoteView() ? 4 * kVerticalPadding
487 : 2 * kVerticalPadding) -
488 titleHeight - connectButtonHeight - helpButtonHeight;
489 CGFloat scrollViewOriginX = kMarginX;
490 CGFloat scrollViewOriginY =
491 kMarginY + helpButtonHeight +
492 (chooserController_->ShouldShowFootnoteView() ? 3 * kVerticalPadding
493 : kVerticalPadding) +
494 connectButtonHeight;
495 NSRect scrollFrame = NSMakeRect(scrollViewOriginX, scrollViewOriginY,
496 scrollViewWidth, scrollViewHeight);
497 scrollView_.reset([[NSScrollView alloc] initWithFrame:scrollFrame]);
498 [scrollView_ setBorderType:NSBezelBorder];
499 [scrollView_ setHasVerticalScroller:YES];
500 [scrollView_ setHasHorizontalScroller:YES];
501 [scrollView_ setAutohidesScrollers:YES];
502 [scrollView_ setDrawsBackground:NO];
503
504 // TableView.
505 tableView_.reset([[NSTableView alloc] initWithFrame:NSZeroRect]);
506 tableColumn_.reset([[NSTableColumn alloc] initWithIdentifier:@""]);
507 [tableColumn_ setWidth:(scrollViewWidth - kMarginX)];
508 [tableView_ addTableColumn:tableColumn_];
509 // Make the column title invisible.
510 [tableView_ setHeaderView:nil];
511 [tableView_ setFocusRingType:NSFocusRingTypeNone];
512 [tableView_
513 setAllowsMultipleSelection:chooserController_->AllowMultipleSelection()
514 ? YES
515 : NO];
516
517 // Spinner.
518 // Set the spinner in the center of the scroll view.
519 CGFloat spinnerOriginX =
520 scrollViewOriginX + (scrollViewWidth - kSpinnerSize) / 2;
521 CGFloat spinnerOriginY =
522 scrollViewOriginY + (scrollViewHeight - kSpinnerSize) / 2;
523 spinner_.reset([[SpinnerView alloc]
524 initWithFrame:NSMakeRect(spinnerOriginX, spinnerOriginY, kSpinnerSize,
525 kSpinnerSize)]);
526
527 // Lay out the views.
528 // Title.
529 CGFloat titleOriginX = kMarginX;
530 CGFloat titleOriginY = kChooserHeight - kMarginY - titleHeight;
531 [titleView_ setFrameOrigin:NSMakePoint(titleOriginX, titleOriginY)];
532 [self addSubview:titleView_];
533
534 // Adapter turned off help button.
535 CGFloat adapterOffHelpButtonOriginX = kMarginX + kAdapterOffHelpLinkPadding;
536 CGFloat adapterOffHelpButtonOriginY = titleOriginY - kVerticalPadding -
537 adapterOffHelpButtonHeight -
538 kAdapterOffHelpLinkPadding;
539 [adapterOffHelpButton_
540 setFrameOrigin:NSMakePoint(adapterOffHelpButtonOriginX,
541 adapterOffHelpButtonOriginY)];
542 [adapterOffHelpButton_ setTarget:self];
543 [adapterOffHelpButton_ setAction:@selector(onAdapterOffHelp:)];
544 [adapterOffHelpButton_ setHidden:YES];
545 [self addSubview:adapterOffHelpButton_];
546
547 // Adapter turned off message.
548 CGFloat adapterOffMessageOriginX = adapterOffHelpButtonOriginX +
549 adapterOffHelpButtonWidth -
550 kHorizontalPadding / 2;
551 CGFloat adapterOffMessageOriginY = adapterOffHelpButtonOriginY;
552 [adapterOffMessage_ setFrameOrigin:NSMakePoint(adapterOffMessageOriginX,
553 adapterOffMessageOriginY)];
554 [adapterOffMessage_ setHidden:YES];
555 [self addSubview:adapterOffMessage_];
556
557 // ScollView and Spinner. Only one of them is shown.
558 [scrollView_ setDocumentView:tableView_];
559 [self addSubview:scrollView_];
560 [spinner_ setHidden:YES];
561 [self addSubview:spinner_];
562
563 // Connect button.
564 CGFloat connectButtonOriginX = kChooserWidth - kMarginX -
565 kHorizontalPadding - connectButtonWidth -
566 cancelButtonWidth;
567 CGFloat connectButtonOriginY =
568 kMarginY + helpButtonHeight +
569 (chooserController_->ShouldShowFootnoteView() ? 2 * kVerticalPadding
570 : 0.0f);
571 [connectButton_
572 setFrameOrigin:NSMakePoint(connectButtonOriginX, connectButtonOriginY)];
573 [connectButton_ setEnabled:NO];
574 [self addSubview:connectButton_];
575
576 // Cancel button.
577 CGFloat cancelButtonOriginX = kChooserWidth - kMarginX - cancelButtonWidth;
578 CGFloat cancelButtonOriginY = connectButtonOriginY;
579 [cancelButton_
580 setFrameOrigin:NSMakePoint(cancelButtonOriginX, cancelButtonOriginY)];
581 [self addSubview:cancelButton_];
582
583 if (chooserController_->ShouldShowFootnoteView()) {
584 // Separator.
585 CGFloat separatorOriginX = 0.0f;
586 separatorOriginY_ = kMarginY + helpButtonHeight + kVerticalPadding;
587 [separator_
588 setFrameOrigin:NSMakePoint(separatorOriginX, separatorOriginY_)];
589 [self addSubview:separator_];
590
591 // Help button.
592 CGFloat helpButtonOriginX = kMarginX;
593 CGFloat helpButtonOriginY = (kVerticalPadding + kMarginY) / 2;
594 [helpButton_
595 setFrameOrigin:NSMakePoint(helpButtonOriginX, helpButtonOriginY)];
596 [helpButton_ setTarget:self];
597 [helpButton_ setAction:@selector(onHelpPressed:)];
598 [self addSubview:helpButton_];
599
600 // Scanning message.
601 CGFloat scanningMessageOriginX =
602 kMarginX + helpButtonWidth - kHorizontalPadding / 2;
603 CGFloat scanningMessageOriginY = helpButtonOriginY;
604 [scanningMessage_ setFrameOrigin:NSMakePoint(scanningMessageOriginX,
605 scanningMessageOriginY)];
606 [self addSubview:scanningMessage_];
607 [scanningMessage_ setHidden:YES];
608
609 // Word connector.
610 CGFloat wordConnectorOriginX =
611 kMarginX + helpButtonWidth - kHorizontalPadding / 2;
612 CGFloat wordConnectorOriginY = helpButtonOriginY;
613 [wordConnector_ setFrameOrigin:NSMakePoint(wordConnectorOriginX,
614 wordConnectorOriginY)];
615 [self addSubview:wordConnector_];
616 [wordConnector_ setHidden:YES];
617
618 // Re-scan button.
619 CGFloat reScanButtonOriginX =
620 kMarginX + helpButtonWidth + wordConnectorWidth - kHorizontalPadding;
621 CGFloat reScanButtonOriginY = helpButtonOriginY;
622 [rescanButton_
623 setFrameOrigin:NSMakePoint(reScanButtonOriginX, reScanButtonOriginY)];
624 [rescanButton_ setTarget:self];
625 [rescanButton_ setAction:@selector(onRescan:)];
626 [self addSubview:rescanButton_];
627 [rescanButton_ setHidden:YES];
628 }
629
630 chooserContentViewController_.reset(new ChooserContentViewController(
631 chooserController_.get(), adapterOffHelpButton_.get(),
632 adapterOffMessage_.get(), tableView_.get(), spinner_.get(),
633 scanningMessage_.get(), wordConnector_.get(), rescanButton_.get()));
634 }
635
636 return self;
637 }
638
639 - (base::scoped_nsobject<NSTextField>)createChooserTitle:(NSString*)title {
640 base::scoped_nsobject<NSTextField> titleView(
641 [[NSTextField alloc] initWithFrame:NSZeroRect]);
642 [titleView setDrawsBackground:NO];
643 [titleView setBezeled:NO];
644 [titleView setEditable:NO];
645 [titleView setSelectable:NO];
646 [titleView setStringValue:title];
647 [titleView setFont:[NSFont systemFontOfSize:[NSFont systemFontSize]]];
648 // The height is arbitrary as it will be adjusted later.
649 [titleView setFrameSize:NSMakeSize(kChooserWidth - 2 * kMarginX, 0.0f)];
650 [GTMUILocalizerAndLayoutTweaker sizeToFitFixedWidthTextField:titleView];
651 return titleView;
652 }
653
654 - (base::scoped_nsobject<NSView>)createTableRowView:(NSInteger)row {
655 NSInteger level = -1;
656 bool isConnected = false;
657 bool isPaired = false;
658 size_t numOptions = chooserController_->NumOptions();
659 base::scoped_nsobject<NSView> tableRowView;
660 if (numOptions == 0) {
661 DCHECK_EQ(0, row);
662 tableRowView.reset([[ChooserContentTableRowView alloc]
663 initWithText:[self optionAtIndex:row]]);
664 } else {
665 DCHECK_GE(row, 0);
666 DCHECK_LT(row, base::checked_cast<NSInteger>(numOptions));
667 size_t rowIndex = base::checked_cast<size_t>(row);
668 if (chooserController_->ShouldShowIconBeforeText()) {
669 level = base::checked_cast<NSInteger>(
670 chooserController_->GetSignalStrengthLevel(rowIndex));
671 }
672 isConnected = chooserController_->IsConnected(rowIndex);
673 isPaired = chooserController_->IsPaired(rowIndex);
674 bool textNeedIndentation = false;
675 for (size_t i = 0; i < numOptions; ++i) {
676 if (chooserController_->GetSignalStrengthLevel(i) != -1 ||
677 chooserController_->IsConnected(i)) {
678 textNeedIndentation = true;
679 break;
680 }
681 }
682 tableRowView.reset([[ChooserContentTableRowView alloc]
683 initWithText:[self optionAtIndex:row]
684 signalStrengthLevel:level
685 isConnected:isConnected
686 isPaired:isPaired
687 rowHeight:[self tableRowViewHeight:row]
688 textNeedIndentation:textNeedIndentation]);
689 }
690
691 return tableRowView;
692 }
693
694 - (CGFloat)tableRowViewHeight:(NSInteger)row {
695 size_t numOptions = chooserController_->NumOptions();
696 if (numOptions == 0) {
697 DCHECK_EQ(0, row);
698 return kTableRowViewOneLineHeight;
699 }
700
701 DCHECK_GE(row, 0);
702 DCHECK_LT(row, base::checked_cast<NSInteger>(numOptions));
703 size_t rowIndex = base::checked_cast<size_t>(row);
704 return chooserController_->IsPaired(rowIndex) ? kTableRowViewTwoLinesHeight
705 : kTableRowViewOneLineHeight;
706 }
707
708 - (base::scoped_nsobject<NSButton>)createButtonWithTitle:(NSString*)title {
709 base::scoped_nsobject<NSButton> button(
710 [[ConstrainedWindowButton alloc] initWithFrame:NSZeroRect]);
711 [button setButtonType:NSMomentaryPushInButton];
712 [button setTitle:title];
713 [button sizeToFit];
714 return button;
715 }
716
717 - (base::scoped_nsobject<NSButton>)createConnectButton {
718 NSString* connectTitle =
719 base::SysUTF16ToNSString(chooserController_->GetOkButtonLabel());
720 return [self createButtonWithTitle:connectTitle];
721 }
722
723 - (base::scoped_nsobject<NSButton>)createCancelButton {
724 NSString* cancelTitle =
725 l10n_util::GetNSString(IDS_DEVICE_CHOOSER_CANCEL_BUTTON_TEXT);
726 return [self createButtonWithTitle:cancelTitle];
727 }
728
729 - (base::scoped_nsobject<NSBox>)createSeparator {
730 base::scoped_nsobject<NSBox> spacer([[NSBox alloc] initWithFrame:NSZeroRect]);
731 [spacer setBoxType:NSBoxSeparator];
732 [spacer setBorderType:NSLineBorder];
733 [spacer setAlphaValue:kSeparatorAlphaValue];
734 [spacer setFrameSize:NSMakeSize(kChooserWidth, kSeparatorHeight)];
735 return spacer;
736 }
737
738 - (base::scoped_nsobject<NSButton>)createHyperlinkButtonWithText:
739 (NSString*)text {
740 base::scoped_nsobject<NSButton> button(
741 [[NSButton alloc] initWithFrame:NSZeroRect]);
742 base::scoped_nsobject<HyperlinkButtonCell> cell(
743 [[HyperlinkButtonCell alloc] initTextCell:text]);
744 [button setCell:cell.get()];
745 [button sizeToFit];
746 return button;
747 }
748
749 - (NSButton*)adapterOffHelpButton {
750 return adapterOffHelpButton_.get();
751 }
752
753 - (NSTableView*)tableView {
754 return tableView_.get();
755 }
756
757 - (SpinnerView*)spinner {
758 return spinner_.get();
759 }
760
761 - (NSButton*)connectButton {
762 return connectButton_.get();
763 }
764
765 - (NSButton*)cancelButton {
766 return cancelButton_.get();
767 }
768
769 - (NSButton*)helpButton {
770 return helpButton_.get();
771 }
772
773 - (NSTextField*)scanningMessage {
774 return scanningMessage_.get();
775 }
776
777 - (NSTextField*)wordConnector {
778 return wordConnector_.get();
779 }
780
781 - (NSButton*)rescanButton {
782 return rescanButton_.get();
783 }
784
785 - (NSInteger)numberOfOptions {
786 // When there are no devices, the table contains a message saying there are
787 // no devices, so the number of rows is always at least 1.
788 return std::max(static_cast<NSInteger>(chooserController_->NumOptions()),
789 static_cast<NSInteger>(1));
790 }
791
792 // When this function is called with numOptions == 0, it is to show the
793 // message saying there are no devices.
794 - (NSString*)optionAtIndex:(NSInteger)index {
795 NSInteger numOptions =
796 static_cast<NSInteger>(chooserController_->NumOptions());
797 if (numOptions == 0) {
798 DCHECK_EQ(0, index);
799 return base::SysUTF16ToNSString(chooserController_->GetNoOptionsText());
800 }
801
802 DCHECK_GE(index, 0);
803 DCHECK_LT(index, numOptions);
804
805 return base::SysUTF16ToNSString(
806 chooserController_->GetOption(static_cast<size_t>(index)));
807 }
808
809 - (void)updateTableView {
810 chooserContentViewController_->UpdateTableView();
811 }
812
813 - (void)accept {
814 NSIndexSet* selectedRows = [tableView_ selectedRowIndexes];
815 NSUInteger index = [selectedRows firstIndex];
816 std::vector<size_t> indices;
817 while (index != NSNotFound) {
818 indices.push_back(index);
819 index = [selectedRows indexGreaterThanIndex:index];
820 }
821 chooserController_->Select(indices);
822 }
823
824 - (void)cancel {
825 chooserController_->Cancel();
826 }
827
828 - (void)close {
829 chooserController_->Close();
830 }
831
832 - (void)onAdapterOffHelp:(id)sender {
833 chooserController_->OpenAdapterOffHelpUrl();
834 }
835
836 - (void)onRescan:(id)sender {
837 chooserController_->RefreshOptions();
838 }
839
840 - (void)onHelpPressed:(id)sender {
841 chooserController_->OpenHelpCenterUrl();
842 }
843
844 - (void)updateContentRowColor {
845 NSIndexSet* selectedRows = [tableView_ selectedRowIndexes];
846 NSInteger numOptions =
847 base::checked_cast<NSInteger>(chooserController_->NumOptions());
848 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
849 for (NSInteger rowIndex = 0; rowIndex < numOptions; ++rowIndex) {
850 BOOL isSelected = [selectedRows containsIndex:rowIndex];
851 // Update the color of the text.
852 [[self tableRowViewText:rowIndex]
853 setTextColor:(isSelected ? [NSColor whiteColor]
854 : [NSColor blackColor])];
855
856 // Update the color of the image.
857 if (chooserController_->ShouldShowIconBeforeText()) {
858 if (chooserController_->IsConnected(rowIndex)) {
859 [[self tableRowViewImage:rowIndex]
860 setImage:gfx::NSImageFromImageSkia(gfx::CreateVectorIcon(
861 gfx::VectorIconId::BLUETOOTH_CONNECTED,
862 isSelected ? SK_ColorWHITE : gfx::kChromeIconGrey))];
863 } else {
864 int signalStrengthLevel =
865 chooserController_->GetSignalStrengthLevel(rowIndex);
866 if (signalStrengthLevel != -1) {
867 int imageId =
868 isSelected
869 ? kSignalStrengthLevelImageSelectedIds[signalStrengthLevel]
870 : kSignalStrengthLevelImageIds[signalStrengthLevel];
871 [[self tableRowViewImage:rowIndex]
872 setImage:rb.GetNativeImageNamed(imageId).ToNSImage()];
873 }
874 }
875 }
876
877 // Update the color of paired status.
878 NSTextField* pairedStatusText = [self tableRowViewPairedStatus:rowIndex];
879 if (pairedStatusText) {
880 [pairedStatusText setTextColor:(skia::SkColorToCalibratedNSColor(
881 isSelected ? gfx::kGoogleGreen300
882 : gfx::kGoogleGreen700))];
883 }
884 }
885 }
886
887 - (NSImageView*)tableRowViewImage:(NSInteger)row {
888 ChooserContentTableRowView* tableRowView =
889 [tableView_ viewAtColumn:0 row:row makeIfNecessary:YES];
890 return [tableRowView image];
891 }
892
893 - (NSTextField*)tableRowViewText:(NSInteger)row {
894 ChooserContentTableRowView* tableRowView =
895 [tableView_ viewAtColumn:0 row:row makeIfNecessary:YES];
896 return [tableRowView text];
897 }
898
899 - (NSTextField*)tableRowViewPairedStatus:(NSInteger)row {
900 ChooserContentTableRowView* tableRowView =
901 [tableView_ viewAtColumn:0 row:row makeIfNecessary:YES];
902 return [tableRowView pairedStatus];
903 }
904
905 - (void)drawRect:(NSRect)rect {
906 [[NSColor colorWithCalibratedWhite:245.0f / 255.0f alpha:1.0f] setFill];
907 NSRect footnoteFrame =
908 NSMakeRect(0.0f, 0.0f, kChooserWidth, separatorOriginY_);
909 NSRectFill(footnoteFrame);
910 [super drawRect:footnoteFrame];
911 }
912
913 @end
OLDNEW
« no previous file with comments | « chrome/browser/ui/cocoa/chooser_content_view_cocoa.h ('k') | chrome/browser/ui/cocoa/device_chooser_content_view_cocoa.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698