diff --git a/baRSS.xcodeproj/project.pbxproj b/baRSS.xcodeproj/project.pbxproj index 53f0c68..105bee9 100644 --- a/baRSS.xcodeproj/project.pbxproj +++ b/baRSS.xcodeproj/project.pbxproj @@ -22,6 +22,7 @@ 544F5A752E30EFC700674F81 /* style.css in Resources */ = {isa = PBXBuildFile; fileRef = 544F5A722E30EFC700674F81 /* style.css */; }; 544F5A762E30EFC700674F81 /* opml-lib.m in Sources */ = {isa = PBXBuildFile; fileRef = 544F5A702E30EFC700674F81 /* opml-lib.m */; }; 54501010230E9C8600F0B165 /* FeedDownload.m in Sources */ = {isa = PBXBuildFile; fileRef = 5450100F230E9C8600F0B165 /* FeedDownload.m */; }; + 545EB5DA2EE8622200FABBE0 /* StrictUIntFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = 545EB5D92EE8622200FABBE0 /* StrictUIntFormatter.m */; }; 5469E13C2EA90C6C00D46CE7 /* NotifyEndpoint.m in Sources */ = {isa = PBXBuildFile; fileRef = 5469E13B2EA90C6C00D46CE7 /* NotifyEndpoint.m */; }; 546A6A2922C583390034E806 /* SettingsGeneralView.m in Sources */ = {isa = PBXBuildFile; fileRef = 54D857D122802309001BA1C8 /* SettingsGeneralView.m */; }; 546A6A2C22C584AF0034E806 /* SettingsAppearanceView.m in Sources */ = {isa = PBXBuildFile; fileRef = 546A6A2A22C584AF0034E806 /* SettingsAppearanceView.m */; }; @@ -150,6 +151,8 @@ 544F5A722E30EFC700674F81 /* style.css */ = {isa = PBXFileReference; lastKnownFileType = text.css; path = style.css; sourceTree = ""; }; 5450100E230E9C8600F0B165 /* FeedDownload.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FeedDownload.h; sourceTree = ""; }; 5450100F230E9C8600F0B165 /* FeedDownload.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FeedDownload.m; sourceTree = ""; }; + 545EB5D62EE8620300FABBE0 /* StrictUIntFormatter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = StrictUIntFormatter.h; sourceTree = ""; }; + 545EB5D92EE8622200FABBE0 /* StrictUIntFormatter.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = StrictUIntFormatter.m; sourceTree = ""; }; 5469E13A2EA90C6C00D46CE7 /* NotifyEndpoint.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = NotifyEndpoint.h; sourceTree = ""; }; 5469E13B2EA90C6C00D46CE7 /* NotifyEndpoint.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = NotifyEndpoint.m; sourceTree = ""; }; 546A6A2A22C584AF0034E806 /* SettingsAppearanceView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SettingsAppearanceView.m; sourceTree = ""; }; @@ -515,6 +518,8 @@ 54910066233A4D4000858AE2 /* URLScheme.m */, 54229F532E02491A0019ACB0 /* TinySVG.h */, 54229F542E02491A0019ACB0 /* TinySVG.m */, + 545EB5D62EE8620300FABBE0 /* StrictUIntFormatter.h */, + 545EB5D92EE8622200FABBE0 /* StrictUIntFormatter.m */, ); path = Helper; sourceTree = ""; @@ -732,6 +737,7 @@ 546FC43D21188AD5007CC3A3 /* SettingsFeeds.m in Sources */, 54253C952C49BFE400742695 /* RegexConverterView.m in Sources */, 548C6D0A230C33DE003A1AAF /* NSURL+Ext.m in Sources */, + 545EB5DA2EE8622200FABBE0 /* StrictUIntFormatter.m in Sources */, 54E88320211B509D00064188 /* ModalFeedEdit.m in Sources */, 54195883218A061100581B79 /* Feed+Ext.m in Sources */, 5469E13C2EA90C6C00D46CE7 /* NotifyEndpoint.m in Sources */, diff --git a/baRSS/Helper/StrictUIntFormatter.h b/baRSS/Helper/StrictUIntFormatter.h new file mode 100644 index 0000000..49e1bd6 --- /dev/null +++ b/baRSS/Helper/StrictUIntFormatter.h @@ -0,0 +1,4 @@ +@import Cocoa; + +@interface StrictUIntFormatter : NSFormatter +@end diff --git a/baRSS/Helper/StrictUIntFormatter.m b/baRSS/Helper/StrictUIntFormatter.m new file mode 100644 index 0000000..7e81a10 --- /dev/null +++ b/baRSS/Helper/StrictUIntFormatter.m @@ -0,0 +1,23 @@ +#import "StrictUIntFormatter.h" + +@implementation StrictUIntFormatter +/// Display object as integer formatted string. +- (NSString *)stringForObjectValue:(id)obj { + return [NSString stringWithFormat:@"%d", [[NSString stringWithFormat:@"%@", obj] intValue]]; +} +/// Parse any pasted input as integer. +- (BOOL)getObjectValue:(out id _Nullable __autoreleasing *)obj forString:(NSString *)string errorDescription:(out NSString *__autoreleasing _Nullable *)error { + *obj = [[NSNumber numberWithInt:[string intValue]] stringValue]; + return YES; +} +/// Only digits, no other character allowed +- (BOOL)isPartialStringValid:(NSString *__autoreleasing _Nonnull *)partialStringPtr proposedSelectedRange:(NSRangePointer)proposedSelRangePtr originalString:(NSString *)origString originalSelectedRange:(NSRange)origSelRange errorDescription:(NSString *__autoreleasing _Nullable *)error { + for (NSUInteger i = 0; i < [*partialStringPtr length]; i++) { + unichar c = [*partialStringPtr characterAtIndex:i]; + if (c < '0' || c > '9') + return NO; + } + return YES; +} +@end + diff --git a/baRSS/NSCategories/NSView+Ext.h b/baRSS/NSCategories/NSView+Ext.h index f2bef49..b330268 100644 --- a/baRSS/NSCategories/NSView+Ext.h +++ b/baRSS/NSCategories/NSView+Ext.h @@ -36,6 +36,7 @@ static inline CGFloat NSMaxWidth(NSView *a, NSView *b) { return Max(NSWidth(a.fr // UI: TextFields + (NSTextField*)label:(NSString*)text; + (NSTextField*)inputField:(NSString*)placeholder width:(CGFloat)w; ++ (NSTextField*)integerField:(NSUInteger)placeholder width:(CGFloat)w; + (NSView*)labelColumn:(NSArray*)labels rowHeight:(CGFloat)h padding:(CGFloat)pad; // UI: Buttons + (NSButton*)button:(NSString*)text; diff --git a/baRSS/NSCategories/NSView+Ext.m b/baRSS/NSCategories/NSView+Ext.m index 70e3bb9..32a9f09 100644 --- a/baRSS/NSCategories/NSView+Ext.m +++ b/baRSS/NSCategories/NSView+Ext.m @@ -1,4 +1,5 @@ #import "NSView+Ext.h" +#import "StrictUIntFormatter.h" @implementation NSView (Ext) @@ -27,6 +28,13 @@ return input; } +/// Create input text field which only accepts integer values. (calls `inputField`) `21px` height. ++ (NSTextField*)integerField:(NSUInteger)placeholder width:(CGFloat)w { + NSTextField *input = [self inputField:[NSString stringWithFormat:@"%ld", placeholder] width:w]; + input.formatter = [StrictUIntFormatter new]; + return input; +} + /// Create view with @c NSTextField subviews with right-aligned and row-centered text from @c labels. + (NSView*)labelColumn:(NSArray*)labels rowHeight:(CGFloat)h padding:(CGFloat)pad { CGFloat w = 0, y = 0; diff --git a/baRSS/Preferences/Feeds Tab/ModalFeedEditView.m b/baRSS/Preferences/Feeds Tab/ModalFeedEditView.m index 4732fe2..f9b199d 100644 --- a/baRSS/Preferences/Feeds Tab/ModalFeedEditView.m +++ b/baRSS/Preferences/Feeds Tab/ModalFeedEditView.m @@ -3,8 +3,6 @@ #import "NSView+Ext.h" #import "Constants.h" -@interface StrictUIntFormatter : NSFormatter -@end @implementation ModalFeedEditView @@ -34,7 +32,7 @@ self.name = [[[NSView inputField:NSLocalizedString(@"Example Title", nil) width:0] placeIn:self x:x yTop:rowHeight] sizeToRight:PAD_S + 18]; self.spinnerName = [[NSView activitySpinner] placeIn:self xRight:1 yTop:rowHeight + 2.5]; // 3. row - self.refreshNum = [[NSView inputField:@"30" width:85] placeIn:self x:x yTop:2*rowHeight]; + self.refreshNum = [[NSView integerField:30 width:85] placeIn:self x:x yTop:2*rowHeight]; self.refreshUnit = [[NSView popupButton:120] placeIn:self x:NSMaxX(self.refreshNum.frame) + PAD_M yTop:2*rowHeight]; self.regexConverterButton = [[[[NSView buttonIcon:RSSImageRegexIcon size:19] action:@selector(openRegexConverter) target:controller] @@ -48,7 +46,6 @@ self.url.delegate = controller; self.warningButton.hidden = YES; self.regexConverterButton.hidden = YES; - self.refreshNum.formatter = [StrictUIntFormatter new]; // see below ... [self prepareWarningPopover]; return self; } @@ -67,29 +64,3 @@ } @end - - -#pragma mark - StrictUIntFormatter - - - -@implementation StrictUIntFormatter -/// Display object as integer formatted string. -- (NSString *)stringForObjectValue:(id)obj { - return [NSString stringWithFormat:@"%d", [[NSString stringWithFormat:@"%@", obj] intValue]]; -} -/// Parse any pasted input as integer. -- (BOOL)getObjectValue:(out id _Nullable __autoreleasing *)obj forString:(NSString *)string errorDescription:(out NSString *__autoreleasing _Nullable *)error { - *obj = [[NSNumber numberWithInt:[string intValue]] stringValue]; - return YES; -} -/// Only digits, no other character allowed -- (BOOL)isPartialStringValid:(NSString *__autoreleasing _Nonnull *)partialStringPtr proposedSelectedRange:(NSRangePointer)proposedSelRangePtr originalString:(NSString *)origString originalSelectedRange:(NSRange)origSelRange errorDescription:(NSString *__autoreleasing _Nullable *)error { - for (NSUInteger i = 0; i < [*partialStringPtr length]; i++) { - unichar c = [*partialStringPtr characterAtIndex:i]; - if (c < '0' || c > '9') - return NO; - } - return YES; -} -@end -