jens@18
|
1 |
//
|
jens@18
|
2 |
// MYAddressField.m
|
jens@18
|
3 |
// YourMove
|
jens@18
|
4 |
//
|
jens@18
|
5 |
// Created by Jens Alfke on 7/16/08.
|
jens@18
|
6 |
// Copyright 2008 Jens Alfke. All rights reserved.
|
jens@18
|
7 |
//
|
jens@18
|
8 |
|
jens@18
|
9 |
#import "MYAddressField.h"
|
jens@18
|
10 |
#import "RegexKitLite.h"
|
jens@18
|
11 |
#import <AddressBook/AddressBook.h>
|
jens@18
|
12 |
|
jens@18
|
13 |
|
jens@18
|
14 |
@interface MYAddressField ()
|
jens@18
|
15 |
@property (retain) MYAddressItem *selectedAddress;
|
jens@18
|
16 |
@end
|
jens@18
|
17 |
|
jens@18
|
18 |
|
jens@18
|
19 |
@implementation MYAddressField
|
jens@18
|
20 |
|
jens@18
|
21 |
|
jens@18
|
22 |
@synthesize defaultAddresses=_defaultAddresses, addressProperty=_property, selectedAddress=_selectedAddress;
|
jens@18
|
23 |
|
jens@18
|
24 |
|
jens@18
|
25 |
- (void) _computeAddresses
|
jens@18
|
26 |
{
|
jens@18
|
27 |
NSMutableArray *newAddresses = $marray();
|
jens@18
|
28 |
if( _property ) {
|
jens@18
|
29 |
if( _prefix.length ) {
|
jens@18
|
30 |
// Find all the people in the address book matching _prefix:
|
jens@18
|
31 |
ABAddressBook *ab = [ABAddressBook sharedAddressBook];
|
jens@18
|
32 |
ABSearchElement *search = [ABPerson searchElementForProperty: _property
|
jens@18
|
33 |
label: nil
|
jens@18
|
34 |
key: nil
|
jens@18
|
35 |
value: nil
|
jens@18
|
36 |
comparison: kABNotEqual];
|
jens@18
|
37 |
for( ABPerson *person in [ab recordsMatchingSearchElement: search] ) {
|
jens@18
|
38 |
ABMultiValue *values = [person valueForProperty: _property];
|
jens@18
|
39 |
NSString *first = [person valueForProperty: kABFirstNameProperty];
|
jens@18
|
40 |
NSString *last = [person valueForProperty: kABLastNameProperty];
|
jens@18
|
41 |
BOOL nameMatches = _prefix==nil || ([first.lowercaseString hasPrefix: _prefix]
|
jens@18
|
42 |
|| [last.lowercaseString hasPrefix: _prefix]);
|
jens@18
|
43 |
for( int i=0; i<values.count; i++ ) {
|
jens@18
|
44 |
NSString *address = [values valueAtIndex: i];
|
jens@18
|
45 |
if( nameMatches || [address.lowercaseString hasPrefix: _prefix] ) {
|
jens@18
|
46 |
MYAddressItem *item = [[MYAddressItem alloc] initWithPerson: person
|
jens@18
|
47 |
addressType: _property
|
jens@18
|
48 |
address: address];
|
jens@18
|
49 |
[newAddresses addObject: item];
|
jens@18
|
50 |
[item release];
|
jens@18
|
51 |
}
|
jens@18
|
52 |
}
|
jens@18
|
53 |
}
|
jens@18
|
54 |
} else if( _defaultAddresses ) {
|
jens@18
|
55 |
[newAddresses addObjectsFromArray: _defaultAddresses];
|
jens@18
|
56 |
}
|
jens@18
|
57 |
}
|
jens@18
|
58 |
|
jens@18
|
59 |
[newAddresses sortUsingSelector: @selector(compare:)];
|
jens@18
|
60 |
|
jens@18
|
61 |
if( ifSetObj(&_addresses,newAddresses) )
|
jens@18
|
62 |
[self reloadData];
|
jens@18
|
63 |
}
|
jens@18
|
64 |
|
jens@18
|
65 |
- (NSArray*) addresses
|
jens@18
|
66 |
{
|
jens@18
|
67 |
if( ! _addresses )
|
jens@18
|
68 |
[self _computeAddresses];
|
jens@18
|
69 |
return _addresses;
|
jens@18
|
70 |
}
|
jens@18
|
71 |
|
jens@18
|
72 |
|
jens@18
|
73 |
- (void) awakeFromNib
|
jens@18
|
74 |
{
|
jens@18
|
75 |
if( ! _addresses )
|
jens@18
|
76 |
_addresses = [[NSMutableArray alloc] init];
|
jens@18
|
77 |
_property = [kABEmailProperty retain];
|
jens@18
|
78 |
self.completes = NO;
|
jens@18
|
79 |
self.usesDataSource = YES;
|
jens@18
|
80 |
self.dataSource = self;
|
jens@18
|
81 |
self.delegate = self;
|
jens@18
|
82 |
}
|
jens@18
|
83 |
|
jens@18
|
84 |
- (void) dealloc
|
jens@18
|
85 |
{
|
jens@18
|
86 |
[_addresses release];
|
jens@18
|
87 |
[_property release];
|
jens@18
|
88 |
[_prefix release];
|
jens@18
|
89 |
[_selectedAddress release];
|
jens@18
|
90 |
[super dealloc];
|
jens@18
|
91 |
}
|
jens@18
|
92 |
|
jens@18
|
93 |
|
jens@18
|
94 |
- (BOOL) isExpanded
|
jens@18
|
95 |
{
|
jens@18
|
96 |
id ax = NSAccessibilityUnignoredDescendant(self);
|
jens@18
|
97 |
return [[ax accessibilityAttributeValue: NSAccessibilityExpandedAttribute] boolValue];
|
jens@18
|
98 |
}
|
jens@18
|
99 |
|
jens@18
|
100 |
|
jens@18
|
101 |
- (void) setExpanded: (BOOL)expanded
|
jens@18
|
102 |
{
|
jens@18
|
103 |
id ax = NSAccessibilityUnignoredDescendant(self);
|
jens@18
|
104 |
[ax accessibilitySetValue: $object(expanded) forAttribute: NSAccessibilityExpandedAttribute];
|
jens@18
|
105 |
}
|
jens@18
|
106 |
|
jens@18
|
107 |
|
jens@18
|
108 |
- (void) controlTextDidChange: (NSNotification*)n
|
jens@18
|
109 |
{
|
jens@18
|
110 |
if( _prefix.length == 0 )
|
jens@18
|
111 |
self.expanded = YES;
|
jens@18
|
112 |
|
jens@18
|
113 |
if( ifSetObj(&_prefix, self.stringValue.lowercaseString) )
|
jens@18
|
114 |
[self _computeAddresses];
|
jens@18
|
115 |
MYAddressItem *item = [[MYAddressItem alloc] initWithString: self.stringValue
|
jens@18
|
116 |
addressType: _property];
|
jens@18
|
117 |
self.selectedAddress = item;
|
jens@18
|
118 |
[item release];
|
jens@18
|
119 |
|
jens@18
|
120 |
if( _prefix.length == 0 )
|
jens@18
|
121 |
self.expanded = NO;
|
jens@18
|
122 |
|
jens@18
|
123 |
//Log(@"Address selection = %@",self.selectedAddress);
|
jens@18
|
124 |
}
|
jens@18
|
125 |
|
jens@18
|
126 |
- (void)comboBoxSelectionDidChange:(NSNotification *)notification
|
jens@18
|
127 |
{
|
jens@18
|
128 |
int sel = self.indexOfSelectedItem;
|
jens@18
|
129 |
self.selectedAddress = sel>=0 ?[self.addresses objectAtIndex: sel] :nil;
|
jens@18
|
130 |
//Log(@"Address selection = %@",self.selectedAddress);
|
jens@18
|
131 |
}
|
jens@18
|
132 |
|
jens@18
|
133 |
|
jens@18
|
134 |
#pragma mark -
|
jens@18
|
135 |
#pragma mark DATA SOURCE:
|
jens@18
|
136 |
|
jens@18
|
137 |
|
jens@18
|
138 |
- (NSInteger)numberOfItemsInComboBox:(NSComboBox *)aComboBox
|
jens@18
|
139 |
{
|
jens@18
|
140 |
return self.addresses.count;
|
jens@18
|
141 |
}
|
jens@18
|
142 |
|
jens@18
|
143 |
- (id)comboBox:(NSComboBox *)aComboBox objectValueForItemAtIndex:(NSInteger)index
|
jens@18
|
144 |
{
|
jens@18
|
145 |
return [[self.addresses objectAtIndex: index] description];
|
jens@18
|
146 |
}
|
jens@18
|
147 |
|
jens@18
|
148 |
|
jens@18
|
149 |
@end
|
jens@18
|
150 |
|
jens@18
|
151 |
|
jens@18
|
152 |
|
jens@18
|
153 |
|
jens@18
|
154 |
@implementation MYAddressItem
|
jens@18
|
155 |
|
jens@18
|
156 |
- (id) initWithName: (NSString*)name
|
jens@18
|
157 |
addressType: (NSString*)addressType address: (NSString*)address
|
jens@18
|
158 |
{
|
jens@18
|
159 |
self = [super init];
|
jens@18
|
160 |
if( self ) {
|
jens@18
|
161 |
_name = name.length ?[name copy] :nil;
|
jens@18
|
162 |
_addressType = [addressType copy];
|
jens@18
|
163 |
_address = [address copy];
|
jens@18
|
164 |
}
|
jens@18
|
165 |
return self;
|
jens@18
|
166 |
}
|
jens@18
|
167 |
|
jens@18
|
168 |
- (id) initWithPerson: (ABPerson*)person
|
jens@18
|
169 |
addressType: (NSString*)addressType address: (NSString*)address
|
jens@18
|
170 |
{
|
jens@18
|
171 |
NSString *first = [person valueForProperty: kABFirstNameProperty] ?: @"";
|
jens@18
|
172 |
NSString *last = [person valueForProperty: kABLastNameProperty] ?: @"";
|
jens@18
|
173 |
NSString *name = $sprintf(@"%@ %@", first,last);
|
jens@18
|
174 |
|
jens@18
|
175 |
self = [self initWithName: name addressType: addressType address: address];
|
jens@18
|
176 |
if( self )
|
jens@18
|
177 |
_uuid = person.uniqueId.copy;
|
jens@18
|
178 |
return self;
|
jens@18
|
179 |
}
|
jens@18
|
180 |
|
jens@18
|
181 |
- (id) initWithString: (NSString*)str addressType: (NSString*)addressType
|
jens@18
|
182 |
{
|
jens@18
|
183 |
#define kJustAddrRegex "[-a-zA-Z0-9%_+.]+(?:@[-a-zA-Z0-9.]+)"
|
jens@18
|
184 |
static NSString* const kNameAndAddrRegex = @"^\\s*(\\S+)?\\s*<("kJustAddrRegex")>\\s*$";
|
jens@18
|
185 |
static NSString* const kAddrRegex = @"^\\s*("kJustAddrRegex")\\s*$";
|
jens@18
|
186 |
|
jens@18
|
187 |
NSString *name = nil;
|
jens@18
|
188 |
NSString *address = [str stringByMatching: kNameAndAddrRegex capture: 2];
|
jens@18
|
189 |
if( address ) {
|
jens@18
|
190 |
name = [str stringByMatching: kNameAndAddrRegex capture: 1];
|
jens@18
|
191 |
} else {
|
jens@18
|
192 |
address = [str stringByMatching: kAddrRegex];
|
jens@18
|
193 |
}
|
jens@18
|
194 |
if( ! address ) {
|
jens@18
|
195 |
[self release];
|
jens@18
|
196 |
return nil;
|
jens@18
|
197 |
}
|
jens@18
|
198 |
return [self initWithName: name addressType: addressType address: address];
|
jens@18
|
199 |
}
|
jens@18
|
200 |
|
jens@18
|
201 |
@synthesize name=_name, addressType=_addressType, address=_address;
|
jens@18
|
202 |
|
jens@18
|
203 |
- (ABPerson*) person
|
jens@18
|
204 |
{
|
jens@18
|
205 |
if( _uuid )
|
jens@18
|
206 |
return (ABPerson*) [[ABAddressBook sharedAddressBook] recordForUniqueId: _uuid];
|
jens@18
|
207 |
else
|
jens@18
|
208 |
return nil;
|
jens@18
|
209 |
}
|
jens@18
|
210 |
|
jens@18
|
211 |
- (NSString*) description
|
jens@18
|
212 |
{
|
jens@18
|
213 |
return $sprintf(@"%@%@<%@>", _name,(_name ?@" ":@""),_address);
|
jens@18
|
214 |
}
|
jens@18
|
215 |
|
jens@18
|
216 |
- (NSComparisonResult) compare: (MYAddressItem*)other
|
jens@18
|
217 |
{
|
jens@18
|
218 |
NSString *str1 = _name ?:_address;
|
jens@18
|
219 |
NSString *str2 = other->_name ?: other->_address;
|
jens@18
|
220 |
return [str1 localizedCaseInsensitiveCompare: str2];
|
jens@18
|
221 |
}
|
jens@18
|
222 |
|
jens@18
|
223 |
@end
|