source: trunk/Cocoa/Pester/Source/NJRDateFormatter.m @ 361

Last change on this file since 361 was 361, checked in by Nicholas Riley, 12 years ago

VERSION: Updated for 1.1b5.

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

English.lproj/MainMenu.nib: Change IB compatibility level to 10.4.
Disable controls which lead to unstable functionality in this version.
Added Sparkle support. Hook up removeMessageButton to
PSAlarmSetController for "-" fallback drawing.

English.lproj/Preferences.nib: Added Sparkle checkbox.

English.lproj/Read Me.nib: Leopard-ized with source list coloring,
highlight and removed focus ring (which caused artifacts anyway).

English.lproj/Snooze until.nib: Use new natural language date strings
and calendar button bezel style.

Info-Pester.plist: Updated for 1.1b5. Added Sparkle support.

NJRDateFormatter.m: Comment out debug logging on every keystroke.

PSAlarmSetController.[hm]: If "-" image exists (on Leopard), don't
draw it with text as well.

PSAlerts.m: Don't describe bounce alert (which is present for
backwards compatibility, but doesn't work yet in this version).

PSPowerManager.m: Temporarily disable; untested in this version.

Pester.xcodeproj: Change Development/Deployment? to Debug/Release?.
Link to Sparkle. STRIP_INSTALLED_PRODUCT=NO on release version for
now (eventually, can investigate using symbol files).

Read Me.rtfd: Updated for 1.1b5. Use real links. Clean up release
notes. Credit Sparkle and Date::Manip. Clean up styles so they look
better in the read me viewer. Fix Omni link.

Sparkle.diff: Changes to Sparkle, which is included as an external.
These aren't yet automatically applied.

Updates/Application? icon.png: The icon converted to a PNG. This will
probably go away as it's too big.

Updates/release-notes.css: Release notes CSS based on the example that
comes with Sparkle.

Updates/release-notes.html: Dummy release notes file; nobody should
see this yet.

Updates/updates.xml: Initial Sparkle appcast file.

package-Pester.sh: Update for xcodebuild, Sparkle, etc. No longer
include source in download.

File size: 6.0 KB
Line 
1//
2//  NJRDateFormatter.m
3//  Pester
4//
5//  Created by Nicholas Riley on Wed Oct 09 2002.
6//  Copyright (c) 2002 Nicholas Riley. All rights reserved.
7//
8
9#import "NJRDateFormatter.h"
10
11// generated by perl -MExtUtils::Embed -e xsinit -- -o perlxsi.c
12#include <EXTERN.h>
13#include <perl.h>
14
15EXTERN_C void xs_init (pTHX);
16
17EXTERN_C void boot_DynaLoader (pTHX_ CV* cv);
18
19EXTERN_C void
20xs_init(pTHX)
21{
22    char *file = __FILE__;
23    dXSUB_SYS;
24   
25    /* DynaLoader is a special case */
26    newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, file);
27}
28// end generated code
29
30static PerlInterpreter *my_perl;
31static NSDateFormatter *dateManipFormatter;
32
33static NSDate *parse_natural_language_date(NSString *input) {
34    if (my_perl == NULL) return nil;
35   
36    if ([input rangeOfString: @"|"].length > 0) {
37        NSMutableString *sanitized = [[input mutableCopy] autorelease];
38        [sanitized replaceOccurrencesOfString: @"|" withString: @""
39                                      options: NSLiteralSearch
40                                        range: NSMakeRange(0, [sanitized length])];
41        input = sanitized;
42    }
43   
44    NSString *temp = [[NSString alloc] initWithFormat: @"UnixDate(q|%@|, '%%q')", input];
45    // NSLog(@"%@", temp);
46    SV *d = eval_pv([temp UTF8String], TRUE);
47    [temp release];
48    if (d == NULL) return nil;
49   
50    STRLEN s_len;
51    char *s = SvPV(d, s_len);
52    if (s == NULL || s_len == 0) return nil;
53   
54    NSDate *date = [dateManipFormatter dateFromString: [NSString stringWithUTF8String: s]];
55    // NSLog(@"%@", date);
56   
57    return date;
58}
59
60static void init_perl(void) {
61    const char *argv[] = {"", "-CSD", "-I", "", "-MDate::Manip", "-e", "0"};
62    argv[3] = [[[NSBundle mainBundle] resourcePath] fileSystemRepresentation];
63    PERL_SYS_INIT(0, NULL);
64    my_perl = perl_alloc();
65    if (my_perl == NULL) return;
66   
67    perl_construct(my_perl);
68    if (perl_parse(my_perl, xs_init, 7, (char **)argv, NULL) != 0) goto fail;
69   
70    PL_exit_flags |= PERL_EXIT_DESTRUCT_END;
71    if (perl_run(my_perl) != 0) goto fail;
72   
73    // XXX detect localization changes
74    eval_pv("Date_Init(\"Language=English\", \"DateFormat=non-US\", \"Internal=1\"", TRUE);
75
76    if (parse_natural_language_date(@"tomorrow") == nil) goto fail;
77   
78    return;
79   
80fail:
81    perl_destruct(my_perl);
82    perl_free(my_perl);
83    PERL_SYS_TERM();
84    my_perl = NULL;
85}
86
87// workaround for bug in Jaguar (and earlier?) NSCalendarDate dateWithNaturalLanguageString:
88NSString *stringByRemovingSurroundingWhitespace(NSString *string) {
89    static NSCharacterSet *nonWhitespace = nil;
90    NSRange firstValidCharacter, lastValidCharacter;
91   
92    if (!nonWhitespace) {
93        nonWhitespace = [[[NSCharacterSet characterSetWithCharactersInString:
94                           @" \t\r\n"] invertedSet] retain];
95    }
96   
97    firstValidCharacter = [string rangeOfCharacterFromSet:nonWhitespace];
98    if (firstValidCharacter.length == 0)
99        return @"";
100    lastValidCharacter = [string rangeOfCharacterFromSet:nonWhitespace options: NSBackwardsSearch];
101   
102    if (firstValidCharacter.location == 0 && lastValidCharacter.location == [string length] - 1)
103        return string;
104    else
105        return [string substringWithRange: NSUnionRange(firstValidCharacter, lastValidCharacter)];
106}
107
108static const NSDateFormatterStyle formatterStyles[] = {
109    NSDateFormatterShortStyle,
110    NSDateFormatterMediumStyle,
111    NSDateFormatterLongStyle,
112    NSDateFormatterFullStyle,
113    NSDateFormatterNoStyle
114};
115
116@implementation NJRDateFormatter
117
118#pragma mark initialize-release
119
120+ (void)initialize;
121{
122    dateManipFormatter = [[NSDateFormatter alloc] init];
123    [dateManipFormatter setDateFormat: @"yyyyMMddHHmmss"]; // Date::Manip's "%q"
124    init_perl();
125}
126
127+ (NJRDateFormatter *)dateFormatter;
128{
129    NJRDateFormatter *formatter = [[self alloc] init];
130    NSMutableArray *tryFormatters = [[NSMutableArray alloc] init];
131   
132    for (NSDateFormatterStyle *s = formatterStyles ; *s < NSDateFormatterNoStyle ; *s++) {
133        NSDateFormatter *tryFormatter = [[NSDateFormatter alloc] init];
134        [tryFormatter setLenient: YES];
135        [tryFormatter setTimeStyle: NSDateFormatterNoStyle];
136        [tryFormatter setDateStyle: *s];
137        [tryFormatters addObject: tryFormatter];
138        [tryFormatter release];
139    }
140    // XXX do this in init
141    formatter->tryFormatters = tryFormatters;
142
143    return [formatter autorelease];
144}
145
146+ (NJRDateFormatter *)timeFormatter;
147{
148    NJRDateFormatter *formatter = [[self alloc] init];
149    NSMutableArray *tryFormatters = [[NSMutableArray alloc] init];
150   
151    for (NSDateFormatterStyle *s = formatterStyles ; *s < NSDateFormatterNoStyle ; *s++) {
152        NSDateFormatter *tryFormatter = [[NSDateFormatter alloc] init];
153        [tryFormatter setLenient: YES];
154        [tryFormatter setTimeStyle: *s];
155        [tryFormatter setDateStyle: NSDateFormatterNoStyle];
156        [tryFormatters addObject: tryFormatter];
157        [tryFormatter release];
158    }
159    formatter->tryFormatters = tryFormatters;
160   
161    return [formatter autorelease];
162}
163
164- (void)dealloc;
165{
166    [tryFormatters release]; tryFormatters = nil;
167    [super dealloc];
168}
169
170#pragma mark primitive formatter
171
172- (NSString *)stringForObjectValue:(id)obj;
173{
174    return [super stringForObjectValue: obj];
175}
176
177- (NSAttributedString *)attributedStringForObjectValue:(id)obj withDefaultAttributes:(NSDictionary *)attrs;
178{
179    return [super attributedStringForObjectValue: obj
180                           withDefaultAttributes: attrs];
181}
182
183- (BOOL)getObjectValue:(id *)anObject forString:(NSString *)string errorDescription:(NSString **)error
184{
185    if ([super getObjectValue: anObject forString: string errorDescription: error])
186        return YES;
187       
188    NSDate *date;
189    NSEnumerator *e = [tryFormatters objectEnumerator];
190    NSDateFormatter *tryFormatter;
191   
192    // XXX untested; does this work?
193    while ( (tryFormatter = [e nextObject]) != nil) {
194        date = [tryFormatter dateFromString: string];
195        if (date != nil) goto success;
196    }
197   
198    date = parse_natural_language_date(string);
199    if (date != nil) goto success;
200   
201    return NO;
202
203success:
204    *anObject = date;
205    if (error != NULL) *error = nil;
206    return YES;
207}
208
209#pragma mark miscellaneous
210
211+ (BOOL)naturalLanguageParsingAvailable;
212{
213    return (my_perl != NULL);
214}
215@end
Note: See TracBrowser for help on using the repository browser.