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