On 2010 Feb 19, at 13:30, Sean McBride wrote:

> In my case currently, I need several separators and also an 'other...'
> item that brings up an open panel.

I don't know about the separators but I have done the 'Other...' item 
successfully.  Referring to my previous message, define a new class called 
FooChoice which is a thin wrapper around a Foo.  A regular FooChoice will have 
a Foo ivar, but your "Other..." FooChoice will instead have a selector ivar.  
Now, add to your model fooChoice and setFooChoice: methods which transform 
between Foo and FooChoice.  When setFooChoice: gets a fooChoice with a selector 
instead of a foo, it plays an NSOpenPanel.  (I suppose an MVC purist might do 
this in a controller class somewhere, but oh well it works for me.)  The 
FooChoice is kind of like a proxy, right?  Don't forget 
+keyPathsForValueAffectingXxxxxxx.

I'm pasting in below my ClientChoice class code.  It looks like it has some 
comments in it that you might find interesting.

#import <Cocoa/Cocoa.h>

@class Client ;

/*!
 @brief    A thin wrapper around a client, or a placeholder
 which allows users to choose "Other Mac Account" or "Choose File"
 instead of an existing client.

 @details  A client choice which wraps a client will have 
 a non-nil client ivar and a nil selector.&nbsp; A client choice
 which wraps a placeholder will have a nil client and a non-nil
 selector.
*/
@interface ClientChoice : NSObject {
    Client* m_client ;
    SEL m_selector ;
    id m_object ;
}

/*!
 @brief    The receiver's title, suitable for display as the title
 of a (popup) menu item.
*/
@property (readonly) NSString* displayName ;

@property (retain) Client* client ;
@property (assign) SEL selector ;
@property (retain) id object ;

/*!
 @brief    Returns a ClientChoice defined by a client.

 @details  Returns a ClientChoice even if client is nil.  This
 is so that the localized "No Selection" placeholder can be
 returned for displayName and appear in the popup in this case.
 @param    client  The client that is being wrapped
*/
+ (ClientChoice*)clientChoiceWithClient:(Client*)client ;

+ (ClientChoice*)clientChoiceInvolvingOtherMacAccount ;

+ (ClientChoice*)clientChoiceInvolvingLooseFile ;

+ 
(ClientChoice*)clientChoiceNewOtherAccountForWebAppExformat:(NSString*)exformat 
;

@end


#import "ClientChoice.h"
#import "Client.h"
#import "NSString+LocalizeSSY.h" ;
#import "BkmxBasis+Strings.h"
#import "Extore.h"

@implementation ClientChoice

@synthesize client = m_client ;
@synthesize selector = m_selector ;
@synthesize object = m_object ;

- (NSString*)displayName {
    NSString* displayName = nil ;

    Client* client = self.client ;
    if (client) {
        displayName = [client displayName] ;
    }
    else {
        SEL selector = [self selector] ;
        if (selector) {
            NSString* targetString = NSStringFromSelector(selector) ;
            NSString* aString ;
            
            aString = @"chooseClientOnOtherMacAccountWithObject:" ;
            if ([targetString isEqualToString:aString]) {
                displayName = [NSString stringWithFormat:@"%C %@",
                    0x27a4,
                    [NSString localize:@"accountMacOther"]] ;
            }
            else if ([targetString isEqualToString:@"chooseClientFromFile"]) {
                displayName = [NSString stringWithFormat:@"%C %@ %@",
                               0x27a4,
                               [NSString localizeFormat:
                                @"choose%0",
                                [NSString localize:@"file"]],
                               [[BkmxBasis sharedBasis] labelAdvanced]] ;
            }
            else if ([targetString 
isEqualToString:@"setClientWithNilProfileForWebAppExformat:"]) {
                NSString* newSlashOther = [NSString stringWithFormat:
                                           @"%@/%@",
                                           [NSString localize:@"new"],
                                           [NSString localize:@"other"]] ;
                displayName = [NSString stringWithFormat:
                               @"%@ - %@",
                               [[Extore extoreClassForExformat:[self object]] 
ownerAppDisplayName],
                               newSlashOther] ;
            }
            else {
                NSLog(@"Internal error 510-5918.  sel=%@", targetString) ;
            }
        }
        else {
            displayName = [NSString localizeFormat:@"no%0",
                           [NSString localize:@"selection"]] ;
        }        
    }
    
    return displayName ;
}

+ (ClientChoice*)clientChoice {
    ClientChoice* clientChoice = [[ClientChoice alloc] init] ;
    return [clientChoice autorelease] ;
}

+ (ClientChoice*)clientChoiceWithClient:(Client*)client {
    ClientChoice* clientChoice = [ClientChoice clientChoice] ;
    [clientChoice setClient:client] ;
    return clientChoice ;
}

+ (ClientChoice*)clientChoiceInvolvingOtherMacAccount {
    ClientChoice* clientChoice = [ClientChoice clientChoice] ;
    [clientChoice 
setSelector:@selector(chooseClientOnOtherMacAccountWithObject:)] ;
    return clientChoice ;
}

+ (ClientChoice*)clientChoiceInvolvingLooseFile {
    ClientChoice* clientChoice = [ClientChoice clientChoice] ;
    [clientChoice setSelector:@selector(chooseClientFromFile)] ;
    return clientChoice ;
}

+ 
(ClientChoice*)clientChoiceNewOtherAccountForWebAppExformat:(NSString*)exformat 
{
    ClientChoice* clientChoice = [ClientChoice clientChoice] ;
    [clientChoice 
setSelector:@selector(setClientWithNilProfileForWebAppExformat:)] ;
    [clientChoice setObject:exformat] ;
    return clientChoice ;
}

/*
 NSPopupMenuCell apparently uses isEqual: to match to an existing
 menu item when it gets the currently-selected value from the
 model.  Evidence: If this method is not implemented, when
 the user clicks the menu, it adds this value as an additional
 item, (and also it displays its -description instead of using
 the model key path in the Content Values binding, which in our
 case is displayName).  So you temporarily have this funky-looking
 extra item in the menu.  Hypothesis: Cocoa uses pointer equality if
 -isEqual: is not implemented, and doesn't find equality since
 we generate ClientChoice wrappers as needed, on the fly.
 Anyhow, I haven't seen this documented anywhere - I just took a
 wild guess to fix the problem when I saw the extra/funky menu
 item showing up when I clicked the popup menu in my Import and
 and Export Client table views, and this fixed it.
 */
- (BOOL)isEqual:(id)otherChoice {
    if ([[self client] isEqual:[otherChoice client]]) {
        return YES ;
    }
    else if (([(ClientChoice*)self selector] != NULL) || 
([(ClientChoice*)otherChoice selector] != NULL)) {
        // After a little testing I convinced myself that selectors
        // are system-wide constants.  That is, the value of
        // @selector(anyMethod:someArg:) is the same pointer address
        // at any point in the program.  So, since the selector ivars
        // are generated using the @selector() thing, I can just
        // compare their pointer values directly...
        return ([(ClientChoice*)self selector] == [(ClientChoice*)otherChoice 
selector]) ;
    }
    
    return NO ;
}

// Documentation says to override -hash if you override -isEqual:
- (NSUInteger)hash {
    if ([self client]) {
        return [[self client] hash] ;
    }
    else if ([(ClientChoice*)self selector] != NULL) {
        return [NSStringFromSelector([(ClientChoice*)self selector]) hash] ;
    }

    return 0 ;
}

- (NSString*)description {
    NSString* answer = [NSString stringWithFormat:@"ClientChoice %p with ", 
self] ;
    
    if (self.client) {
        answer = [answer stringByAppendingFormat:@"client; clientSignature %@", 
self.client.clientSignature] ;
    }
    else if (self.selector) {
        answer = [answer stringByAppendingFormat:@"selector %@", 
NSStringFromSelector(self.selector)] ;
    }
    else {
        // At one time, I saw this displayed when the user clicks the popup.
        // Doesn't make sense.  I quick-fixed it by mimicking
        // the -displayName output in this case.  Probably this
        // patch is no longer needed.
        answer = [NSString localizeFormat:@"no%0",
                       [NSString localize:@"selection"]] ;
    }
    
    return answer ;
}
    
- (void)dealloc {
    [m_client release] ;
    
    [super dealloc];
}

@end_______________________________________________

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Reply via email to