Ignore:
Timestamp:
11/10/02 05:34:08 (20 years ago)
Author:
Nicholas Riley
Message:

Pester 1.1a1.

English.lproj/InfoPlist.strings: Updated for 1.1a1.

English.lproj/MainMenu.nib: Placeholder for day names in popup menu, fixed up by code (this means you can still edit it from IB though). Added command-shift-T to both in/at cells (required, code removes one or the other as appropriate). Fixed up sizes of fields. Default to today (this will need fixing when we localized the word "today", but it's fine for now...).

English.lproj/Notifier.nib: Remove date formatter because we set a string directly now instead (could set formatter from code, but we don't).

NJRDateFormatter: many workarounds for Cocoa bugs: missing AM/PM, incorrect results with space before AM/PM, etc. Added class methods to do format manipulation and return localized formats which work for output (though not always for input; this class has an internal workaround for the AM/PM problem).

NJRFSObjectSelector: properly handle enabled attribute, store internally and report externally as appropriate. Previously, the button would become enabled if you dropped something on it even if it was supposed to be disabled.

NJRQTMediaPopUpButton: stop sound preview when button disabled.

NJRVoicePopUpButton: stop voice preview when button disabled.

PSAlarm: new method -dateString returns long date string. Maintain local copy of long date, short date and time formats, and locale, using NJRDateFormatter.

PSAlarmNotifierController: update to use -[PSAlarm dateString], -[PSAlarm timeString] for localization instead of using broken formatter.

PSAlarmSetController: update documentation for some more Cocoa bugs I need to file. Set time of day and date formatters with localized date formats from NJRDateFormatter (retain/release issue here?) Localize weekday popup for predefined dates. Localize static date display with NJRDateFormatter. Note a solution (thanks to Douglas Davidson) for figuring out which control is editing. Added command-shift-T key equivalent to toggle in/at. Properly work around bugs witih soundRepetitionCount flashing, except where it's impossible to do anything else.

Read Me.rtfd: Updated for 1.1a1.

VERSION: Updated for 1.1a1.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Cocoa/Pester/Source/NJRDateFormatter.m

    r21 r43  
    99#import "NJRDateFormatter.h"
    1010
     11NSUserDefaults *locale;
    1112
    1213@implementation NJRDateFormatter
     14
     15+ (void)initialize;
     16{
     17    locale = [[NSUserDefaults standardUserDefaults] retain];
     18}
     19
     20+ (NSString *)format:(NSString *)format withoutComponent:(unichar)component;
     21{
     22    NSScanner *scanner = [NSScanner scannerWithString: format];
     23    NSRange range;
     24    [scanner setCharactersToBeSkipped: [NSCharacterSet characterSetWithCharactersInString: @""]];
     25    while ([scanner scanUpToString: @"%" intoString: nil] || ![scanner isAtEnd]) {
     26        range.location = [scanner scanLocation];
     27        [scanner scanUpToCharactersFromSet: [NSCharacterSet letterCharacterSet] intoString: nil];
     28        if ([format characterAtIndex: [scanner scanLocation]] == component) {
     29            if ([scanner scanUpToString: @"%" intoString: nil] && ![scanner isAtEnd]) {
     30                NSMutableString *mutableFormat = [format mutableCopy];
     31                if (range.location != 0 && [[NSCharacterSet punctuationCharacterSet] characterIsMember: [format characterAtIndex: range.location - 1]]) {
     32                    range.location--; // "%I:%M:%S%p" -> "%I:%M%p"
     33                }
     34                range.length = [scanner scanLocation] - range.location;
     35                [mutableFormat deleteCharactersInRange: range];
     36                format = [mutableFormat copy];
     37                [mutableFormat release];
     38                return [format autorelease];
     39            } else {
     40                range = [format rangeOfCharacterFromSet: [NSCharacterSet letterCharacterSet] options: NSBackwardsSearch range: NSMakeRange(0, range.location)];
     41                return [format substringToIndex: NSMaxRange(range)];
     42            }
     43        }
     44    }
     45    return format;
     46}
     47
     48+ (NSString *)localizedDateFormatIncludingWeekday:(BOOL)weekday;
     49{
     50    NSString *format = [locale stringForKey: NSDateFormatString];
     51    if (weekday) return format;
     52    return [self format: format withoutComponent: (unichar)'A'];
     53}
     54
     55+ (NSString *)localizedShortDateFormatIncludingWeekday:(BOOL)weekday;
     56{
     57    NSString *format = [locale stringForKey: NSShortDateFormatString];
     58    if (weekday) return format;
     59    return [self format: format withoutComponent: (unichar)'A'];
     60}
     61
     62NSString *stringByInsertingStringAtLocation(NSString *string, NSString *insert, int location) {
     63    return [NSString stringWithFormat: @"%@%@%@", [string substringToIndex: location], insert,
     64        [string substringFromIndex: location]];
     65}
     66
     67+ (NSString *)localizedTimeFormatIncludingSeconds:(BOOL)seconds;
     68{
     69    NSString *format = [locale stringForKey: NSTimeFormatString];
     70    NSArray *ampm = [locale arrayForKey: NSAMPMDesignation];
     71    NSString *am = [ampm objectAtIndex: 0], *pm = [ampm objectAtIndex: 1];
     72    // work around bug with inconsistent AM/PM and time format
     73    if ([am isEqualToString: @""] && [pm isEqualToString: @""])
     74        format = [self format: format withoutComponent: 'p'];
     75    else {
     76        NSRange ampmComponentRange = [format rangeOfString: @"%p"];
     77        NSCharacterSet *whitespace = [NSCharacterSet whitespaceCharacterSet];
     78        BOOL needSpaceInFormatString = ![whitespace characterIsMember: [am characterAtIndex: 0]];
     79        if (ampmComponentRange.location == NSNotFound) // "%1I:%M:%S" -> "%1I:%M:%S%p", "%1I:%M:%S %p"
     80            format = [format stringByAppendingString: (needSpaceInFormatString ? @" %p" : @"%p")];
     81        else {
     82            NSRange whitespaceRange = [format rangeOfCharacterFromSet: whitespace options: NSBackwardsSearch range: NSMakeRange(0, ampmComponentRange.location)];
     83            if (whitespaceRange.location == NSNotFound) {
     84                if (needSpaceInFormatString) // "%1I:%M:%S%p" -> "%1I:%M:%S %p"
     85                    format = stringByInsertingStringAtLocation(format, @" ", ampmComponentRange.location);
     86                // else "%1I:%M:%S%p" -> no change
     87            } else {
     88                if (NSMaxRange(whitespaceRange) == ampmComponentRange.location) {
     89                    if (!needSpaceInFormatString) // "%1I:%M:%S %p" -> "%1I:%M:%S%p"
     90                        format = [[format substringToIndex: whitespaceRange.location] stringByAppendingString: [format substringFromIndex: ampmComponentRange.location]];
     91                    // else "%1I:%M:%S %p" -> no change
     92                } else {
     93                    if (needSpaceInFormatString)
     94                        format = stringByInsertingStringAtLocation(format, @" ", ampmComponentRange.location);
     95                    // else "%1I %M:%S%p" -> no change
     96                }
     97            }
     98        }
     99    }
     100    if (seconds) return format;
     101    return [self format: format withoutComponent: 'S'];
     102}
    13103
    14104// workaround for bug in Jaguar (and earlier?) NSCalendarDate dateWithNaturalLanguageString:
     
    25115    if (firstValidCharacter.length == 0)
    26116        return @"";
    27     lastValidCharacter = [string rangeOfCharacterFromSet:nonWhitespace options:NSBackwardsSearch];
     117    lastValidCharacter = [string rangeOfCharacterFromSet:nonWhitespace options: NSBackwardsSearch];
    28118
    29119    if (firstValidCharacter.location == 0 && lastValidCharacter.location == [string length] - 1)
    30120        return string;
    31121    else
    32         return [string substringWithRange:NSUnionRange(firstValidCharacter, lastValidCharacter)];
     122        return [string substringWithRange: NSUnionRange(firstValidCharacter, lastValidCharacter)];
    33123}
    34124
     125- (id)initWithDateFormat:(NSString *)format allowNaturalLanguage:(BOOL)flag;
     126{
     127    if ( (self = [super initWithDateFormat: format allowNaturalLanguage: flag]) != nil) {
     128        NSRange ampmRange = [format rangeOfString: @"%p"];
     129        NSArray *ampm = [locale arrayForKey: NSAMPMDesignation];
     130        NSString *am = [ampm objectAtIndex: 0], *pm = [ampm objectAtIndex: 1];
     131        if (flag && ampmRange.location != NSNotFound &&
     132            [[locale stringForKey: NSTimeFormatString] rangeOfString: @"%p"].location == NSNotFound && ![am isEqualToString: pm]) {
     133            // workaround for bug in NSCalendarDate dateWithNaturalLanguageString: discarding AM/PM value when AM/PM designations have spaces in them (of which the use thereof is a workaround for NSDateFormatter discarding the AM/PM value)
     134            NSMutableString *paddedFormat = [format mutableCopy];
     135            [paddedFormat replaceCharactersInRange: ampmRange withString: @" %p"];
     136            alteredLocale = [[locale dictionaryRepresentation] mutableCopy];
     137            [(NSMutableDictionary *)alteredLocale setObject: paddedFormat forKey: NSTimeFormatString];
     138            [(NSMutableDictionary *)alteredLocale setObject:
     139                [NSArray arrayWithObjects: stringByRemovingSurroundingWhitespace(am),
     140                    stringByRemovingSurroundingWhitespace(pm)] forKey: NSAMPMDesignation];
     141            [paddedFormat release];
     142        } else {
     143            alteredLocale = [(NSDictionary *)locale retain];
     144        }
     145    }
     146    return self;
     147}
     148
     149- (void)dealloc;
     150{
     151    [alteredLocale release];
     152    [super dealloc];
     153}
    35154
    36155- (BOOL)getObjectValue:(id *)anObject forString:(NSString *)string errorDescription:(NSString **)error
     
    41160    if (string == nil) return nil;
    42161    NS_DURING // dateWithNaturalLanguageString: can throw an exception
    43         date = [NSCalendarDate dateWithNaturalLanguageString: stringByRemovingSurroundingWhitespace(string)];
     162        date = [NSCalendarDate dateWithNaturalLanguageString: stringByRemovingSurroundingWhitespace(string) locale: alteredLocale];
     163        // NSLog(@"%@: natural language date is %@", string, date);
    44164    NS_HANDLER
    45165        if (error != nil) *error = [localException reason];
    46166        NS_VALUERETURN(NO, BOOL);
    47167    NS_ENDHANDLER
     168    // [super getObjectValue: anObject forString: string errorDescription: error];
     169    // NSLog(@"%@: formatter date is %@", string, anObject == nil ? @"(null)" : *anObject);
    48170    if (date == nil) return [super getObjectValue: anObject forString: string errorDescription: error];
    49171    *anObject = date;
Note: See TracChangeset for help on using the changeset viewer.