Have I missed something or is access to a decent NSFormatter subclass to handle 
NSTextField string length limiting troublesome?

There is some form on this:
 
http://stackoverflow.com/questions/827014/how-to-limit-nstextfield-text-length-and-keep-it-always-upper-case/827598#827598
 
http://www.cocoabuilder.com/archive/cocoa/184885-nsformatter-interfering-with-bindings-continuous-update.html

However the solutions provided have issues, some with bindings, and most 
suggestions don't handle pasted text well.

I am currently using the following. Comments, suggested improvements etc 
welcome.

Jonathan

@interface BPPlainTextFormatter : NSFormatter
{
    NSInteger _maxLength;
}

/*!
 
 Set the maximum string length. 
 
 Note that to use this class within a Nib:
 1. Add an NSFormatter as a Custom Formatter.
 2. In the Identity inspector set the Class to BPPlainTextFormatter
 3. In user defined attributes add Key Path: maxlength Type: Number Value: 30
 
Note that rather than attaching formatter instances to individual cells they
can be positioned in the nib Objects section and referenced by numerous 
controls.
A name, such as Plain Text Formatter 100, can  be used to identify the 
formatters max length.

 */
@property NSInteger maxLength;

@end

#define _TRACE

#import "BPPlainTextFormatter.h"

@implementation BPPlainTextFormatter
@synthesize maxLength = _maxLength;

- (id)init
{
    if(self = [super init]){
        self.maxLength = INT_MAX;
    }
    
    return self;
}

- (id)initWithCoder:(NSCoder *)aDecoder
{
    // support Nib based initialisation
    self = [super initWithCoder:aDecoder];
    if (self) {
        self.maxLength = INT_MAX;
    }
    
    return self;
}

#pragma mark -
#pragma mark Textual Representation of Cell Content

- (NSString *)stringForObjectValue:(id)object
{
    NSString *stringValue = nil;
    if ([object isKindOfClass:[NSString class]]) {
        
        // A new NSString is perhaps not required here
        // but generically a new object would be generated
        stringValue = [NSString stringWithString:object];
    }
    
    return stringValue;
}

#pragma mark -
#pragma mark Object Equivalent to Textual Representation

- (BOOL)getObjectValue:(id *)object forString:(NSString *)string 
errorDescription:(NSString **)error
{
    BOOL valid = YES;
    
    // Be sure to generate a new object here or binding woe ensues
    // when continuously updating bindings are enabled.
    *object = [NSString stringWithString:string];
    
    return valid;
}

#pragma mark -
#pragma mark Dynamic Cell Editing

- (BOOL)isPartialStringValid:(NSString **)partialStringPtr
       proposedSelectedRange:(NSRangePointer)proposedSelRangePtr
              originalString:(NSString *)origString
       originalSelectedRange:(NSRange)origSelRange
            errorDescription:(NSString **)error
{
    BOOL valid = YES;
    
    NSString *proposedString = *partialStringPtr;
    if ([proposedString length] > self.maxLength) {
        
        // The original string has been modified by one or more characters (via 
pasting).
        // Either way compute how much of the proposed string can be 
accommodated.
        NSInteger origLength = origString.length;
        NSInteger insertLength = self.maxLength - origLength;
        
        // If a range is selected then characters in that range will be removed
        // so adjust the insert length accordingly
        insertLength += origSelRange.length;
        
        // Get the string components
        NSString *prefix = [origString substringToIndex:origSelRange.location];
        NSString *suffix = [origString substringFromIndex:origSelRange.location 
+ origSelRange.length];
        NSString *insert = [proposedString 
substringWithRange:NSMakeRange(origSelRange.location, insertLength)];

#ifdef _TRACE
        
        NSLog(@"Original string: %@", origString);
        NSLog(@"Original selection location: %u length %u", 
origSelRange.location, origSelRange.length);
        
        NSLog(@"Proposed string: %@", proposedString);
        NSLog(@"Proposed selection location: %u length %u", 
proposedSelRangePtr->location, proposedSelRangePtr->length);
        
        NSLog(@"Prefix: %@", prefix);
        NSLog(@"Suffix: %@", suffix);
        NSLog(@"Insert: %@", insert);
#endif
        
        // Assemble the final string
        *partialStringPtr = [NSString stringWithFormat:@"%@%@%@", prefix, 
insert, suffix];

        // Fix-up the proposed selection range
        proposedSelRangePtr->location = origSelRange.location + insertLength;
        proposedSelRangePtr->length = 0;

#ifdef _TRACE
        
        NSLog(@"Final string: %@", *partialStringPtr);
        NSLog(@"Final selection location: %u length %u", 
proposedSelRangePtr->location, proposedSelRangePtr->length);
        
#endif
        valid = NO;
    }
    
    return valid;
}












_______________________________________________

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:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

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

Reply via email to