diff --git a/Source/NSAttributedString.m b/Source/NSAttributedString.m index cfca61f55..df8955b38 100644 --- a/Source/NSAttributedString.m +++ b/Source/NSAttributedString.m @@ -53,6 +53,7 @@ #import "AppKit/NSFont.h" #import "AppKit/NSFontDescriptor.h" #import "AppKit/NSFontManager.h" +#import "AppKit/NSTextList.h" // For the colour name spaces #import "AppKit/NSGraphics.h" #import "AppKit/NSTextTable.h" @@ -1095,20 +1096,43 @@ documentAttributes: (NSDictionary **)dict - (NSInteger) itemNumberInTextList: (NSTextList *)list atIndex: (NSUInteger)location { - NSParagraphStyle *style = [self attribute: NSParagraphStyleAttributeName - atIndex: location - effectiveRange: NULL]; - if (style != nil) + NSRange listRange = [self rangeOfTextList: list atIndex: location]; + if (listRange.location == NSNotFound) { - NSArray *textLists = [style textLists]; - - if (textLists != nil) - { - return [textLists indexOfObject: list]; - } + return 0; } - return NSNotFound; + NSRange subRange = NSMakeRange(listRange.location, location-listRange.location+1); + unichar buffer[subRange.length]; + + [[self string] getCharacters: buffer range: subRange]; + + NSCharacterSet *newlineCharacterSet = [NSCharacterSet newlineCharacterSet]; + + NSUInteger itemNumber = 1; + NSUInteger index; + for (index=1; index 0) && style && textLists) + while (effRange.location > 0) { style = [self attribute: NSParagraphStyleAttributeName atIndex: effRange.location - 1 @@ -1196,11 +1220,13 @@ documentAttributes: (NSDictionary **)dict { effRange.location = newEffRange.location; effRange.length += newEffRange.length; + continue; } } + break; } - while (NSMaxRange(effRange) < len && style && textLists) + while (NSMaxRange(effRange) < len) { style = [self attribute: NSParagraphStyleAttributeName atIndex: NSMaxRange(effRange) @@ -1212,8 +1238,10 @@ documentAttributes: (NSDictionary **)dict if ((textLists != nil) && [textLists containsObject: list]) { effRange.length += newEffRange.length; + continue; } } + break; } return effRange; diff --git a/Source/NSParagraphStyle.m b/Source/NSParagraphStyle.m index 468b72c44..a3f00eefb 100644 --- a/Source/NSParagraphStyle.m +++ b/Source/NSParagraphStyle.m @@ -303,6 +303,8 @@ static NSParagraphStyle *defaultStyle = nil; [_tabStops addObject: tab]; RELEASE(tab); } + + ASSIGN(_textLists, [NSArray array]); } return self; } @@ -494,6 +496,9 @@ static NSParagraphStyle *defaultStyle = nil; [aCoder decodeValueOfObjCType: @encode(float) at: &_paragraphSpacing]; [aCoder decodeValueOfObjCType: @encode(float) at: &_tailIndent]; + // Text lists were not included for non-keyed encoding, use a default + ASSIGN(_textLists, [NSArray array]); + /* * Tab stops don't conform to NSCoding - so we do it the long way. */ @@ -621,7 +626,12 @@ static NSParagraphStyle *defaultStyle = nil; C(_headerLevel); #undef C - return [_tabStops isEqualToArray: other->_tabStops]; +#define C(x) if (![x isEqualToArray: other->x]) return NO; + C(_tabStops); + C(_textLists); +#undef C + + return YES; } - (NSUInteger) hash diff --git a/Source/NSTextList.m b/Source/NSTextList.m index 080735b61..70f3aac04 100644 --- a/Source/NSTextList.m +++ b/Source/NSTextList.m @@ -51,21 +51,6 @@ [super dealloc]; } -- (BOOL) isEqual: (id)anObject -{ - if (anObject == self) - { - return YES; - } - if (anObject == nil || [anObject isKindOfClass: [NSTextList class]] == NO) - { - return NO; - } - - return ([anObject listOptions] == _listOptions) - && [_markerFormat isEqualToString: [anObject markerFormat]]; -} - - (unsigned int) listOptions { return _listOptions; diff --git a/Tests/gui/NSAttributedString/NSAttributedString_itemNumberInTextList.m b/Tests/gui/NSAttributedString/NSAttributedString_itemNumberInTextList.m new file mode 100644 index 000000000..1043df6d4 --- /dev/null +++ b/Tests/gui/NSAttributedString/NSAttributedString_itemNumberInTextList.m @@ -0,0 +1,79 @@ +#include "Testing.h" + +#include +#include +#include +#include + +int main(int argc, char **argv) +{ + CREATE_AUTORELEASE_POOL(arp); + + START_SET("NSAttributedString itemNumberInTextList:atIndex: category method"); + + NSTextList *list1 = [[NSTextList alloc] initWithMarkerFormat:@"{decimal}" options:0]; + NSTextList *list2 = [[NSTextList alloc] initWithMarkerFormat:@"{box}" options:0]; + + NSMutableParagraphStyle *style1 = [[NSParagraphStyle defaultParagraphStyle] mutableCopy]; + NSMutableParagraphStyle *style2 = [[NSParagraphStyle defaultParagraphStyle] mutableCopy]; + + [style1 setTextLists: [NSArray arrayWithObject: list1]]; + [style2 setTextLists: [NSArray arrayWithObjects: list1, list2, nil]]; + + NSDictionary *attrs1 = [NSDictionary dictionaryWithObject: style1 + forKey: NSParagraphStyleAttributeName]; + NSDictionary *attrs2 = [NSDictionary dictionaryWithObject: style2 + forKey: NSParagraphStyleAttributeName]; + NSDictionary *attrs3 = [NSDictionary dictionaryWithObject: [NSParagraphStyle defaultParagraphStyle] + forKey: NSParagraphStyleAttributeName]; + + NSMutableAttributedString *storage = [[NSMutableAttributedString alloc] init]; + + NSUInteger index1 = [storage length]; + [storage appendAttributedString: + [[NSMutableAttributedString alloc] initWithString: @"item 1\r\n" attributes: attrs1]]; + + NSUInteger index2 = [storage length]; + [storage appendAttributedString: + [[NSMutableAttributedString alloc] initWithString: @"item 2\n" attributes: attrs1]]; + + NSUInteger index3 = [storage length]; + [storage appendAttributedString: + [[NSMutableAttributedString alloc] initWithString: @"item 3\n" attributes: attrs1]]; + + NSUInteger index4 = [storage length]; + [storage appendAttributedString: + [[NSMutableAttributedString alloc] initWithString: @"subitem 1\n" attributes: attrs2]]; + + NSUInteger index5 = [storage length]; + [storage appendAttributedString: + [[NSMutableAttributedString alloc] initWithString: @"subitem 2\n" attributes: attrs2]]; + + NSUInteger index6 = [storage length]; + [storage appendAttributedString: + [[NSMutableAttributedString alloc] initWithString: @"item 4\n" attributes: attrs1]]; + + NSUInteger index7 = [storage length]; + [storage appendAttributedString: + [[NSMutableAttributedString alloc] initWithString: @"extra text\n" attributes: attrs3]]; + + pass([storage itemNumberInTextList: list1 atIndex: index1] == 1, "Index for first list item"); + pass([storage itemNumberInTextList: list1 atIndex: index2] == 2, "Index with CR+LF sequence"); + pass([storage itemNumberInTextList: list1 atIndex: index3 - 1] == 2, "Index on boundary"); + pass([storage itemNumberInTextList: list1 atIndex: index3] == 3, "Index for third list item"); + pass([storage itemNumberInTextList: list1 atIndex: index4] == 3, "Index for third list item (sublist 1)"); + pass([storage itemNumberInTextList: list1 atIndex: index5] == 3, "Index for third list item (sublist 2"); + pass([storage itemNumberInTextList: list1 atIndex: index6] == 4, "Index for fourth list item"); + + pass([storage itemNumberInTextList: list2 atIndex: index4] == 1, "Index for first sublist item"); + pass([storage itemNumberInTextList: list2 atIndex: index5] == 2, "Index for second sublist item"); + + pass([storage itemNumberInTextList: list2 atIndex: index1] == 0, "Index in other list is zero"); + pass([storage itemNumberInTextList: list1 atIndex: index7] == 0, "Index in nonlist is zero"); + + END_SET("NSAttributedString itemNumberInTextList:atIndex: category method"); + + DESTROY(arp); + + return 0; +} diff --git a/Tests/gui/NSAttributedString/NSAttributedString_mergingAttributes.m b/Tests/gui/NSAttributedString/NSAttributedString_mergingAttributes.m new file mode 100644 index 000000000..e3b4adfd1 --- /dev/null +++ b/Tests/gui/NSAttributedString/NSAttributedString_mergingAttributes.m @@ -0,0 +1,73 @@ +#include "Testing.h" + +#include +#include +#include +#include + +int main(int argc, char **argv) +{ + CREATE_AUTORELEASE_POOL(arp); + + START_SET("NSAttributedString attribute merging"); + + NSMutableParagraphStyle *style1 = [[NSParagraphStyle defaultParagraphStyle] mutableCopy]; + NSMutableParagraphStyle *style2 = [[NSParagraphStyle defaultParagraphStyle] mutableCopy]; + NSMutableParagraphStyle *style3 = [[NSParagraphStyle defaultParagraphStyle] mutableCopy]; + NSMutableParagraphStyle *style4 = [[NSParagraphStyle defaultParagraphStyle] mutableCopy]; + + NSTextList *list1 = [[NSTextList alloc] initWithMarkerFormat: @"{box}" options: 0]; + NSTextList *list2 = [[NSTextList alloc] initWithMarkerFormat: @"{box}" options: 0]; + + [style3 setTextLists: [NSArray arrayWithObject: list1]]; + [style4 setTextLists: [NSArray arrayWithObject: list2]]; + + NSAttributedString *str1 = [[NSAttributedString alloc] + initWithString: @"string 1" + attributes: [NSDictionary dictionaryWithObject: style1 forKey: NSParagraphStyleAttributeName]]; + NSAttributedString *str2 = [[NSAttributedString alloc] + initWithString: @"string 2" + attributes: [NSDictionary dictionaryWithObject: style2 forKey: NSParagraphStyleAttributeName]]; + NSAttributedString *str3 = [[NSAttributedString alloc] + initWithString: @"string 3" + attributes: [NSDictionary dictionaryWithObject: style3 forKey: NSParagraphStyleAttributeName]]; + NSAttributedString *str4 = [[NSAttributedString alloc] + initWithString: @"string 4" + attributes: [NSDictionary dictionaryWithObject: style4 forKey: NSParagraphStyleAttributeName]]; + + NSMutableAttributedString *storage = [[NSMutableAttributedString alloc] init]; + + NSUInteger pos1 = [storage length]; + [storage appendAttributedString: str1]; + + NSUInteger pos2 = [storage length]; + [storage appendAttributedString: str2]; + + NSUInteger pos3 = [storage length]; + [storage appendAttributedString: str3]; + + NSUInteger pos4 = [storage length]; + [storage appendAttributedString: str4]; + + NSParagraphStyle *result1 = [storage attribute: NSParagraphStyleAttributeName + atIndex: pos1 + effectiveRange: NULL]; + NSParagraphStyle *result2 = [storage attribute: NSParagraphStyleAttributeName + atIndex: pos2 + effectiveRange: NULL]; + NSParagraphStyle *result3 = [storage attribute: NSParagraphStyleAttributeName + atIndex: pos3 + effectiveRange: NULL]; + NSParagraphStyle *result4 = [storage attribute: NSParagraphStyleAttributeName + atIndex: pos4 + effectiveRange: NULL]; + + pass(result1 == result2, "Did merge equal paragraph styles"); + pass(result3 != result4, "Did not merge equal paragraph styles with text lists"); + + END_SET("NSAttributedString attribute merging"); + + DESTROY(arp); + + return 0; +} diff --git a/Tests/gui/NSAttributedString/NSAttributedString_rangeOfTextList.m b/Tests/gui/NSAttributedString/NSAttributedString_rangeOfTextList.m new file mode 100644 index 000000000..62dfb0cf0 --- /dev/null +++ b/Tests/gui/NSAttributedString/NSAttributedString_rangeOfTextList.m @@ -0,0 +1,88 @@ +#include "Testing.h" + +#include +#include +#include +#include + +int main(int argc, char **argv) +{ + CREATE_AUTORELEASE_POOL(arp); + + START_SET("NSAttributedString rangeOfTextList:atIndex: category method"); + + NSTextList *list1 = [[NSTextList alloc] initWithMarkerFormat: @"{box}" options: 0]; + NSTextList *list2 = [[NSTextList alloc] initWithMarkerFormat: @"{box}" options: 0]; + NSTextList *list3 = [[NSTextList alloc] initWithMarkerFormat: @"{box}" options: 0]; + + NSMutableParagraphStyle *style1 = [[NSParagraphStyle defaultParagraphStyle] mutableCopy]; + NSMutableParagraphStyle *style2 = [[NSParagraphStyle defaultParagraphStyle] mutableCopy]; + NSMutableParagraphStyle *style3 = [[NSParagraphStyle defaultParagraphStyle] mutableCopy]; + NSMutableParagraphStyle *style4 = [[NSParagraphStyle defaultParagraphStyle] mutableCopy]; + + [style2 setTextLists: [NSArray arrayWithObject: list1]]; + [style3 setTextLists: [NSArray arrayWithObjects: list1, list2, nil]]; + [style4 setTextLists: [NSArray arrayWithObject: list3]]; + + NSMutableAttributedString *storage = [[NSMutableAttributedString alloc] init]; + + NSUInteger pos1 = [storage length]; + [storage appendAttributedString: [[NSAttributedString alloc] + initWithString: @"before\n" + attributes: [NSDictionary dictionaryWithObject: style1 forKey: NSParagraphStyleAttributeName]]]; + + NSUInteger pos2 = [storage length]; + [storage appendAttributedString: [[NSAttributedString alloc] + initWithString: @"list 1\n" + attributes: [NSDictionary dictionaryWithObject: style2 forKey: NSParagraphStyleAttributeName]]]; + + NSUInteger pos3 = [storage length]; + [storage appendAttributedString: [[NSAttributedString alloc] + initWithString: @"sublist 1\n" + attributes: [NSDictionary dictionaryWithObject: style3 forKey: NSParagraphStyleAttributeName]]]; + + NSUInteger pos4 = [storage length]; + [storage appendAttributedString: [[NSAttributedString alloc] + initWithString: @"list 1\n" + attributes: [NSDictionary dictionaryWithObject: style2 forKey: NSParagraphStyleAttributeName]]]; + + NSUInteger pos5 = [storage length]; + [storage appendAttributedString: [[NSAttributedString alloc] + initWithString: @"list 2\n" + attributes: [NSDictionary dictionaryWithObject: style4 forKey: NSParagraphStyleAttributeName]]]; + + NSUInteger pos6 = [storage length]; + [storage appendAttributedString: [[NSAttributedString alloc] + initWithString: @"ending\n" + attributes: [NSDictionary dictionaryWithObject: style1 forKey: NSParagraphStyleAttributeName]]]; + + NSRange expected, actual; + + expected = NSMakeRange(pos3, pos4 - pos3); + actual = [storage rangeOfTextList: list2 atIndex: pos3 + 1]; + pass(NSEqualRanges(expected, actual), "Found correct range of nested list"); + + expected = NSMakeRange(pos2, pos5 - pos2); + actual = [storage rangeOfTextList: list1 atIndex: pos3 + 1]; + pass(NSEqualRanges(expected, actual), "Found correct range of enclosing list"); + + expected = NSMakeRange(pos2, pos5 - pos2); + actual = [storage rangeOfTextList: list1 atIndex: pos2 + 1]; + pass(NSEqualRanges(expected, actual), "Found correct range including nested list"); + + expected = NSMakeRange(pos5, pos6 - pos5); + actual = [storage rangeOfTextList: list3 atIndex: pos5 + 1]; + pass(NSEqualRanges(expected, actual), "Found correct range of an adjacent list"); + + actual = [storage rangeOfTextList: list1 atIndex: pos5]; + pass(actual.location == NSNotFound, "Returned not found for location in different list"); + + actual = [storage rangeOfTextList: list1 atIndex: pos1]; + pass(actual.location == NSNotFound, "Returned not found for location not in any list"); + + END_SET("NSAttributedString rangeOfTextList:atIndex: category method"); + + DESTROY(arp); + + return 0; +} diff --git a/Tests/gui/NSAttributedString/TestInfo b/Tests/gui/NSAttributedString/TestInfo new file mode 100644 index 000000000..e69de29bb diff --git a/Tests/gui/NSParagraphStyle/NSParagraphStyle_equalityTesting.m b/Tests/gui/NSParagraphStyle/NSParagraphStyle_equalityTesting.m new file mode 100644 index 000000000..443dfa822 --- /dev/null +++ b/Tests/gui/NSParagraphStyle/NSParagraphStyle_equalityTesting.m @@ -0,0 +1,40 @@ +#include "Testing.h" + +#include +#include +#include + +int main(int argc, char **argv) +{ + CREATE_AUTORELEASE_POOL(arp); + + START_SET("NSParagraphStyle equality tests"); + + NSMutableParagraphStyle *default1 = [NSParagraphStyle defaultParagraphStyle]; + NSMutableParagraphStyle *default2 = [NSParagraphStyle defaultParagraphStyle]; + + PASS_EQUAL(default1, default2, "NSParagraphStyle isEqual: works for default paragraph styles"); + + NSMutableParagraphStyle *style1 = [[NSMutableParagraphStyle alloc] init]; + NSMutableParagraphStyle *style2 = [[NSMutableParagraphStyle alloc] init]; + + PASS_EQUAL(style1, style2, "NSParagraphStyle isEqual: works for default mutable copies"); + + NSTextList *textList = [[NSTextList alloc] init]; + + [style1 setTextLists: [NSArray arrayWithObject: textList]]; + [style2 setTextLists: [NSArray arrayWithObject: textList]]; + + PASS_EQUAL(style1, style2, "NSParagraphStyle isEqual: works for identical textlists"); + + [style1 setTextLists: [NSArray arrayWithObject: [[NSTextList alloc] init]]]; + [style2 setTextLists: [NSArray arrayWithObject: [[NSTextList alloc] init]]]; + + pass(![style1 isEqual: style2], "NSParagraphStyle isEqual: works for different textlists"); + + END_SET("NSParagraphStyle equality tests"); + + DESTROY(arp); + + return 0; +}