-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathSSYTabView.m
168 lines (142 loc) · 5.09 KB
/
SSYTabView.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
#import "SSYTabView.h"
NSString* const SSYTabViewDidChangeItemNotification = @"SSYTabViewDidChangeItemNotification" ;
static NSString* SSYTabViewObservedKeyPath = @"selectedTabIndex" ;
@implementation SSYTabView
#if 0
#warning Logging SSYTabView Memory Managment
#define LOG_SSYTABVIEW_MEMORY_MANAGEMENT 1
#else
#endif
#if LOG_SSYTABVIEW_MEMORY_MANAGEMENT
- (id)initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder] ;
NSString* line = [NSString stringWithFormat:@"%p initted %03ld %@", self, (long)[self retainCount], SSYDebugCaller()] ;
printf("%s\n", [line UTF8String]) ;
return self ;
}
- (id)retain {
id x = [super retain] ;
NSString* line = [NSString stringWithFormat:@"retain %03ld %@", (long)[self retainCount], SSYDebugCaller()] ;
printf("%s\n", [line UTF8String]) ;
return x ;
}
- (id)autorelease {
NSString* line = [NSString stringWithFormat:@"autorelease %@", SSYDebugCaller()] ;
printf("%s\n", [line UTF8String]) ;
id x = [super autorelease] ;
return x ;
}
- (oneway void)release {
NSInteger rc = [self retainCount] ;
NSString* line = [NSString stringWithFormat:@"release %03ld %@", (long)rc-1, SSYDebugCaller()] ;
printf("%s\n", [line UTF8String]) ;
#if 0
if (rc == 1) {
[self retain] ;
[self autorelease] ;
}
#endif
[super release] ;
return ;
}
- (void)dealloc {
NSInteger rc = [self retainCount] ;
NSString* line = [NSString stringWithFormat:@"deallocc %03ld %p %@", (long)rc-1, self, SSYDebugCaller()] ;
printf("%s\n", [line UTF8String]) ;
[super dealloc] ;
}
#endif
+ (void)initialize {
if (self == [SSYTabView class] ) {
[self exposeBinding:SSYTabViewObservedKeyPath] ;
}
}
// This is the only support that is needed for the segmented control
- (NSInteger)selectedTabIndex {
NSInteger selectedTabIndex ;
@synchronized(self) {
selectedTabIndex = m_selectedTabIndex ; ;
}
return selectedTabIndex ;
}
- (void)setSelectedTabIndex:(NSInteger)selectedTabIndex {
@synchronized(self) {
m_selectedTabIndex = selectedTabIndex ;
if (selectedTabIndex == [[self tabViewItems] indexOfObject:[self selectedTabViewItem]]) {
return ;
}
NSString* identifier = [[self tabViewItemAtIndex:selectedTabIndex] identifier] ;
[toolbar setSelectedItemIdentifier:identifier] ;
// Now, we need to set the selected tab in super. There are three
// methods that we could choose to do this:
// selectTabViewItem:
// selectTabViewItemAtIndex:
// selectTabViewItemWithIdentifier:
// Presumably, one of these methods is the "designated/base" method
// which is invoked by the other two in super's implementation, and
// this is the one we want to invoke. Invoking either of the other
// two will cause an infinite loop when the designated/base method
// is invoked, because that message will come back to one of our
// overrides (see below) since it will not be sent to super in
// Apple's implementation. As it turns out, the correct answer,
// the only one which does not cause an infinite loop, is
// selectTabViewItem. However, since Apple is free to change the
// implementation, we instead use the method which is most
// straightforward, and avoid the infinite loop by setting
// m_lockOutInfiniteLoop momentarily, and check it in our
// overrides below.
m_lockOutInfiniteLoop = YES ;
[super selectTabViewItemAtIndex:selectedTabIndex] ;
// When the above message invokes any of the methods we have
// overridden below, they'll route to super too.
m_lockOutInfiniteLoop = NO ;
[[NSNotificationCenter defaultCenter] postNotificationName:SSYTabViewDidChangeItemNotification
object:self] ;
}
}
- (void)selectTabViewItem:(NSTabViewItem *)tabViewItem {
if (m_lockOutInfiniteLoop) {
[super selectTabViewItem:tabViewItem] ;
}
else {
NSInteger index = [[self tabViewItems] indexOfObject:tabViewItem] ;
if (index != NSNotFound) {
[self setSelectedTabIndex:index] ;
}
}
}
- (void)selectTabViewItemAtIndex:(NSInteger)index {
if (m_lockOutInfiniteLoop) {
[super selectTabViewItemAtIndex:index] ;
}
else {
[self setSelectedTabIndex:index] ;
}
}
- (void)selectTabViewItemWithIdentifier:(id)identifier {
if (m_lockOutInfiniteLoop) {
[super selectTabViewItemWithIdentifier:identifier] ;
}
else {
NSInteger index = [[[self tabViewItems] valueForKey:@"identifier"] indexOfObject:identifier] ;
if (index != NSNotFound) {
[self setSelectedTabIndex:index] ;
}
}
}
// Needed for propagating changes from toolbar to tab view
- (IBAction)changeTabViewItem:(NSToolbarItem*)sender {
NSString* identifier = [sender itemIdentifier] ;
// We have required that corresponding tab view items and toolbar items
// have the same identifiers. So we can do this:
[self selectTabViewItemWithIdentifier:identifier] ;
}
- (void)awakeFromNib {
// Set the initial state
NSTabViewItem* selectedTabViewItem = [self selectedTabViewItem] ;
// We have required that corresponding tab view items and toolbar items
// have the same identifiers. So we can do this:
NSString* identifier = [selectedTabViewItem identifier] ;
[toolbar setSelectedItemIdentifier:identifier] ;
}
@end