diff --git a/ChangeLog b/ChangeLog index 5bcf430c..33b2b84c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,20 @@ +2001-12-04 Laurent Julliard + + * Palettes/4Data/main.m: Date and Number Formatters added + * Palettes/4Data/inspectors.m: Date and Number Formatters added + * Palettes/4Data/GNUmakefile: Date and Number Formatters added + * GormWindowEditor.m: drag and drop logic for formatters + * IBPAlette.m: drag and drop logic for formatters + * GormPrivate.h: NSDateFormatter and NSNumberFormatter additions + * GormPalettesManager.m: drag and drop logic for formatters + * GormInspectorsManager.m: new (optional) popup button item for + formatters + * Gorm.h: new drag and drop type for formatters + * Palettes/4Data/GormDateFormatterInspector.gorm: New Date + Formatter Inspector + * Palettes/4Data/GormDateFormatterInspector.gorm: New Number + Formatter Inspector + 2001-11-20 Laurent Julliard * GNUMakefile: data palette and new icons added diff --git a/Palettes/4Data/GNUmakefile b/Palettes/4Data/GNUmakefile index 21619b91..20b1989c 100644 --- a/Palettes/4Data/GNUmakefile +++ b/Palettes/4Data/GNUmakefile @@ -30,7 +30,9 @@ PALETTE_NAME = 4Data 4Data_RESOURCE_FILES = DataPalette.tiff \ GormImageViewInspector.gorm \ GormTextViewInspector.gorm \ - GormComboBoxInspector.gorm + GormComboBoxInspector.gorm \ + GormDateFormatterInspector.gorm \ + GormNumberFormatterInspector.gorm -include GNUmakefile.preamble diff --git a/Palettes/4Data/inspectors.m b/Palettes/4Data/inspectors.m index 0a669327..9ababa55 100644 --- a/Palettes/4Data/inspectors.m +++ b/Palettes/4Data/inspectors.m @@ -29,6 +29,8 @@ #define VSTR(str) ({id _str = str; (_str) ? _str : @"";}) +extern NSArray *predefinedDateFormats, *predefinedNumberFormats; + /*---------------------------------------------------------------------------- * NSComboBox */ @@ -381,3 +383,570 @@ } @end + + +/*------------------------------------------------------------------ + * NSDateFormatter + * + * Rk: The Inspector object is also the table view delegate and data source + *-----------------------------------------------------------------*/ + +@implementation NSDateFormatter (IBInspectorClassNames) + +- (NSString*) inspectorClassName +{ + return @"GormDateFormatterAttributesInspector"; +} + +@end + +@interface GormDateFormatterAttributesInspector : IBInspector +{ + NSTableView *formatTable; + id formatField; + id languageSwitch; + id detachButton; +} +@end + +@implementation GormDateFormatterAttributesInspector + +- (void) _setValuesFromControl: control +{ + BOOL allowslanguage; + NSString *dateFmt; + NSDateFormatter *fmtr; + + if (control == detachButton) + { + [[object cell] setFormatter: nil]; + // FIXME: Should empty the inspector window or show + // the default inspector. How do we do that? + //[ (GormInspectorManager *)[window view] setCurrentInspector: 0] ?? + } + else + { + NSCell *cell = [object cell]; + + if (control == formatTable) + { + int row; + + if ((row = [control selectedRow]) != -1) + { + dateFmt = [NSDateFormatter formatAtIndex: row]; + } + + [formatField setStringValue: VSTR(dateFmt) ]; + } + else if (control == formatField) + { + int idx; + + dateFmt = [control stringValue]; + + // If the string typed is a predefined one then highligh it in + // table dateFormat table view above + if ( (idx = [NSDateFormatter indexOfFormat: dateFmt]) == NSNotFound) + { + [formatTable deselectAll:self]; + } + else + { + [formatTable selectRow:idx byExtendingSelection:NO]; + } + + } + else if (control == languageSwitch) + { + allowslanguage = ([control state] == NSOnState); + } + + // Update the Formatter and refresh the Cell value + fmtr = [[NSDateFormatter alloc] initWithDateFormat:dateFmt + allowNaturalLanguage:allowslanguage]; + [cell setFormatter:fmtr]; + RELEASE(fmtr); + + [cell setObjectValue: [cell objectValue]]; + + } + +} + +- (void) _getValuesFromObject: (id) anObject +{ + int idx; + NSDateFormatter *fmtr = [[anObject cell] formatter]; + + if (anObject != object) + { + return; + } + + + // If the string typed is a predefined one then highligh it in + // table dateFormat table view above + if ( (idx = [NSDateFormatter indexOfFormat: [fmtr dateFormat]]) == NSNotFound) + { + [formatTable deselectAll:self]; + } + else + { + [formatTable selectRow:idx byExtendingSelection:NO]; + } + [formatField setStringValue: VSTR([fmtr dateFormat]) ]; + [languageSwitch setState: [fmtr allowsNaturalLanguage]]; +} + +- (void) dealloc +{ + RELEASE(window); + [super dealloc]; +} + +- (id) init +{ + + if ([super init] == nil) + { + return nil; + } + if ([NSBundle loadNibNamed: @"GormDateFormatterInspector" owner: self] == NO) + { + NSLog(@"Could not gorm GormDateFormatterInspector"); + return nil; + } + + // Add format/date table view by hand for now... + { + NSScrollView *v; + NSTableColumn *tc; + NSSize contentSize; + + v = [[NSScrollView alloc] initWithFrame: NSMakeRect(5,170,IVW-10,200)]; + [v setHasVerticalScroller: YES]; + [v setHasHorizontalScroller: NO]; + contentSize = [v contentSize]; + + formatTable = [[NSTableView alloc] initWithFrame: + NSMakeRect(0,0,contentSize.width, contentSize.height)]; + + [formatTable setDataSource: self]; + [formatTable setDelegate: self]; + [formatTable setAutoresizesAllColumnsToFit: YES]; + [formatTable setAllowsEmptySelection: YES]; + [formatTable setAllowsMultipleSelection: NO]; + [v setDocumentView: formatTable]; + + tc = [[NSTableColumn alloc] initWithIdentifier: @"format"]; + [[tc headerCell] setStringValue: @"Format"]; + [tc setWidth: contentSize.width*4/9]; + [tc setResizable: NO]; + [tc setEditable: NO]; + [formatTable addTableColumn: tc]; + RELEASE(tc); + + tc = [[NSTableColumn alloc] initWithIdentifier: @"date"]; + [[tc headerCell] setStringValue: @"Date"]; + [tc setMinWidth: contentSize.width*5/9]; + [tc setResizable: NO]; + [tc setEditable: NO]; + [formatTable addTableColumn: tc]; + RELEASE(tc); + + [v setDocumentView: formatTable]; + [[window contentView] addSubview: v]; + RELEASE(v); + } + + return self; +} + + +- (void) ok: (id)sender +{ + [self _setValuesFromControl: sender]; +} + +- (void) setObject: (id)anObject +{ + NSDebugLog(@"Formatting object: %@", anObject); + [super setObject: anObject]; + [self _getValuesFromObject: anObject]; +} + +/* NSDateFormatter inspector: table view delegate and data source */ + +- (int)numberOfRowsInTableView:(NSTableView *)aTableView +{ + return [NSDateFormatter formatCount]; +} + +- (id)tableView:(NSTableView *)aTableView + objectValueForTableColumn:(NSTableColumn *)aTableColumn + row:(int)rowIndex +{ + NSString *fmt = [NSDateFormatter formatAtIndex:rowIndex]; + + if ( [[aTableColumn identifier] isEqualToString: @"format"] ) + { + return fmt; + } + else if ( [[aTableColumn identifier] isEqualToString: @"date"] ) + { + return [[NSDateFormatter defaultFormatValue] + descriptionWithCalendarFormat:fmt ]; + } + else + { + // Huuh?? Only 2 columns + NSLog(@"Date table view only doesn't known column identifier: %@", [aTableColumn identifier]); + } + + return nil; + +} + +- (void)tableViewSelectionDidChange:(NSNotification *)aNotification +{ + [self _setValuesFromControl: formatTable]; +} + +@end + + +/*------------------------------------------------------------------ + * NSNumberFormatter + * + * Rk: The Inspector object is also the table view delegate and data source + *-----------------------------------------------------------------*/ + +@implementation NSNumberFormatter (IBInspectorClassNames) + +- (NSString*) inspectorClassName +{ + return @"GormNumberFormatterAttributesInspector"; +} + +@end + +@interface GormNumberFormatterAttributesInspector : IBInspector +{ + id addThousandSeparatorSwitch; + id commaPointSwitch; + id formatForm; + id formatTable; + id localizeSwitch; + id negativeField; + id negativeRedSwitch; + id positiveField; + id detachButton; +} +@end + +@implementation GormNumberFormatterAttributesInspector + +- (void) updateAppearanceFieldsWithFormat: (NSString *)format; +{ + + [[[positiveField cell] formatter] setFormat: format]; + [[positiveField cell] setObjectValue: + [NSDecimalNumber decimalNumberWithString: @"123456.789"]]; + + [[[negativeField cell] formatter] setFormat: format]; + [[negativeField cell] setObjectValue: + [NSDecimalNumber decimalNumberWithString: @"-123456.789"]]; +} + + +- (void) _setValuesFromControl: control +{ + NSString *positiveFmt, *negativeFmt, *zeroFmt, *fullFmt; + NSString *minValue, *maxValue; + NSCell *cell = [object cell]; + NSNumberFormatter *fmtr = [cell formatter]; + + if (control == detachButton) + { + [cell setFormatter: nil]; + // FIXME: Should empty the inspector window or show + // the default inspector. How do we do that? + //[ (GormInspectorManager *)[window view] setCurrentInspector: 0] ?? + } + else + { + + if (control == formatTable) + { + int row; + + if ((row = [control selectedRow]) != -1) + { + positiveFmt = [NSNumberFormatter positiveFormatAtIndex:row]; + zeroFmt = [NSNumberFormatter zeroFormatAtIndex:row]; + negativeFmt = [NSNumberFormatter negativeFormatAtIndex:row]; + fullFmt = [NSNumberFormatter formatAtIndex:row]; + } + + // Update Appearance samples + [self updateAppearanceFieldsWithFormat: fullFmt]; + + // Update editable format fields + [[formatForm cellAtIndex:0] setStringValue: VSTR(positiveFmt)]; + [[formatForm cellAtIndex:1] setStringValue: VSTR(zeroFmt)]; + [[formatForm cellAtIndex:2] setStringValue: VSTR(negativeFmt)]; + + [fmtr setFormat:fullFmt]; + + } + + else if (control == formatForm) + { + int idx; + + positiveFmt = [[control cellAtIndex:0] stringValue]; + zeroFmt = [[control cellAtIndex:1] stringValue]; + negativeFmt = [[control cellAtIndex:2] stringValue]; + minValue = [[control cellAtIndex:3] stringValue]; + maxValue = [[control cellAtIndex:4] stringValue]; + NSDebugLog(@"min,max: %@, %@", minValue, maxValue); + + fullFmt = [NSString stringWithFormat:@"%@;%@;%@", + positiveFmt, zeroFmt, negativeFmt]; + + // If the 3 formats correspond to a predefined set then highlight it in + // number Format table view above + if ( (idx = [NSNumberFormatter indexOfFormat: fullFmt]) == NSNotFound) + { + [formatTable deselectAll:self]; + } + else + { + [formatTable selectRow:idx byExtendingSelection:NO]; + NSDebugLog(@"format found at index: %d", idx); + } + + // Update Appearance samples + [self updateAppearanceFieldsWithFormat: fullFmt]; + + [fmtr setFormat: fullFmt]; + + if (minValue != nil) + [fmtr setMinimum: [NSDecimalNumber decimalNumberWithString: minValue]]; + if (maxValue != nil) + [fmtr setMaximum: [NSDecimalNumber decimalNumberWithString: maxValue]]; + + + } + else if (control == localizeSwitch) + { + [fmtr setLocalizesFormat:([control state] == NSOnState)]; + } + else if (control == negativeRedSwitch) + { + NSMutableDictionary *newAttrs = [NSMutableDictionary dictionary]; + + [newAttrs setObject:[NSColor redColor] forKey:@"NSColor"]; + [fmtr setTextAttributesForNegativeValues:newAttrs]; + } + else if (control == addThousandSeparatorSwitch) + { + [fmtr setHasThousandSeparators:([control state] == NSOnState)]; + } + else if (control == commaPointSwitch) + { + [fmtr setDecimalSeparator:([control state] == NSOnState) ? @"," : @"."]; + } + + // FIXME: Force cell refresh with the new formatter. Really useful ? + //[cell setObjectValue: [cell objectValue]]; + + } + +} + +- (void) _getValuesFromObject: (id) anObject +{ + int idx; + NSNumberFormatter *fmtr = [[anObject cell] formatter]; + + + if (anObject != object) + { + return; + } + + // Format form + NSDebugLog(@"format from object: %@", [fmtr format]); + [[formatForm cellAtIndex:0] setStringValue: [fmtr positiveFormat]]; + [[formatForm cellAtIndex:1] setStringValue: [fmtr zeroFormat]]; + [[formatForm cellAtIndex:2] setStringValue: [fmtr negativeFormat]]; + [[formatForm cellAtIndex:3] setObjectValue: [fmtr minimum]]; + [[formatForm cellAtIndex:4] setObjectValue: [fmtr maximum]]; + + // If the string typed is a predefined one then highligh it in + // Number Format table view above + if ( (idx = [NSNumberFormatter indexOfFormat: [fmtr format]]) == NSNotFound) + { + [formatTable deselectAll:self]; + } + else + { + [formatTable selectRow:idx byExtendingSelection:NO]; + } + + // Option switches + [localizeSwitch setState: ([fmtr localizesFormat] == YES) ? NSOnState : NSOffState]; + + [addThousandSeparatorSwitch setState: ([fmtr hasThousandSeparators] == YES) ? NSOnState : NSOffState]; + + if ([[fmtr decimalSeparator] isEqualToString: @","] ) + [commaPointSwitch setState: NSOnState]; + else + [commaPointSwitch setState: NSOffState]; + + if ( [[[fmtr textAttributesForNegativeValues] objectForKey: @"NSColor"] isEqual: [NSColor redColor] ] ) + [negativeRedSwitch setState: NSOnState]; + else + [negativeRedSwitch setState: NSOffState]; + +} + +- (void) dealloc +{ + RELEASE(window); + [super dealloc]; +} + +- (id) init +{ + + if ([super init] == nil) + { + return nil; + } + if ([NSBundle loadNibNamed: @"GormNumberFormatterInspector" owner: self] == NO) + { + NSLog(@"Could not gorm GormNumberFormatterInspector"); + return nil; + } + + // Add positive/negative format table view by hand for now... + { + NSScrollView *v; + NSTableColumn *tc; + NSSize contentSize; + + v = [[NSScrollView alloc] initWithFrame: NSMakeRect(12,268,245,118)]; + [v setHasVerticalScroller: YES]; + [v setHasHorizontalScroller: NO]; + contentSize = [v contentSize]; + + formatTable = [[NSTableView alloc] initWithFrame: + NSMakeRect(0,0,contentSize.width, contentSize.height)]; + + [formatTable setDataSource: self]; + [formatTable setDelegate: self]; + [formatTable setAutoresizesAllColumnsToFit: YES]; + [formatTable setAllowsEmptySelection: YES]; + [formatTable setAllowsMultipleSelection: NO]; + + tc = [[NSTableColumn alloc] initWithIdentifier: @"positive"]; + [[tc headerCell] setStringValue: @"Positive"]; + [tc setWidth: contentSize.width/2]; + [tc setResizable: NO]; + [tc setEditable: NO]; + [formatTable addTableColumn: tc]; + RELEASE(tc); + + tc = [[NSTableColumn alloc] initWithIdentifier: @"negative"]; + [[tc headerCell] setStringValue: @"Negative"]; + [tc setMinWidth: contentSize.width/2]; + [tc setResizable: NO]; + [tc setEditable: NO]; + [formatTable addTableColumn: tc]; + RELEASE(tc); + + [v setDocumentView: formatTable]; + [[window contentView] addSubview: v]; + RELEASE(v); + } + + // Initialize Positive/Negative appearance fields formatter + { + NSNumberFormatter *fmtr = [[NSNumberFormatter alloc] init]; + [fmtr setFormat: [NSNumberFormatter defaultFormat]]; + [[positiveField cell] setFormatter: fmtr]; + [[negativeField cell] setFormatter: fmtr]; + } + + + + return self; +} + + +- (void) ok: (id)sender +{ + [self _setValuesFromControl: sender]; +} + +- (void) setObject: (id)anObject +{ + NSDebugLog(@"Formatting object: %@", anObject); + [super setObject: anObject]; + [self _getValuesFromObject: anObject]; +} + +/* Positive/Negative Format table data source */ + +- (int)numberOfRowsInTableView:(NSTableView *)aTableView +{ + return [NSNumberFormatter formatCount]; +} + +- (id)tableView:(NSTableView *)aTableView + objectValueForTableColumn:(NSTableColumn *)aTableColumn + row:(int)rowIndex +{ + if ( [[aTableColumn identifier] isEqualToString: @"positive"] ) + { + return [NSNumberFormatter positiveValueAtIndex:rowIndex]; + } + else if ( [[aTableColumn identifier] isEqualToString: @"negative"] ) + { + return [NSNumberFormatter negativeValueAtIndex:rowIndex]; + } + else + { + // Huuh?? Only 2 columns + NSLog(@"Number table view doesn't known column identifier: %@", [aTableColumn identifier]); + } + + return nil; + +} + +/* Positive/Negative Format table Delegate */ + +- (void)tableViewSelectionDidChange:(NSNotification *)aNotification +{ + // When a row is selected update the rest of the inspector accordingly + [self _setValuesFromControl: formatTable]; +} + +- (void)tableView:(NSTableView *)aTableView willDisplayCell:(id)aCell + forTableColumn:(NSTableColumn*)aTableColumn row:(int)rowIndex +{ + NSNumberFormatter *fmtr; + + // Adjust the cell formatter before it is displayed + fmtr = [[NSNumberFormatter alloc] init]; + [fmtr setFormat: [NSNumberFormatter formatAtIndex:rowIndex]]; + [aCell setFormatter: fmtr]; + //RELEASE(fmtr); + +} + +@end diff --git a/Palettes/4Data/main.m b/Palettes/4Data/main.m index 6702bbee..4d0c3d70 100644 --- a/Palettes/4Data/main.m +++ b/Palettes/4Data/main.m @@ -24,7 +24,163 @@ #include #include #include "../../Gorm.h" +#include "../../GormPrivate.h" + +/* ----------------------------------------------------------- + * Some additions to the NSNumberFormatter Class specific to Gorm + * -----------------------------------------------------------*/ +NSArray *predefinedNumberFormats; +int defaultNumberFormatIndex = 0; + +@implementation NSNumberFormatter (GormAdditions) + ++ (void) initialize +{ + predefinedNumberFormats = [NSArray arrayWithObjects: + [NSArray arrayWithObjects: @"$#,##0.00;0.00;-$#,##0.00",@"9999.99",@"-9999.99",nil], + [NSArray arrayWithObjects: @"$#,##0.00;0.00;[Red]($#,##0.00)",@"9999.99",@"-9999.99",nil], + [NSArray arrayWithObjects: @"0.00;0.00;-0.00",@"9999.99",@"-9999.99",nil], + [NSArray arrayWithObjects: @"0;0;-0",@"100",@"-100",nil], + [NSArray arrayWithObjects: @"00000;00000;-00000",@"100",@"-100",nil], + [NSArray arrayWithObjects: @"0%;0%;-0%",@"100",@"-100",nil], + [NSArray arrayWithObjects: @"0.00%;0.00%;-0.00%",@"99.99",@"-99.99",nil], + nil]; +} + + ++ (int) formatCount +{ + return [predefinedNumberFormats count]; +} + ++ (NSString *) formatAtIndex: (int)i +{ + return [[predefinedNumberFormats objectAtIndex:i] objectAtIndex:0]; +} + ++ (NSString *) positiveFormatAtIndex: (int)i +{ + NSString *fmt =[[predefinedNumberFormats objectAtIndex:i] objectAtIndex:0]; + + return [ [fmt componentsSeparatedByString:@";"] objectAtIndex:0]; +} + ++ (NSString *) zeroFormatAtIndex: (int)i +{ + NSString *fmt =[[predefinedNumberFormats objectAtIndex:i] objectAtIndex:0]; + + return [ [fmt componentsSeparatedByString:@";"] objectAtIndex:1]; +} + ++ (NSString *) negativeFormatAtIndex: (int)i +{ + NSString *fmt =[[predefinedNumberFormats objectAtIndex:i] objectAtIndex:0]; + + return [ [fmt componentsSeparatedByString:@";"] objectAtIndex:2]; +} + ++ (NSDecimalNumber *) positiveValueAtIndex: (int)i +{ + return [NSDecimalNumber decimalNumberWithString: + [[predefinedNumberFormats objectAtIndex:i] objectAtIndex:1] ]; +} + ++ (NSDecimalNumber *) negativeValueAtIndex: (int)i +{ + return [NSDecimalNumber decimalNumberWithString: + [[predefinedNumberFormats objectAtIndex:i] objectAtIndex:2] ]; +} + ++ (int) indexOfFormat: (NSString *) format +{ + int i; + NSString *fmt; + int count = [predefinedNumberFormats count]; + + for (i=0;i