MYAddressField.m
author Jens Alfke <jens@mooseyard.com>
Mon Aug 10 08:29:32 2009 -0700 (2009-08-10)
changeset 34 50c4f26bcc1b
permissions -rw-r--r--
Fixed signed/unsigned warnings in Base64.m.
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