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/stack_view/card_set.h" | 5 #import "ios/chrome/browser/ui/stack_view/card_set.h" |
6 | 6 |
7 #import <QuartzCore/QuartzCore.h> | 7 #import <QuartzCore/QuartzCore.h> |
8 | 8 |
9 #include "base/logging.h" | 9 #include "base/logging.h" |
| 10 #import "base/mac/scoped_nsobject.h" |
10 #import "ios/chrome/browser/tabs/tab.h" | 11 #import "ios/chrome/browser/tabs/tab.h" |
11 #import "ios/chrome/browser/tabs/tab_model.h" | 12 #import "ios/chrome/browser/tabs/tab_model.h" |
12 #include "ios/chrome/browser/ui/rtl_geometry.h" | 13 #include "ios/chrome/browser/ui/rtl_geometry.h" |
13 #import "ios/chrome/browser/ui/stack_view/card_stack_layout_manager.h" | 14 #import "ios/chrome/browser/ui/stack_view/card_stack_layout_manager.h" |
14 #import "ios/chrome/browser/ui/stack_view/page_animation_util.h" | 15 #import "ios/chrome/browser/ui/stack_view/page_animation_util.h" |
15 #import "ios/chrome/browser/ui/stack_view/stack_card.h" | 16 #import "ios/chrome/browser/ui/stack_view/stack_card.h" |
16 #include "ios/chrome/browser/ui/ui_util.h" | 17 #include "ios/chrome/browser/ui/ui_util.h" |
17 #import "ios/web/web_state/ui/crw_web_controller.h" | 18 #import "ios/web/web_state/ui/crw_web_controller.h" |
18 | 19 |
19 #if !defined(__has_feature) || !__has_feature(objc_arc) | |
20 #error "This file requires ARC support." | |
21 #endif | |
22 | |
23 namespace { | 20 namespace { |
24 const CGFloat kMaxCardStaggerPercentage = 0.35; | 21 const CGFloat kMaxCardStaggerPercentage = 0.35; |
25 } | 22 } |
26 | 23 |
27 @interface CardSet ()<StackCardViewProvider, TabModelObserver> { | 24 @interface CardSet ()<StackCardViewProvider, TabModelObserver> { |
28 TabModel* tabModel_; | 25 base::scoped_nsobject<TabModel> tabModel_; |
29 UIView* view_; | 26 base::scoped_nsobject<UIView> view_; |
30 CardStackLayoutManager* stackModel_; | 27 base::scoped_nsobject<CardStackLayoutManager> stackModel_; |
31 UIImageView* stackShadow_; | 28 base::scoped_nsobject<UIImageView> stackShadow_; |
32 } | 29 } |
33 | 30 |
34 // Set to |YES| when the card set should draw a shadow around the entire stack. | 31 // Set to |YES| when the card set should draw a shadow around the entire stack. |
35 @property(nonatomic, assign) BOOL shouldShowShadow; | 32 @property(nonatomic, assign) BOOL shouldShowShadow; |
36 | 33 |
37 // Creates and returns an autoreleased StackCard from the given |tab| (which | 34 // Creates and returns an autoreleased StackCard from the given |tab| (which |
38 // must not be nil). | 35 // must not be nil). |
39 - (StackCard*)buildCardFromTab:(Tab*)tab; | 36 - (StackCard*)buildCardFromTab:(Tab*)tab; |
40 | 37 |
41 // Rebuilds the set of cards from the current state of the tab model. | 38 // Rebuilds the set of cards from the current state of the tab model. |
(...skipping 15 matching lines...) Expand all Loading... |
57 @implementation CardSet | 54 @implementation CardSet |
58 | 55 |
59 @synthesize observer = observer_; | 56 @synthesize observer = observer_; |
60 @synthesize ignoresTabModelChanges = ignoresTabModelChanges_; | 57 @synthesize ignoresTabModelChanges = ignoresTabModelChanges_; |
61 @synthesize defersCardHiding = defersCardHiding_; | 58 @synthesize defersCardHiding = defersCardHiding_; |
62 @synthesize keepOnlyVisibleCardViewsAlive = keepOnlyVisibleCardViewsAlive_; | 59 @synthesize keepOnlyVisibleCardViewsAlive = keepOnlyVisibleCardViewsAlive_; |
63 @synthesize shouldShowShadow = shouldShowShadow_; | 60 @synthesize shouldShowShadow = shouldShowShadow_; |
64 @synthesize closingCard = closingCard_; | 61 @synthesize closingCard = closingCard_; |
65 | 62 |
66 - (CardStackLayoutManager*)stackModel { | 63 - (CardStackLayoutManager*)stackModel { |
67 return stackModel_; | 64 return stackModel_.get(); |
68 } | 65 } |
69 | 66 |
70 - (id)initWithModel:(TabModel*)model { | 67 - (id)initWithModel:(TabModel*)model { |
71 if ((self = [super init])) { | 68 if ((self = [super init])) { |
72 tabModel_ = model; | 69 tabModel_.reset([model retain]); |
73 [tabModel_ addObserver:self]; | 70 [tabModel_ addObserver:self]; |
74 stackModel_ = [[CardStackLayoutManager alloc] init]; | 71 stackModel_.reset([[CardStackLayoutManager alloc] init]); |
75 [self rebuildCards]; | 72 [self rebuildCards]; |
76 self.shouldShowShadow = YES; | 73 self.shouldShowShadow = YES; |
77 } | 74 } |
78 return self; | 75 return self; |
79 } | 76 } |
80 | 77 |
81 - (void)dealloc { | 78 - (void)dealloc { |
82 [tabModel_ removeObserver:self]; | 79 [tabModel_ removeObserver:self]; |
| 80 [super dealloc]; |
83 } | 81 } |
84 | 82 |
85 #pragma mark Properties | 83 #pragma mark Properties |
86 | 84 |
87 - (TabModel*)tabModel { | 85 - (TabModel*)tabModel { |
88 return tabModel_; | 86 return tabModel_; |
89 } | 87 } |
90 | 88 |
91 - (void)setTabModel:(TabModel*)tabModel { | 89 - (void)setTabModel:(TabModel*)tabModel { |
92 DCHECK([tabModel count] == 0); | 90 DCHECK([tabModel count] == 0); |
93 DCHECK([tabModel_ count] == 0); | 91 DCHECK([tabModel_ count] == 0); |
94 [tabModel_ removeObserver:self]; | 92 [tabModel_ removeObserver:self]; |
95 tabModel_ = tabModel; | 93 tabModel_.reset([tabModel retain]); |
96 if (!ignoresTabModelChanges_) | 94 if (!ignoresTabModelChanges_) |
97 [tabModel_ addObserver:self]; | 95 [tabModel_ addObserver:self]; |
98 } | 96 } |
99 | 97 |
100 - (NSArray*)cards { | 98 - (NSArray*)cards { |
101 return [stackModel_ cards]; | 99 return [stackModel_ cards]; |
102 } | 100 } |
103 | 101 |
104 - (StackCard*)currentCard { | 102 - (StackCard*)currentCard { |
105 DCHECK(!ignoresTabModelChanges_); | 103 DCHECK(!ignoresTabModelChanges_); |
(...skipping 11 matching lines...) Expand all Loading... |
117 } | 115 } |
118 | 116 |
119 - (void)setCurrentCard:(StackCard*)card { | 117 - (void)setCurrentCard:(StackCard*)card { |
120 DCHECK(!ignoresTabModelChanges_); | 118 DCHECK(!ignoresTabModelChanges_); |
121 NSInteger cardIndex = [self.cards indexOfObject:card]; | 119 NSInteger cardIndex = [self.cards indexOfObject:card]; |
122 DCHECK(cardIndex != NSNotFound); | 120 DCHECK(cardIndex != NSNotFound); |
123 [tabModel_ setCurrentTab:[tabModel_ tabAtIndex:cardIndex]]; | 121 [tabModel_ setCurrentTab:[tabModel_ tabAtIndex:cardIndex]]; |
124 } | 122 } |
125 | 123 |
126 - (UIView*)displayView { | 124 - (UIView*)displayView { |
127 return view_; | 125 return view_.get(); |
128 } | 126 } |
129 | 127 |
130 - (void)setDisplayView:(UIView*)view { | 128 - (void)setDisplayView:(UIView*)view { |
131 if (view == view_) | 129 if (view == view_.get()) |
132 return; | 130 return; |
133 for (StackCard* card in self.cards) { | 131 for (StackCard* card in self.cards) { |
134 if (card.viewIsLive) { | 132 if (card.viewIsLive) { |
135 [card.view removeFromSuperview]; | 133 [card.view removeFromSuperview]; |
136 [card releaseView]; | 134 [card releaseView]; |
137 } | 135 } |
138 } | 136 } |
139 [stackShadow_ removeFromSuperview]; | 137 [stackShadow_ removeFromSuperview]; |
140 view_ = view; | 138 view_.reset([view retain]); |
141 // Add the stack shadow view to the new display view. | 139 // Add the stack shadow view to the new display view. |
142 if (!stackShadow_) { | 140 if (!stackShadow_) { |
143 UIImage* shadowImage = [UIImage imageNamed:kCardShadowImageName]; | 141 UIImage* shadowImage = [UIImage imageNamed:kCardShadowImageName]; |
144 shadowImage = [shadowImage | 142 shadowImage = [shadowImage |
145 resizableImageWithCapInsets:UIEdgeInsetsMake( | 143 resizableImageWithCapInsets:UIEdgeInsetsMake( |
146 shadowImage.size.height / 2.0, | 144 shadowImage.size.height / 2.0, |
147 shadowImage.size.width / 2.0, | 145 shadowImage.size.width / 2.0, |
148 shadowImage.size.height / 2.0, | 146 shadowImage.size.height / 2.0, |
149 shadowImage.size.width / 2.0)]; | 147 shadowImage.size.width / 2.0)]; |
150 stackShadow_ = [[UIImageView alloc] initWithImage:shadowImage]; | 148 stackShadow_.reset([[UIImageView alloc] initWithImage:shadowImage]); |
151 [stackShadow_ setHidden:!self.cards.count]; | 149 [stackShadow_ setHidden:!self.cards.count]; |
152 } | 150 } |
153 [view_ addSubview:stackShadow_]; | 151 [view_ addSubview:stackShadow_]; |
154 // Don't set the stack's end limit when the view is set to nil in order to | 152 // Don't set the stack's end limit when the view is set to nil in order to |
155 // avoid losing existing card positions; these positions will be needed | 153 // avoid losing existing card positions; these positions will be needed |
156 // if/when the view is restored (e.g., if the view was purged due to a memory | 154 // if/when the view is restored (e.g., if the view was purged due to a memory |
157 // warning while in a modal view and then restored when exiting the modal | 155 // warning while in a modal view and then restored when exiting the modal |
158 // view). | 156 // view). |
159 if (view_) | 157 if (view_.get()) |
160 [self displayViewSizeWasChanged]; | 158 [self displayViewSizeWasChanged]; |
161 } | 159 } |
162 | 160 |
163 - (CardCloseButtonSide)closeButtonSide { | 161 - (CardCloseButtonSide)closeButtonSide { |
164 return [stackModel_ layoutIsVertical] ? CardCloseButtonSide::TRAILING | 162 return [stackModel_ layoutIsVertical] ? CardCloseButtonSide::TRAILING |
165 : CardCloseButtonSide::LEADING; | 163 : CardCloseButtonSide::LEADING; |
166 } | 164 } |
167 | 165 |
168 - (void)setIgnoresTabModelChanges:(BOOL)ignoresTabModelChanges { | 166 - (void)setIgnoresTabModelChanges:(BOOL)ignoresTabModelChanges { |
169 if (ignoresTabModelChanges_ == ignoresTabModelChanges) | 167 if (ignoresTabModelChanges_ == ignoresTabModelChanges) |
(...skipping 229 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
399 // associated with this target to be removed. Note that if |object| is | 397 // associated with this target to be removed. Note that if |object| is |
400 // not a target of |recognizer| this method is a no-op. | 398 // not a target of |recognizer| this method is a no-op. |
401 [recognizer removeTarget:object action:NULL]; | 399 [recognizer removeTarget:object action:NULL]; |
402 } | 400 } |
403 } | 401 } |
404 } | 402 } |
405 | 403 |
406 - (void)removeCardAtIndex:(NSUInteger)index { | 404 - (void)removeCardAtIndex:(NSUInteger)index { |
407 DCHECK(index < [self.cards count]); | 405 DCHECK(index < [self.cards count]); |
408 StackCard* card = [self.cards objectAtIndex:index]; | 406 StackCard* card = [self.cards objectAtIndex:index]; |
| 407 [[card retain] autorelease]; |
409 [self.observer cardSet:self willRemoveCard:card atIndex:index]; | 408 [self.observer cardSet:self willRemoveCard:card atIndex:index]; |
410 [stackModel_ removeCard:card]; | 409 [stackModel_ removeCard:card]; |
411 | 410 |
412 [self.observer cardSet:self didRemoveCard:card atIndex:index]; | 411 [self.observer cardSet:self didRemoveCard:card atIndex:index]; |
413 } | 412 } |
414 | 413 |
415 #pragma mark Card Construction/Display | 414 #pragma mark Card Construction/Display |
416 | 415 |
417 - (StackCard*)buildCardFromTab:(Tab*)tab { | 416 - (StackCard*)buildCardFromTab:(Tab*)tab { |
418 DCHECK(tab); | 417 DCHECK(tab); |
419 StackCard* card = [[StackCard alloc] initWithViewProvider:self]; | 418 StackCard* card = [[[StackCard alloc] initWithViewProvider:self] autorelease]; |
420 card.size = [stackModel_ cardSize]; | 419 card.size = [stackModel_ cardSize]; |
421 card.tabID = reinterpret_cast<NSUInteger>(tab); | 420 card.tabID = reinterpret_cast<NSUInteger>(tab); |
422 | 421 |
423 return card; | 422 return card; |
424 } | 423 } |
425 | 424 |
426 - (void)rebuildCards { | 425 - (void)rebuildCards { |
427 [stackModel_ removeAllCards]; | 426 [stackModel_ removeAllCards]; |
428 | 427 |
429 for (Tab* tab in tabModel_) { | 428 for (Tab* tab in tabModel_.get()) { |
430 StackCard* card = [self buildCardFromTab:tab]; | 429 StackCard* card = [self buildCardFromTab:tab]; |
431 [stackModel_ addCard:card]; | 430 [stackModel_ addCard:card]; |
432 } | 431 } |
433 | 432 |
434 [self.observer cardSetRecreatedCards:self]; | 433 [self.observer cardSetRecreatedCards:self]; |
435 } | 434 } |
436 | 435 |
437 - (void)displayCard:(StackCard*)card { | 436 - (void)displayCard:(StackCard*)card { |
438 DCHECK(view_); | 437 DCHECK(view_); |
439 card.view.hidden = [stackModel_ cardIsCovered:card]; | 438 card.view.hidden = [stackModel_ cardIsCovered:card]; |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
479 | 478 |
480 - (CardView*)cardViewWithFrame:(CGRect)frame forStackCard:(StackCard*)card { | 479 - (CardView*)cardViewWithFrame:(CGRect)frame forStackCard:(StackCard*)card { |
481 DCHECK(!ignoresTabModelChanges_); | 480 DCHECK(!ignoresTabModelChanges_); |
482 NSUInteger cardIndex = [self.cards indexOfObject:card]; | 481 NSUInteger cardIndex = [self.cards indexOfObject:card]; |
483 DCHECK(cardIndex != NSNotFound); | 482 DCHECK(cardIndex != NSNotFound); |
484 Tab* tab = [tabModel_ tabAtIndex:cardIndex]; | 483 Tab* tab = [tabModel_ tabAtIndex:cardIndex]; |
485 DCHECK(tab); | 484 DCHECK(tab); |
486 NSString* title = tab.title; | 485 NSString* title = tab.title; |
487 if (![title length]) | 486 if (![title length]) |
488 title = tab.urlDisplayString; | 487 title = tab.urlDisplayString; |
489 CardView* view = [[CardView alloc] initWithFrame:frame | 488 CardView* view = |
490 isIncognito:[tabModel_ isOffTheRecord]]; | 489 [[[CardView alloc] initWithFrame:frame |
| 490 isIncognito:[tabModel_ isOffTheRecord]] autorelease]; |
491 [view setTitle:title]; | 491 [view setTitle:title]; |
492 [view setFavicon:[tab favicon]]; | 492 [view setFavicon:[tab favicon]]; |
493 [tab retrieveSnapshot:^(UIImage* image) { | 493 [tab retrieveSnapshot:^(UIImage* image) { |
494 [view setImage:image]; | 494 [view setImage:image]; |
495 }]; | 495 }]; |
496 if (!view.image) | 496 if (!view.image) |
497 [view setImage:[CRWWebController defaultSnapshotImage]]; | 497 [view setImage:[CRWWebController defaultSnapshotImage]]; |
498 view.closeButtonSide = self.closeButtonSide; | 498 view.closeButtonSide = self.closeButtonSide; |
499 | 499 |
500 return view; | 500 return view; |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
585 @implementation CardSet (Testing) | 585 @implementation CardSet (Testing) |
586 | 586 |
587 - (StackCard*)cardForTab:(Tab*)tab { | 587 - (StackCard*)cardForTab:(Tab*)tab { |
588 NSUInteger tabIndex = [tabModel_ indexOfTab:tab]; | 588 NSUInteger tabIndex = [tabModel_ indexOfTab:tab]; |
589 if (tabIndex == NSNotFound) | 589 if (tabIndex == NSNotFound) |
590 return nil; | 590 return nil; |
591 return [self.cards objectAtIndex:tabIndex]; | 591 return [self.cards objectAtIndex:tabIndex]; |
592 } | 592 } |
593 | 593 |
594 - (void)setStackModelForTesting:(CardStackLayoutManager*)stackModel { | 594 - (void)setStackModelForTesting:(CardStackLayoutManager*)stackModel { |
595 stackModel_ = stackModel; | 595 stackModel_.reset([stackModel retain]); |
596 } | 596 } |
597 | 597 |
598 @end | 598 @end |
OLD | NEW |