On Oct 24, 2013, at 9:01 AM, jonat...@mugginsoft.com wrote: > 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.
I recall that this can be tricky. Below is a method that I dug up from an old NSFormatter subclass that handles both min/max lengths, non-stored delimiters and filtering to acceptable characters, which I recall is also paste-proof. I can send the whole class files if you care. - (BOOL)isPartialStringValid:(NSString **)partial proposedSelectedRange:(NSRange *)proposedRange originalString:(NSString *)original originalSelectedRange:(NSRange)originalRange errorDescription:(NSString **)errorDescription { // ignore empty if( ! [*partial length] ) return YES; // we want a mutable string NSMutableString *newString = [NSMutableString stringWithString:*partial]; // if single deletion, adjust to ignore delimiters by changing what is expected to be deleted if( proposedRange->location == originalRange.location && originalRange.length == 1 && originalRange.location > 0 ) { while( ! [allowedCharacters characterIsMember:[original characterAtIndex:proposedRange->location]] ) { proposedRange->location--; } // re-adjust string & change orig [newString deleteCharactersInRange:NSMakeRange( proposedRange->location, originalRange.location - proposedRange->location )]; originalRange.location = proposedRange->location; } NSUInteger proposedLocation = proposedRange->location; // strip down--this will include removing delimiters & updating location [newString setString:[self filterToAllowed:newString location:&proposedLocation]]; // are we too long? if( maxLength > 0 && [newString length] > maxLength ) { // delete from added NSUInteger delta = [newString length] - maxLength; proposedLocation -= delta; [newString deleteCharactersInRange:NSMakeRange( proposedLocation, delta )]; NSBeep(); } // determine the string being added: if deletion or filter actions make orig before proposed, consider empty added NSString *addedString = nil; if( originalRange.location < proposedLocation ) addedString = [newString substringWithRange:NSMakeRange( originalRange.location, proposedLocation-originalRange.location )]; if( [addedString length] ) { addedString = [self caseFoldString:addedString precursor:[newString substringToIndex:originalRange.location]]; [newString replaceCharactersInRange:NSMakeRange( originalRange.location, proposedLocation-originalRange.location ) withString:addedString]; } else if( originalRange.location < [newString length] ) { // if no added--i.e. deletion or all added was filtered out--only check case folding if not at end addedString = [self caseFoldString:[newString substringWithRange:NSMakeRange( originalRange.location, 1 )] precursor:[newString substringToIndex:originalRange.location]]; [newString replaceCharactersInRange:NSMakeRange( originalRange.location, 1 ) withString:addedString]; } // now format & check changed NSString *finalString = [self formatString:newString location:&proposedLocation]; BOOL valid = [*partial isEqualToString:finalString]; // update proposed location proposedRange->location = proposedLocation; // check completions if( completions ) { NSUInteger i, count = [completions count]; for( i=0; i<count; i++ ) { NSString *proposed = [completions objectAtIndex:i]; if( [proposed rangeOfString:finalString options:NSCaseInsensitiveSearch].location == 0 && [proposed length] >= [finalString length] ) { *proposedRange = NSMakeRange( [finalString length], [proposed length] - [finalString length] ); finalString = proposed; break; } } } // always set *partial = finalString; return valid; } HTH, Keary Suska Esoteritech, Inc. "Demystifying technology for your home or business" _______________________________________________ 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