OLD | NEW |
1 // Copyright 2012 The Chromium Authors. All rights reserved. | 1 // Copyright 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #import "ios/chrome/browser/ui/tabs/tab_strip_controller.h" | 5 #import "ios/chrome/browser/ui/tabs/tab_strip_controller.h" |
6 #import "ios/chrome/browser/ui/tabs/tab_strip_controller_private.h" | 6 #import "ios/chrome/browser/ui/tabs/tab_strip_controller_private.h" |
7 | 7 |
8 #include <cmath> | 8 #include <cmath> |
9 #include <vector> | 9 #include <vector> |
10 | 10 |
11 #include "base/i18n/rtl.h" | 11 #include "base/i18n/rtl.h" |
12 #import "base/ios/weak_nsobject.h" | |
13 #include "base/mac/bundle_locations.h" | 12 #include "base/mac/bundle_locations.h" |
14 #include "base/mac/foundation_util.h" | 13 #include "base/mac/foundation_util.h" |
15 #include "base/mac/objc_property_releaser.h" | 14 |
16 #include "base/mac/scoped_nsobject.h" | |
17 #include "base/metrics/user_metrics.h" | 15 #include "base/metrics/user_metrics.h" |
18 #include "base/metrics/user_metrics_action.h" | 16 #include "base/metrics/user_metrics_action.h" |
19 #include "base/strings/sys_string_conversions.h" | 17 #include "base/strings/sys_string_conversions.h" |
20 #include "ios/chrome/browser/browser_state/chrome_browser_state.h" | 18 #include "ios/chrome/browser/browser_state/chrome_browser_state.h" |
21 #include "ios/chrome/browser/experimental_flags.h" | 19 #include "ios/chrome/browser/experimental_flags.h" |
22 #import "ios/chrome/browser/tabs/tab.h" | 20 #import "ios/chrome/browser/tabs/tab.h" |
23 #import "ios/chrome/browser/tabs/tab_model.h" | 21 #import "ios/chrome/browser/tabs/tab_model.h" |
24 #import "ios/chrome/browser/tabs/tab_model_observer.h" | 22 #import "ios/chrome/browser/tabs/tab_model_observer.h" |
25 #import "ios/chrome/browser/ui/commands/UIKit+ChromeExecuteCommand.h" | 23 #import "ios/chrome/browser/ui/commands/UIKit+ChromeExecuteCommand.h" |
26 #include "ios/chrome/browser/ui/commands/ios_command_ids.h" | 24 #include "ios/chrome/browser/ui/commands/ios_command_ids.h" |
27 #import "ios/chrome/browser/ui/fullscreen_controller.h" | 25 #import "ios/chrome/browser/ui/fullscreen_controller.h" |
28 #include "ios/chrome/browser/ui/rtl_geometry.h" | 26 #include "ios/chrome/browser/ui/rtl_geometry.h" |
29 #include "ios/chrome/browser/ui/tab_switcher/tab_switcher_tab_strip_placeholder_
view.h" | 27 #include "ios/chrome/browser/ui/tab_switcher/tab_switcher_tab_strip_placeholder_
view.h" |
30 #import "ios/chrome/browser/ui/tabs/tab_strip_controller+tab_switcher_animation.
h" | 28 #import "ios/chrome/browser/ui/tabs/tab_strip_controller+tab_switcher_animation.
h" |
31 #import "ios/chrome/browser/ui/tabs/tab_strip_view.h" | 29 #import "ios/chrome/browser/ui/tabs/tab_strip_view.h" |
32 #import "ios/chrome/browser/ui/tabs/tab_view.h" | 30 #import "ios/chrome/browser/ui/tabs/tab_view.h" |
33 #include "ios/chrome/browser/ui/tabs/target_frame_cache.h" | 31 #include "ios/chrome/browser/ui/tabs/target_frame_cache.h" |
34 #include "ios/chrome/browser/ui/ui_util.h" | 32 #include "ios/chrome/browser/ui/ui_util.h" |
35 #import "ios/chrome/browser/ui/uikit_ui_util.h" | 33 #import "ios/chrome/browser/ui/uikit_ui_util.h" |
36 #import "ios/chrome/browser/ui/util/snapshot_util.h" | 34 #import "ios/chrome/browser/ui/util/snapshot_util.h" |
37 #include "ios/chrome/grit/ios_strings.h" | 35 #include "ios/chrome/grit/ios_strings.h" |
38 #import "ios/web/public/web_state/web_state.h" | 36 #import "ios/web/public/web_state/web_state.h" |
39 #include "third_party/google_toolbox_for_mac/src/iPhone/GTMFadeTruncatingLabel.h
" | 37 #include "third_party/google_toolbox_for_mac/src/iPhone/GTMFadeTruncatingLabel.h
" |
40 #include "ui/gfx/image/image.h" | 38 #include "ui/gfx/image/image.h" |
41 | 39 |
| 40 #if !defined(__has_feature) || !__has_feature(objc_arc) |
| 41 #error "This file requires ARC support." |
| 42 #endif |
| 43 |
42 using base::UserMetricsAction; | 44 using base::UserMetricsAction; |
43 | 45 |
44 NSString* const kWillStartTabStripTabAnimation = | 46 NSString* const kWillStartTabStripTabAnimation = |
45 @"kWillStartTabStripTabAnimation"; | 47 @"kWillStartTabStripTabAnimation"; |
46 NSString* const kTabStripDragStarted = @"kTabStripDragStarted"; | 48 NSString* const kTabStripDragStarted = @"kTabStripDragStarted"; |
47 NSString* const kTabStripDragEnded = @"kTabStripDragEnded"; | 49 NSString* const kTabStripDragEnded = @"kTabStripDragEnded"; |
48 | 50 |
49 namespace TabStrip { | 51 namespace TabStrip { |
50 UIColor* BackgroundColor() { | 52 UIColor* BackgroundColor() { |
51 DCHECK(IsIPadIdiom()); | 53 DCHECK(IsIPadIdiom()); |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
111 | 113 |
112 // Offsets needed to keep the UI properly centered on high-res screens, in | 114 // Offsets needed to keep the UI properly centered on high-res screens, in |
113 // points. | 115 // points. |
114 const CGFloat kNewTabButtonBottomOffsetHighRes = 2.0; | 116 const CGFloat kNewTabButtonBottomOffsetHighRes = 2.0; |
115 } | 117 } |
116 | 118 |
117 @interface TabStripController ()<TabModelObserver, | 119 @interface TabStripController ()<TabModelObserver, |
118 TabStripViewLayoutDelegate, | 120 TabStripViewLayoutDelegate, |
119 UIGestureRecognizerDelegate, | 121 UIGestureRecognizerDelegate, |
120 UIScrollViewDelegate> { | 122 UIScrollViewDelegate> { |
121 base::scoped_nsobject<TabModel> _tabModel; | 123 TabModel* _tabModel; |
122 UIView* _view; | 124 UIView* _view; |
123 TabStripView* _tabStripView; | 125 TabStripView* _tabStripView; |
124 UIButton* _buttonNewTab; | 126 UIButton* _buttonNewTab; |
125 base::scoped_nsobject<UIButton> _tabSwitcherButton; | 127 UIButton* _tabSwitcherButton; |
126 | 128 |
127 // Background view of the tab switcher button. Only visible while in compact | 129 // Background view of the tab switcher button. Only visible while in compact |
128 // layout. | 130 // layout. |
129 base::scoped_nsobject<UIImageView> _tabSwitcherButtonBackgroundView; | 131 UIImageView* _tabSwitcherButtonBackgroundView; |
130 | 132 |
131 TabStrip::Style _style; | 133 TabStrip::Style _style; |
132 base::WeakNSProtocol<id<FullScreenControllerDelegate>> _fullscreenDelegate; | 134 __weak id<FullScreenControllerDelegate> _fullscreenDelegate; |
133 | 135 |
134 // Array of TabViews. There is a one-to-one correspondence between this array | 136 // Array of TabViews. There is a one-to-one correspondence between this array |
135 // and the set of Tabs in the TabModel. | 137 // and the set of Tabs in the TabModel. |
136 base::scoped_nsobject<NSMutableArray> _tabArray; | 138 NSMutableArray* _tabArray; |
137 | 139 |
138 // Set of TabViews that are currently closing. These TabViews are also in | 140 // Set of TabViews that are currently closing. These TabViews are also in |
139 // |_tabArray|. Used to translate between |_tabArray| indexes and TabModel | 141 // |_tabArray|. Used to translate between |_tabArray| indexes and TabModel |
140 // indexes. | 142 // indexes. |
141 base::scoped_nsobject<NSMutableSet> _closingTabs; | 143 NSMutableSet* _closingTabs; |
142 | 144 |
143 // Tracks target frames for TabViews. | 145 // Tracks target frames for TabViews. |
144 // TODO(rohitrao): This is unnecessary, as UIKit updates view frames | 146 // TODO(rohitrao): This is unnecessary, as UIKit updates view frames |
145 // immediately, so [view frame] will always return the end state of the | 147 // immediately, so [view frame] will always return the end state of the |
146 // current animation. We can remove this cache entirely. b/5516053 | 148 // current animation. We can remove this cache entirely. b/5516053 |
147 TargetFrameCache _targetFrames; | 149 TargetFrameCache _targetFrames; |
148 | 150 |
149 // Animate when doing layout. This flag is set by setNeedsLayoutWithAnimation | 151 // Animate when doing layout. This flag is set by setNeedsLayoutWithAnimation |
150 // and cleared in layoutSubviews. | 152 // and cleared in layoutSubviews. |
151 BOOL _animateLayout; | 153 BOOL _animateLayout; |
152 | 154 |
153 // The current tab width. Recomputed whenever a tab is added or removed. | 155 // The current tab width. Recomputed whenever a tab is added or removed. |
154 CGFloat _currentTabWidth; | 156 CGFloat _currentTabWidth; |
155 | 157 |
156 // View used to dim unselected tabs when in reordering mode. Nil when not | 158 // View used to dim unselected tabs when in reordering mode. Nil when not |
157 // reordering tabs. | 159 // reordering tabs. |
158 base::scoped_nsobject<UIView> _dimmingView; | 160 UIView* _dimmingView; |
159 | 161 |
160 // Is the selected tab highlighted, used when dragging or swiping tabs. | 162 // Is the selected tab highlighted, used when dragging or swiping tabs. |
161 BOOL _highlightsSelectedTab; | 163 BOOL _highlightsSelectedTab; |
162 | 164 |
163 // YES when in reordering mode. | 165 // YES when in reordering mode. |
164 // TODO(rohitrao): This is redundant with |_draggedTab|. Remove it. | 166 // TODO(rohitrao): This is redundant with |_draggedTab|. Remove it. |
165 BOOL _isReordering; | 167 BOOL _isReordering; |
166 | 168 |
167 // The tab that is currently being dragged. nil when not in reordering mode. | 169 // The tab that is currently being dragged. nil when not in reordering mode. |
168 base::scoped_nsobject<TabView> _draggedTab; | 170 TabView* _draggedTab; |
169 | 171 |
170 // The last known location of the touch that is dragging the tab. This | 172 // The last known location of the touch that is dragging the tab. This |
171 // location is in the coordinate system of |[_tabStripView superview]| because | 173 // location is in the coordinate system of |[_tabStripView superview]| because |
172 // that coordinate system does not change as the scroll view scrolls. | 174 // that coordinate system does not change as the scroll view scrolls. |
173 CGPoint _lastDragLocation; | 175 CGPoint _lastDragLocation; |
174 | 176 |
175 // Timer used to autoscroll when in reordering mode. Is nil when not active. | 177 // Timer used to autoscroll when in reordering mode. Is nil when not active. |
176 // Owned by its runloop. | 178 // Owned by its runloop. |
177 NSTimer* _autoscrollTimer; // weak | 179 NSTimer* _autoscrollTimer; // weak |
178 | 180 |
179 // The distance to scroll for each autoscroll timer tick. If negative, the | 181 // The distance to scroll for each autoscroll timer tick. If negative, the |
180 // tabstrip will scroll to the left; if positive, to the right. | 182 // tabstrip will scroll to the left; if positive, to the right. |
181 CGFloat _autoscrollDistance; | 183 CGFloat _autoscrollDistance; |
182 | 184 |
183 // The model index of the placeholder gap, if one exists. This value is used | 185 // The model index of the placeholder gap, if one exists. This value is used |
184 // as the new model index of the dragged tab when it is dropped. | 186 // as the new model index of the dragged tab when it is dropped. |
185 NSUInteger _placeholderGapModelIndex; | 187 NSUInteger _placeholderGapModelIndex; |
186 | |
187 base::mac::ObjCPropertyReleaser _propertyReleaser_TabStripController; | |
188 } | 188 } |
189 | 189 |
190 @property(nonatomic, readonly, retain) TabStripView* tabStripView; | 190 @property(nonatomic, readonly, retain) TabStripView* tabStripView; |
191 @property(nonatomic, readonly, retain) UIButton* buttonNewTab; | 191 @property(nonatomic, readonly, retain) UIButton* buttonNewTab; |
192 | 192 |
193 // Initializes the tab array based on the the entries in the TabModel. Creates | 193 // Initializes the tab array based on the the entries in the TabModel. Creates |
194 // one TabView per Tab and adds it to the tabstrip. A later call to | 194 // one TabView per Tab and adds it to the tabstrip. A later call to |
195 // |-layoutTabs| is needed to properly place the tabs in the correct positions. | 195 // |-layoutTabs| is needed to properly place the tabs in the correct positions. |
196 - (void)initializeTabArrayFromTabModel; | 196 - (void)initializeTabArrayFromTabModel; |
197 | 197 |
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
319 @implementation TabStripController | 319 @implementation TabStripController |
320 | 320 |
321 @synthesize buttonNewTab = _buttonNewTab; | 321 @synthesize buttonNewTab = _buttonNewTab; |
322 @synthesize highlightsSelectedTab = _highlightsSelectedTab; | 322 @synthesize highlightsSelectedTab = _highlightsSelectedTab; |
323 @synthesize tabStripView = _tabStripView; | 323 @synthesize tabStripView = _tabStripView; |
324 @synthesize view = _view; | 324 @synthesize view = _view; |
325 | 325 |
326 - (instancetype)initWithTabModel:(TabModel*)tabModel | 326 - (instancetype)initWithTabModel:(TabModel*)tabModel |
327 style:(TabStrip::Style)style { | 327 style:(TabStrip::Style)style { |
328 if ((self = [super init])) { | 328 if ((self = [super init])) { |
329 _propertyReleaser_TabStripController.Init(self, [TabStripController class]); | 329 _tabArray = [[NSMutableArray alloc] initWithCapacity:10]; |
330 _tabArray.reset([[NSMutableArray alloc] initWithCapacity:10]); | 330 _closingTabs = [[NSMutableSet alloc] initWithCapacity:5]; |
331 _closingTabs.reset([[NSMutableSet alloc] initWithCapacity:5]); | |
332 | 331 |
333 _tabModel.reset([tabModel retain]); | 332 _tabModel = tabModel; |
334 [_tabModel addObserver:self]; | 333 [_tabModel addObserver:self]; |
335 _style = style; | 334 _style = style; |
336 | 335 |
337 // |self.view| setup. | 336 // |self.view| setup. |
338 CGRect tabStripFrame = [UIApplication sharedApplication].keyWindow.bounds; | 337 CGRect tabStripFrame = [UIApplication sharedApplication].keyWindow.bounds; |
339 tabStripFrame.size.height = kTabStripHeight; | 338 tabStripFrame.size.height = kTabStripHeight; |
340 _view = [[UIView alloc] initWithFrame:tabStripFrame]; | 339 _view = [[UIView alloc] initWithFrame:tabStripFrame]; |
341 _view.autoresizingMask = (UIViewAutoresizingFlexibleWidth | | 340 _view.autoresizingMask = (UIViewAutoresizingFlexibleWidth | |
342 UIViewAutoresizingFlexibleBottomMargin); | 341 UIViewAutoresizingFlexibleBottomMargin); |
343 _view.backgroundColor = TabStrip::BackgroundColor(); | 342 _view.backgroundColor = TabStrip::BackgroundColor(); |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
425 | 424 |
426 - (instancetype)init { | 425 - (instancetype)init { |
427 NOTREACHED(); | 426 NOTREACHED(); |
428 return nil; | 427 return nil; |
429 } | 428 } |
430 | 429 |
431 - (void)dealloc { | 430 - (void)dealloc { |
432 [_tabStripView setDelegate:nil]; | 431 [_tabStripView setDelegate:nil]; |
433 [_tabStripView setLayoutDelegate:nil]; | 432 [_tabStripView setLayoutDelegate:nil]; |
434 [_tabModel removeObserver:self]; | 433 [_tabModel removeObserver:self]; |
435 [super dealloc]; | |
436 } | 434 } |
437 | 435 |
438 - (id<FullScreenControllerDelegate>)fullscreenDelegate { | 436 - (id<FullScreenControllerDelegate>)fullscreenDelegate { |
439 return _fullscreenDelegate; | 437 return _fullscreenDelegate; |
440 } | 438 } |
441 | 439 |
442 - (void)setFullscreenDelegate: | 440 - (void)setFullscreenDelegate: |
443 (id<FullScreenControllerDelegate>)fullscreenDelegate { | 441 (id<FullScreenControllerDelegate>)fullscreenDelegate { |
444 _fullscreenDelegate.reset(fullscreenDelegate); | 442 _fullscreenDelegate = fullscreenDelegate; |
445 } | 443 } |
446 | 444 |
447 - (void)initializeTabArrayFromTabModel { | 445 - (void)initializeTabArrayFromTabModel { |
448 DCHECK(_tabModel); | 446 DCHECK(_tabModel); |
449 for (Tab* tab in _tabModel.get()) { | 447 for (Tab* tab in _tabModel) { |
450 BOOL isSelectedTab = [_tabModel currentTab] == tab; | 448 BOOL isSelectedTab = [_tabModel currentTab] == tab; |
451 TabView* view = [self tabViewForTab:tab isSelected:isSelectedTab]; | 449 TabView* view = [self tabViewForTab:tab isSelected:isSelectedTab]; |
452 [_tabArray addObject:view]; | 450 [_tabArray addObject:view]; |
453 [_tabStripView addSubview:view]; | 451 [_tabStripView addSubview:view]; |
454 } | 452 } |
455 } | 453 } |
456 | 454 |
457 - (void)initializeTabArrayWithNoModel { | 455 - (void)initializeTabArrayWithNoModel { |
458 DCHECK(!_tabModel); | 456 DCHECK(!_tabModel); |
459 TabView* view = [self emptyTabView]; | 457 TabView* view = [self emptyTabView]; |
460 [_tabArray addObject:view]; | 458 [_tabArray addObject:view]; |
461 [_tabStripView addSubview:view]; | 459 [_tabStripView addSubview:view]; |
462 [view setSelected:YES]; | 460 [view setSelected:YES]; |
463 return; | 461 return; |
464 } | 462 } |
465 | 463 |
466 - (TabView*)emptyTabView { | 464 - (TabView*)emptyTabView { |
467 TabView* view = | 465 TabView* view = [[TabView alloc] initWithEmptyView:YES selected:YES]; |
468 [[[TabView alloc] initWithEmptyView:YES selected:YES] autorelease]; | |
469 [view setIncognitoStyle:(_style == TabStrip::kStyleIncognito)]; | 466 [view setIncognitoStyle:(_style == TabStrip::kStyleIncognito)]; |
470 [view setContentMode:UIViewContentModeRedraw]; | 467 [view setContentMode:UIViewContentModeRedraw]; |
471 | 468 |
472 // Setting the tab to be hidden marks it as a new tab. The layout code will | 469 // Setting the tab to be hidden marks it as a new tab. The layout code will |
473 // make the tab visible and set up the appropriate animations. | 470 // make the tab visible and set up the appropriate animations. |
474 [view setHidden:YES]; | 471 [view setHidden:YES]; |
475 | 472 |
476 return view; | 473 return view; |
477 } | 474 } |
478 | 475 |
479 - (TabView*)tabViewForTab:(Tab*)tab isSelected:(BOOL)isSelected { | 476 - (TabView*)tabViewForTab:(Tab*)tab isSelected:(BOOL)isSelected { |
480 TabView* view = | 477 TabView* view = [[TabView alloc] initWithEmptyView:NO selected:isSelected]; |
481 [[[TabView alloc] initWithEmptyView:NO selected:isSelected] autorelease]; | |
482 if (UseRTLLayout()) | 478 if (UseRTLLayout()) |
483 [view setTransform:CGAffineTransformMakeScale(-1, 1)]; | 479 [view setTransform:CGAffineTransformMakeScale(-1, 1)]; |
484 [view setIncognitoStyle:(_style == TabStrip::kStyleIncognito)]; | 480 [view setIncognitoStyle:(_style == TabStrip::kStyleIncognito)]; |
485 [view setContentMode:UIViewContentModeRedraw]; | 481 [view setContentMode:UIViewContentModeRedraw]; |
486 [[view titleLabel] setText:[tab title]]; | 482 [[view titleLabel] setText:[tab title]]; |
487 [view setFavicon:[tab favicon]]; | 483 [view setFavicon:[tab favicon]]; |
488 | 484 |
489 // Set the tab buttons' action messages. | 485 // Set the tab buttons' action messages. |
490 [view addTarget:self | 486 [view addTarget:self |
491 action:@selector(tabTapped:) | 487 action:@selector(tabTapped:) |
492 forControlEvents:UIControlEventTouchUpInside]; | 488 forControlEvents:UIControlEventTouchUpInside]; |
493 [[view closeButton] addTarget:self | 489 [[view closeButton] addTarget:self |
494 action:@selector(closeTab:) | 490 action:@selector(closeTab:) |
495 forControlEvents:UIControlEventTouchUpInside]; | 491 forControlEvents:UIControlEventTouchUpInside]; |
496 | 492 |
497 // Install a long press gesture recognizer to handle drag and drop. | 493 // Install a long press gesture recognizer to handle drag and drop. |
498 base::scoped_nsobject<UILongPressGestureRecognizer> longPress( | 494 UILongPressGestureRecognizer* longPress = |
499 [[UILongPressGestureRecognizer alloc] | 495 [[UILongPressGestureRecognizer alloc] |
500 initWithTarget:self | 496 initWithTarget:self |
501 action:@selector(handleLongPress:)]); | 497 action:@selector(handleLongPress:)]; |
502 [longPress setMinimumPressDuration:kDragAndDropLongPressDuration]; | 498 [longPress setMinimumPressDuration:kDragAndDropLongPressDuration]; |
503 [longPress setDelegate:self]; | 499 [longPress setDelegate:self]; |
504 [view addGestureRecognizer:longPress]; | 500 [view addGestureRecognizer:longPress]; |
505 | 501 |
506 // Giving the tab view exclusive touch prevents other views from receiving | 502 // Giving the tab view exclusive touch prevents other views from receiving |
507 // touches while a TabView is handling a touch. | 503 // touches while a TabView is handling a touch. |
508 [view setExclusiveTouch:YES]; | 504 [view setExclusiveTouch:YES]; |
509 | 505 |
510 // Setting the tab to be hidden marks it as a new tab. The layout code will | 506 // Setting the tab to be hidden marks it as a new tab. The layout code will |
511 // make the tab visible and set up the appropriate animations. | 507 // make the tab visible and set up the appropriate animations. |
(...skipping 14 matching lines...) Expand all Loading... |
526 - (void)installDimmingViewWithAnimation:(BOOL)animate { | 522 - (void)installDimmingViewWithAnimation:(BOOL)animate { |
527 // The dimming view should not cover the bottom 2px of the tab strip, as those | 523 // The dimming view should not cover the bottom 2px of the tab strip, as those |
528 // pixels are visually part of the top border of the toolbar. The bottom | 524 // pixels are visually part of the top border of the toolbar. The bottom |
529 // inset constants take into account the conversion from pixels to points. | 525 // inset constants take into account the conversion from pixels to points. |
530 CGRect frame = [_tabStripView bounds]; | 526 CGRect frame = [_tabStripView bounds]; |
531 frame.size.height -= (IsHighResScreen() ? kDimmingViewBottomInsetHighRes | 527 frame.size.height -= (IsHighResScreen() ? kDimmingViewBottomInsetHighRes |
532 : kDimmingViewBottomInset); | 528 : kDimmingViewBottomInset); |
533 | 529 |
534 // Create the dimming view if it doesn't exist. In all cases, make sure it's | 530 // Create the dimming view if it doesn't exist. In all cases, make sure it's |
535 // set up correctly. | 531 // set up correctly. |
536 if (_dimmingView.get()) | 532 if (_dimmingView) |
537 [_dimmingView setFrame:frame]; | 533 [_dimmingView setFrame:frame]; |
538 else | 534 else |
539 _dimmingView.reset([[UIView alloc] initWithFrame:frame]); | 535 _dimmingView = [[UIView alloc] initWithFrame:frame]; |
540 | 536 |
541 // Enable user interaction in order to eat touches from views behind it. | 537 // Enable user interaction in order to eat touches from views behind it. |
542 [_dimmingView setUserInteractionEnabled:YES]; | 538 [_dimmingView setUserInteractionEnabled:YES]; |
543 [_dimmingView setBackgroundColor:[TabStrip::BackgroundColor() | 539 [_dimmingView setBackgroundColor:[TabStrip::BackgroundColor() |
544 colorWithAlphaComponent:0]]; | 540 colorWithAlphaComponent:0]]; |
545 [_dimmingView setAutoresizingMask:(UIViewAutoresizingFlexibleWidth | | 541 [_dimmingView setAutoresizingMask:(UIViewAutoresizingFlexibleWidth | |
546 UIViewAutoresizingFlexibleHeight)]; | 542 UIViewAutoresizingFlexibleHeight)]; |
547 [_tabStripView addSubview:_dimmingView]; | 543 [_tabStripView addSubview:_dimmingView]; |
548 | 544 |
549 CGFloat duration = animate ? kTabStripFadeAnimationDuration : 0; | 545 CGFloat duration = animate ? kTabStripFadeAnimationDuration : 0; |
(...skipping 10 matching lines...) Expand all Loading... |
560 CGFloat duration = animate ? kTabStripFadeAnimationDuration : 0; | 556 CGFloat duration = animate ? kTabStripFadeAnimationDuration : 0; |
561 [UIView animateWithDuration:duration | 557 [UIView animateWithDuration:duration |
562 animations:^{ | 558 animations:^{ |
563 [_dimmingView setBackgroundColor:[TabStrip::BackgroundColor() | 559 [_dimmingView setBackgroundColor:[TabStrip::BackgroundColor() |
564 colorWithAlphaComponent:0]]; | 560 colorWithAlphaComponent:0]]; |
565 } | 561 } |
566 completion:^(BOOL finished) { | 562 completion:^(BOOL finished) { |
567 // Do not remove the dimming view if the animation was aborted. | 563 // Do not remove the dimming view if the animation was aborted. |
568 if (finished) { | 564 if (finished) { |
569 [_dimmingView removeFromSuperview]; | 565 [_dimmingView removeFromSuperview]; |
570 _dimmingView.reset(); | 566 _dimmingView = nil; |
571 } | 567 } |
572 }]; | 568 }]; |
573 } | 569 } |
574 } | 570 } |
575 | 571 |
576 - (void)recordUserMetrics:(id)sender { | 572 - (void)recordUserMetrics:(id)sender { |
577 if (sender == _buttonNewTab) | 573 if (sender == _buttonNewTab) |
578 base::RecordAction(UserMetricsAction("MobileTabStripNewTab")); | 574 base::RecordAction(UserMetricsAction("MobileTabStripNewTab")); |
579 else if (sender == _tabSwitcherButton.get()) | 575 else if (sender == _tabSwitcherButton) |
580 base::RecordAction(UserMetricsAction("MobileTabSwitcherOpen")); | 576 base::RecordAction(UserMetricsAction("MobileTabSwitcherOpen")); |
581 else | 577 else |
582 LOG(WARNING) << "Trying to record metrics for unknown sender " | 578 LOG(WARNING) << "Trying to record metrics for unknown sender " |
583 << base::SysNSStringToUTF8([sender description]); | 579 << base::SysNSStringToUTF8([sender description]); |
584 } | 580 } |
585 | 581 |
586 - (void)tabTapped:(id)sender { | 582 - (void)tabTapped:(id)sender { |
587 DCHECK([sender isKindOfClass:[TabView class]]); | 583 DCHECK([sender isKindOfClass:[TabView class]]); |
588 | 584 |
589 // Ignore taps while in reordering mode. | 585 // Ignore taps while in reordering mode. |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
643 object:nil]; | 639 object:nil]; |
644 break; | 640 break; |
645 default: | 641 default: |
646 NOTREACHED(); | 642 NOTREACHED(); |
647 } | 643 } |
648 } | 644 } |
649 | 645 |
650 - (NSUInteger)indexForModelIndex:(NSUInteger)modelIndex { | 646 - (NSUInteger)indexForModelIndex:(NSUInteger)modelIndex { |
651 NSUInteger index = modelIndex; | 647 NSUInteger index = modelIndex; |
652 NSUInteger i = 0; | 648 NSUInteger i = 0; |
653 for (TabView* tab in _tabArray.get()) { | 649 for (TabView* tab in _tabArray) { |
654 if ([_closingTabs containsObject:tab]) | 650 if ([_closingTabs containsObject:tab]) |
655 ++index; | 651 ++index; |
656 | 652 |
657 if (i == index) | 653 if (i == index) |
658 break; | 654 break; |
659 | 655 |
660 ++i; | 656 ++i; |
661 } | 657 } |
662 | 658 |
663 DCHECK_GE(index, modelIndex); | 659 DCHECK_GE(index, modelIndex); |
664 return index; | 660 return index; |
665 } | 661 } |
666 | 662 |
667 - (NSUInteger)modelIndexForIndex:(NSUInteger)index { | 663 - (NSUInteger)modelIndexForIndex:(NSUInteger)index { |
668 NSUInteger modelIndex = 0; | 664 NSUInteger modelIndex = 0; |
669 NSUInteger arrayIndex = 0; | 665 NSUInteger arrayIndex = 0; |
670 for (TabView* tab in _tabArray.get()) { | 666 for (TabView* tab in _tabArray) { |
671 if (arrayIndex == index) { | 667 if (arrayIndex == index) { |
672 if ([_closingTabs containsObject:tab]) | 668 if ([_closingTabs containsObject:tab]) |
673 return NSNotFound; | 669 return NSNotFound; |
674 return modelIndex; | 670 return modelIndex; |
675 } | 671 } |
676 | 672 |
677 if (![_closingTabs containsObject:tab]) | 673 if (![_closingTabs containsObject:tab]) |
678 ++modelIndex; | 674 ++modelIndex; |
679 | 675 |
680 ++arrayIndex; | 676 ++arrayIndex; |
(...skipping 22 matching lines...) Expand all Loading... |
703 // Install the dimming view, hide the new tab button, and select the tab so it | 699 // Install the dimming view, hide the new tab button, and select the tab so it |
704 // appears highlighted. | 700 // appears highlighted. |
705 Tab* tab = [_tabModel tabAtIndex:index]; | 701 Tab* tab = [_tabModel tabAtIndex:index]; |
706 self.highlightsSelectedTab = YES; | 702 self.highlightsSelectedTab = YES; |
707 _buttonNewTab.hidden = YES; | 703 _buttonNewTab.hidden = YES; |
708 [_tabModel setCurrentTab:tab]; | 704 [_tabModel setCurrentTab:tab]; |
709 | 705 |
710 // Set up initial drag state. | 706 // Set up initial drag state. |
711 _lastDragLocation = [gesture locationInView:[_tabStripView superview]]; | 707 _lastDragLocation = [gesture locationInView:[_tabStripView superview]]; |
712 _isReordering = YES; | 708 _isReordering = YES; |
713 _draggedTab.reset([view retain]); | 709 _draggedTab = view; |
714 _placeholderGapModelIndex = [self modelIndexForTabView:_draggedTab]; | 710 _placeholderGapModelIndex = [self modelIndexForTabView:_draggedTab]; |
715 | 711 |
716 // Update the autoscroll distance and timer. | 712 // Update the autoscroll distance and timer. |
717 [self computeAutoscrollDistanceForTabView:_draggedTab]; | 713 [self computeAutoscrollDistanceForTabView:_draggedTab]; |
718 if (_autoscrollDistance != 0) | 714 if (_autoscrollDistance != 0) |
719 [self installAutoscrollTimerIfNeeded]; | 715 [self installAutoscrollTimerIfNeeded]; |
720 else | 716 else |
721 [self removeAutoscrollTimer]; | 717 [self removeAutoscrollTimer]; |
722 } | 718 } |
723 | 719 |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
778 [self setNeedsLayoutWithAnimation]; | 774 [self setNeedsLayoutWithAnimation]; |
779 } | 775 } |
780 | 776 |
781 - (void)resetDragState { | 777 - (void)resetDragState { |
782 self.highlightsSelectedTab = NO; | 778 self.highlightsSelectedTab = NO; |
783 _buttonNewTab.hidden = NO; | 779 _buttonNewTab.hidden = NO; |
784 [self removeAutoscrollTimer]; | 780 [self removeAutoscrollTimer]; |
785 | 781 |
786 _isReordering = NO; | 782 _isReordering = NO; |
787 _placeholderGapModelIndex = NSNotFound; | 783 _placeholderGapModelIndex = NSNotFound; |
788 _draggedTab.reset(); | 784 _draggedTab = nil; |
789 } | 785 } |
790 | 786 |
791 - (BOOL)isReorderingTabs { | 787 - (BOOL)isReorderingTabs { |
792 return _isReordering; | 788 return _isReordering; |
793 } | 789 } |
794 | 790 |
795 - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer*)recognizer { | 791 - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer*)recognizer { |
796 DCHECK([recognizer isKindOfClass:[UILongPressGestureRecognizer class]]); | 792 DCHECK([recognizer isKindOfClass:[UILongPressGestureRecognizer class]]); |
797 | 793 |
798 // If a drag is already in progress, do not allow another to start. | 794 // If a drag is already in progress, do not allow another to start. |
(...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
946 | 942 |
947 // Observer method. | 943 // Observer method. |
948 - (void)tabModel:(TabModel*)model | 944 - (void)tabModel:(TabModel*)model |
949 didMoveTab:(Tab*)tab | 945 didMoveTab:(Tab*)tab |
950 fromIndex:(NSUInteger)fromIndex | 946 fromIndex:(NSUInteger)fromIndex |
951 toIndex:(NSUInteger)toIndex { | 947 toIndex:(NSUInteger)toIndex { |
952 DCHECK(!_isReordering); | 948 DCHECK(!_isReordering); |
953 | 949 |
954 // Reorder the objects in _tabArray to keep in sync with the model ordering. | 950 // Reorder the objects in _tabArray to keep in sync with the model ordering. |
955 NSUInteger arrayIndex = [self indexForModelIndex:fromIndex]; | 951 NSUInteger arrayIndex = [self indexForModelIndex:fromIndex]; |
956 base::scoped_nsobject<TabView> view( | 952 TabView* view = [_tabArray objectAtIndex:arrayIndex]; |
957 [[_tabArray objectAtIndex:arrayIndex] retain]); | |
958 [_tabArray removeObject:view]; | 953 [_tabArray removeObject:view]; |
959 [_tabArray insertObject:view atIndex:toIndex]; | 954 [_tabArray insertObject:view atIndex:toIndex]; |
960 [self setNeedsLayoutWithAnimation]; | 955 [self setNeedsLayoutWithAnimation]; |
961 } | 956 } |
962 | 957 |
963 // Observer method. | 958 // Observer method. |
964 - (void)tabModel:(TabModel*)model | 959 - (void)tabModel:(TabModel*)model |
965 didChangeActiveTab:(Tab*)newTab | 960 didChangeActiveTab:(Tab*)newTab |
966 previousTab:(Tab*)previousTab | 961 previousTab:(Tab*)previousTab |
967 atIndex:(NSUInteger)modelIndex { | 962 atIndex:(NSUInteger)modelIndex { |
968 for (TabView* view in _tabArray.get()) { | 963 for (TabView* view in _tabArray) { |
969 [view setSelected:NO]; | 964 [view setSelected:NO]; |
970 } | 965 } |
971 | 966 |
972 NSUInteger index = [self indexForModelIndex:modelIndex]; | 967 NSUInteger index = [self indexForModelIndex:modelIndex]; |
973 TabView* activeView = [_tabArray objectAtIndex:index]; | 968 TabView* activeView = [_tabArray objectAtIndex:index]; |
974 [activeView setSelected:YES]; | 969 [activeView setSelected:YES]; |
975 | 970 |
976 // No need to animate this change, as selecting a new tab simply changes the | 971 // No need to animate this change, as selecting a new tab simply changes the |
977 // z-ordering of the TabViews. If a new tab was selected as a result of a tab | 972 // z-ordering of the TabViews. If a new tab was selected as a result of a tab |
978 // closure, then the animated layout has already been scheduled. | 973 // closure, then the animated layout has already been scheduled. |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1025 [UIImage imageNamed:@"tabswitcher_tab_switcher_button"]; | 1020 [UIImage imageNamed:@"tabswitcher_tab_switcher_button"]; |
1026 tabSwitcherButtonIcon = [tabSwitcherButtonIcon | 1021 tabSwitcherButtonIcon = [tabSwitcherButtonIcon |
1027 imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; | 1022 imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; |
1028 int tabSwitcherButtonIdsAccessibilityLabel = | 1023 int tabSwitcherButtonIdsAccessibilityLabel = |
1029 IDS_IOS_TAB_STRIP_ENTER_TAB_SWITCHER; | 1024 IDS_IOS_TAB_STRIP_ENTER_TAB_SWITCHER; |
1030 NSString* tabSwitcherButtonEnglishUiAutomationName = @"Enter Tab Switcher"; | 1025 NSString* tabSwitcherButtonEnglishUiAutomationName = @"Enter Tab Switcher"; |
1031 const CGFloat tabStripHeight = _view.frame.size.height; | 1026 const CGFloat tabStripHeight = _view.frame.size.height; |
1032 CGRect buttonFrame = | 1027 CGRect buttonFrame = |
1033 CGRectMake(CGRectGetMaxX(_view.frame) - kTabSwitcherButtonWidth, 0.0, | 1028 CGRectMake(CGRectGetMaxX(_view.frame) - kTabSwitcherButtonWidth, 0.0, |
1034 kTabSwitcherButtonWidth, tabStripHeight); | 1029 kTabSwitcherButtonWidth, tabStripHeight); |
1035 _tabSwitcherButton.reset( | 1030 _tabSwitcherButton = [UIButton buttonWithType:UIButtonTypeCustom]; |
1036 [[UIButton buttonWithType:UIButtonTypeCustom] retain]); | |
1037 [_tabSwitcherButton setTintColor:[UIColor whiteColor]]; | 1031 [_tabSwitcherButton setTintColor:[UIColor whiteColor]]; |
1038 [_tabSwitcherButton setFrame:buttonFrame]; | 1032 [_tabSwitcherButton setFrame:buttonFrame]; |
1039 [_tabSwitcherButton setContentMode:UIViewContentModeCenter]; | 1033 [_tabSwitcherButton setContentMode:UIViewContentModeCenter]; |
1040 [_tabSwitcherButton setAutoresizingMask:UIViewAutoresizingFlexibleLeftMargin]; | 1034 [_tabSwitcherButton setAutoresizingMask:UIViewAutoresizingFlexibleLeftMargin]; |
1041 [_tabSwitcherButton setBackgroundColor:[UIColor clearColor]]; | 1035 [_tabSwitcherButton setBackgroundColor:[UIColor clearColor]]; |
1042 [_tabSwitcherButton setExclusiveTouch:YES]; | 1036 [_tabSwitcherButton setExclusiveTouch:YES]; |
1043 [_tabSwitcherButton setImage:tabSwitcherButtonIcon | 1037 [_tabSwitcherButton setImage:tabSwitcherButtonIcon |
1044 forState:UIControlStateNormal]; | 1038 forState:UIControlStateNormal]; |
1045 // Set target/action to bubble up with command id as tag. | 1039 // Set target/action to bubble up with command id as tag. |
1046 [_tabSwitcherButton addTarget:nil | 1040 [_tabSwitcherButton addTarget:nil |
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1167 } | 1161 } |
1168 | 1162 |
1169 // To handle content offset change without making views appear to jump, | 1163 // To handle content offset change without making views appear to jump, |
1170 // shift all of the subviews by an amount equal to the size change. | 1164 // shift all of the subviews by an amount equal to the size change. |
1171 [self shiftTabStripSubviews:oldOffset]; | 1165 [self shiftTabStripSubviews:oldOffset]; |
1172 return; | 1166 return; |
1173 } | 1167 } |
1174 | 1168 |
1175 NSUInteger numNonClosingTabsToLeft = 0; | 1169 NSUInteger numNonClosingTabsToLeft = 0; |
1176 NSUInteger i = 0; | 1170 NSUInteger i = 0; |
1177 for (TabView* tab in _tabArray.get()) { | 1171 for (TabView* tab in _tabArray) { |
1178 if ([_closingTabs containsObject:tab]) | 1172 if ([_closingTabs containsObject:tab]) |
1179 ++i; | 1173 ++i; |
1180 | 1174 |
1181 if (i == tabIndex) | 1175 if (i == tabIndex) |
1182 break; | 1176 break; |
1183 | 1177 |
1184 ++numNonClosingTabsToLeft; | 1178 ++numNonClosingTabsToLeft; |
1185 ++i; | 1179 ++i; |
1186 } | 1180 } |
1187 | 1181 |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1224 | 1218 |
1225 - (void)updateScrollViewFrameForTabSwitcherButton { | 1219 - (void)updateScrollViewFrameForTabSwitcherButton { |
1226 CGRect tabFrame = _tabStripView.frame; | 1220 CGRect tabFrame = _tabStripView.frame; |
1227 tabFrame.size.width = _view.bounds.size.width; | 1221 tabFrame.size.width = _view.bounds.size.width; |
1228 if (!IsCompactTablet()) { | 1222 if (!IsCompactTablet()) { |
1229 tabFrame.size.width -= kTabSwitcherButtonWidth; | 1223 tabFrame.size.width -= kTabSwitcherButtonWidth; |
1230 _tabStripView.contentInset = UIEdgeInsetsZero; | 1224 _tabStripView.contentInset = UIEdgeInsetsZero; |
1231 [_tabSwitcherButtonBackgroundView setHidden:YES]; | 1225 [_tabSwitcherButtonBackgroundView setHidden:YES]; |
1232 } else { | 1226 } else { |
1233 if (!_tabSwitcherButtonBackgroundView) { | 1227 if (!_tabSwitcherButtonBackgroundView) { |
1234 _tabSwitcherButtonBackgroundView.reset([[UIImageView alloc] init]); | 1228 _tabSwitcherButtonBackgroundView = [[UIImageView alloc] init]; |
1235 const CGFloat tabStripHeight = _view.frame.size.height; | 1229 const CGFloat tabStripHeight = _view.frame.size.height; |
1236 const CGRect backgroundViewFrame = CGRectMake( | 1230 const CGRect backgroundViewFrame = CGRectMake( |
1237 CGRectGetMaxX(_view.frame) - kTabSwitcherButtonBackgroundWidth, 0.0, | 1231 CGRectGetMaxX(_view.frame) - kTabSwitcherButtonBackgroundWidth, 0.0, |
1238 kTabSwitcherButtonBackgroundWidth, tabStripHeight); | 1232 kTabSwitcherButtonBackgroundWidth, tabStripHeight); |
1239 [_tabSwitcherButtonBackgroundView setFrame:backgroundViewFrame]; | 1233 [_tabSwitcherButtonBackgroundView setFrame:backgroundViewFrame]; |
1240 [_tabSwitcherButtonBackgroundView | 1234 [_tabSwitcherButtonBackgroundView |
1241 setAutoresizingMask:UIViewAutoresizingFlexibleLeftMargin]; | 1235 setAutoresizingMask:UIViewAutoresizingFlexibleLeftMargin]; |
1242 UIImage* backgroundTabSwitcherImage = | 1236 UIImage* backgroundTabSwitcherImage = |
1243 [UIImage imageNamed:@"tabstrip_toggle_button_gradient"]; | 1237 [UIImage imageNamed:@"tabstrip_toggle_button_gradient"]; |
1244 [_tabSwitcherButtonBackgroundView setImage:backgroundTabSwitcherImage]; | 1238 [_tabSwitcherButtonBackgroundView setImage:backgroundTabSwitcherImage]; |
(...skipping 303 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1548 } | 1542 } |
1549 | 1543 |
1550 @end | 1544 @end |
1551 | 1545 |
1552 #pragma mark - TabSwitcherAnimation | 1546 #pragma mark - TabSwitcherAnimation |
1553 | 1547 |
1554 @implementation TabStripController (TabSwitcherAnimation) | 1548 @implementation TabStripController (TabSwitcherAnimation) |
1555 | 1549 |
1556 - (TabSwitcherTabStripPlaceholderView*)placeholderView { | 1550 - (TabSwitcherTabStripPlaceholderView*)placeholderView { |
1557 TabSwitcherTabStripPlaceholderView* placeholderView = | 1551 TabSwitcherTabStripPlaceholderView* placeholderView = |
1558 [[[TabSwitcherTabStripPlaceholderView alloc] | 1552 [[TabSwitcherTabStripPlaceholderView alloc] |
1559 initWithFrame:self.view.bounds] autorelease]; | 1553 initWithFrame:self.view.bounds]; |
1560 CGFloat xOffset = [_tabStripView contentOffset].x; | 1554 CGFloat xOffset = [_tabStripView contentOffset].x; |
1561 UIView* previousView = nil; | 1555 UIView* previousView = nil; |
1562 const NSUInteger selectedModelIndex = | 1556 const NSUInteger selectedModelIndex = |
1563 [_tabModel indexOfTab:[_tabModel currentTab]]; | 1557 [_tabModel indexOfTab:[_tabModel currentTab]]; |
1564 const NSUInteger selectedArrayIndex = | 1558 const NSUInteger selectedArrayIndex = |
1565 [self indexForModelIndex:selectedModelIndex]; | 1559 [self indexForModelIndex:selectedModelIndex]; |
1566 [self updateContentSizeAndRepositionViews]; | 1560 [self updateContentSizeAndRepositionViews]; |
1567 [self layoutTabStripSubviews]; | 1561 [self layoutTabStripSubviews]; |
1568 for (NSUInteger tabArrayIndex = 0; tabArrayIndex < [_tabArray count]; | 1562 for (NSUInteger tabArrayIndex = 0; tabArrayIndex < [_tabArray count]; |
1569 ++tabArrayIndex) { | 1563 ++tabArrayIndex) { |
(...skipping 22 matching lines...) Expand all Loading... |
1592 | 1586 |
1593 @implementation TabStripController (Testing) | 1587 @implementation TabStripController (Testing) |
1594 | 1588 |
1595 - (TabView*)existingTabViewForTab:(Tab*)tab { | 1589 - (TabView*)existingTabViewForTab:(Tab*)tab { |
1596 NSUInteger tabIndex = [_tabModel indexOfTab:tab]; | 1590 NSUInteger tabIndex = [_tabModel indexOfTab:tab]; |
1597 NSUInteger tabViewIndex = [self indexForModelIndex:tabIndex]; | 1591 NSUInteger tabViewIndex = [self indexForModelIndex:tabIndex]; |
1598 return [_tabArray objectAtIndex:tabViewIndex]; | 1592 return [_tabArray objectAtIndex:tabViewIndex]; |
1599 } | 1593 } |
1600 | 1594 |
1601 @end | 1595 @end |
OLD | NEW |