Index: trunk/Cocoa/Pester/Source/PSAlarmSetController.h
===================================================================
--- trunk/Cocoa/Pester/Source/PSAlarmSetController.h	(revision 621)
+++ trunk/Cocoa/Pester/Source/PSAlarmSetController.h	(revision 622)
@@ -15,4 +15,5 @@
 @class NJRValidatingField;
 @class NJRVoicePopUpButton;
+@class PSDateFieldEditor;
 
 @interface PSAlarmSetController : NSWindowController <NSUserInterfaceValidations> {
@@ -50,4 +51,5 @@
     NSTimer *updateTimer;
     PSAlarm *alarm;
+    PSDateFieldEditor *dateFieldEditor;
     BOOL isInterval;
 }
Index: trunk/Cocoa/Pester/Source/PSAlarmSetController.m
===================================================================
--- trunk/Cocoa/Pester/Source/PSAlarmSetController.m	(revision 621)
+++ trunk/Cocoa/Pester/Source/PSAlarmSetController.m	(revision 622)
@@ -25,4 +25,5 @@
 
 #import "PSAlerts.h"
+#import "PSDateFieldEditor.h"
 #import "PSDockBounceAlert.h"
 #import "PSScriptAlert.h"
@@ -113,4 +114,8 @@
     [voice setDelegate: self]; // XXX why don't we do this in IB?  It should use the accessor...
     [wakeUp setEnabled: [PSPowerManager autoWakeSupported]];
+    
+    dateFieldEditor = [[PSDateFieldEditor alloc] init];
+    [dateFieldEditor setFieldEditor: YES];
+    [dateFieldEditor setDelegate: timeDate];
     
     // XXX workaround for 10.1.x and 10.2.x bug which sets the first responder to the wrong field alternately, but it works if I set the initial first responder to nil... go figure.
@@ -605,9 +610,21 @@
 	[completions removeObjectAtIndex: i];
     }
-    NSLog(@"%@ %d %@", partialMatch, partialLength, completions);
     return [completions autorelease];
 }
 
 @end
+
+@implementation PSAlarmSetController (NSWindowDelegate)
+
+- (id)windowWillReturnFieldEditor:(NSWindow *)sender toObject:(id)client;
+{
+    if (client == timeDate)
+	return dateFieldEditor;
+
+    return nil;
+}
+
+@end
+
 
 @implementation PSAlarmSetController (NSWindowNotifications)
@@ -629,7 +646,5 @@
 - (void)controlTextDidEndEditing:(NSNotification *)notification;
 {
-    NSControl *control = [notification object];
-
-    if (control != timeOfDay)
+    if ([notification object] != timeOfDay)
 	return;
     
@@ -683,5 +698,4 @@
 }
 
-// XXX need to override NSTextView; when completing with space or tab, we don't get a selector, which causes usability problems with tab and bugs with space
 - (BOOL)control:(NSControl *)control textView:(NSTextView *)textView doCommandBySelector:(SEL)commandSelector;
 {
Index: trunk/Cocoa/Pester/Source/PSDateFieldEditor.h
===================================================================
--- trunk/Cocoa/Pester/Source/PSDateFieldEditor.h	(revision 622)
+++ trunk/Cocoa/Pester/Source/PSDateFieldEditor.h	(revision 622)
@@ -0,0 +1,16 @@
+//
+//  PSDateFieldEditor.h
+//  Pester
+//
+//  Created by Nicholas Riley on 3/1/10.
+//  Copyright 2010 Nicholas Riley. All rights reserved.
+//
+
+#import <Cocoa/Cocoa.h>
+
+
+@interface PSDateFieldEditor : NSTextView {
+
+}
+
+@end
Index: trunk/Cocoa/Pester/Source/PSDateFieldEditor.m
===================================================================
--- trunk/Cocoa/Pester/Source/PSDateFieldEditor.m	(revision 622)
+++ trunk/Cocoa/Pester/Source/PSDateFieldEditor.m	(revision 622)
@@ -0,0 +1,35 @@
+//
+//  PSDateFieldEditor.m
+//  Pester
+//
+//  Created by Nicholas Riley on 3/1/10.
+//  Copyright 2010 Nicholas Riley. All rights reserved.
+//
+
+#import "PSDateFieldEditor.h"
+
+
+@implementation PSDateFieldEditor
+
+- (NSRange)rangeForUserCompletion;
+{
+    NSRange range = [super rangeForUserCompletion];
+    range.length += range.location;
+    range.location = 0;
+    
+    return range;
+}
+
+- (void)insertCompletion:(NSString *)word forPartialWordRange:(NSRange)charRange movement:(int)movement isFinal:(BOOL)flag;
+{
+    // space bar (or right arrow, which is less ideal)
+    if (movement == NSRightTextMovement)
+	flag = NO;
+	
+    [super insertCompletion:word forPartialWordRange:charRange movement:movement isFinal:flag];
+
+    if (movement == NSTabTextMovement)
+	[self insertTab: nil];
+}
+
+@end
Index: trunk/Cocoa/Pester/Source/Pester.xcodeproj/project.pbxproj
===================================================================
--- trunk/Cocoa/Pester/Source/Pester.xcodeproj/project.pbxproj	(revision 621)
+++ trunk/Cocoa/Pester/Source/Pester.xcodeproj/project.pbxproj	(revision 622)
@@ -15,4 +15,5 @@
 		E17562720CF8C53F00FC5057 /* Sparkle.framework in Copy Sparkle.framework */ = {isa = PBXBuildFile; fileRef = E17562610CF8C50B00FC5057 /* Sparkle.framework */; };
 		E17CA9AB0CF7F8CB00018B34 /* Manip.pm in Copy Perl Modules */ = {isa = PBXBuildFile; fileRef = E17CA9A90CF7F8C200018B34 /* Manip.pm */; };
+		E18E8230113CC5C300687310 /* PSDateFieldEditor.m in Sources */ = {isa = PBXBuildFile; fileRef = E18E822F113CC5C300687310 /* PSDateFieldEditor.m */; };
 		E1985796104F68EC0082AC3E /* ParseDate.m in Sources */ = {isa = PBXBuildFile; fileRef = E19CC53E0CFDE48C0079DCFC /* ParseDate.m */; };
 		E1985798104F68EC0082AC3E /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 29B97325FDCFA39411CA2CEA /* Foundation.framework */; };
@@ -230,4 +231,6 @@
 		E18DAAEB0442CC3E00050002 /* NJRSoundManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NJRSoundManager.m; sourceTree = "<group>"; };
 		E18DAAEE0442D02500050002 /* CoreAudio.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreAudio.framework; path = /System/Library/Frameworks/CoreAudio.framework; sourceTree = "<absolute>"; };
+		E18E822E113CC5C300687310 /* PSDateFieldEditor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PSDateFieldEditor.h; sourceTree = "<group>"; };
+		E18E822F113CC5C300687310 /* PSDateFieldEditor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PSDateFieldEditor.m; sourceTree = "<group>"; };
 		E198579D104F68EC0082AC3E /* libParseDate-10.6.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = "libParseDate-10.6.dylib"; sourceTree = BUILT_PRODUCTS_DIR; };
 		E19CC5220CFDE3350079DCFC /* libParseDate-10.4.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = "libParseDate-10.4.dylib"; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -687,4 +690,6 @@
 				F5F19871036B822E01EB0372 /* NJRVoicePopUpButton.h */,
 				F5F19870036B822E01EB0372 /* NJRVoicePopUpButton.m */,
+				E18E822E113CC5C300687310 /* PSDateFieldEditor.h */,
+				E18E822F113CC5C300687310 /* PSDateFieldEditor.m */,
 			);
 			name = Views;
@@ -950,4 +955,5 @@
 				E15044670CFCDC7E00DE47E9 /* NJRValidatingField.m in Sources */,
 				E12CBFD310CC310800159E88 /* NJRMenuSlider.m in Sources */,
+				E18E8230113CC5C300687310 /* PSDateFieldEditor.m in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
