mirror of
https://github.com/gnustep/libs-gui.git
synced 2025-04-24 20:49:13 +00:00
New files for RTF output, code comes partly from Source/NSAttributedString
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/gui/trunk@6787 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
21e0c1e7b2
commit
368f544163
2 changed files with 723 additions and 0 deletions
49
Source/Parsers/RTFProducer.h
Normal file
49
Source/Parsers/RTFProducer.h
Normal file
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
RTFProducer.h
|
||||
|
||||
Writes out a NSAttributedString as RTF
|
||||
|
||||
Copyright (C) 2000 Free Software Foundation, Inc.
|
||||
|
||||
Author: Fred Kiefer <FredKiefer@gmx.de>
|
||||
Date: June 2000
|
||||
|
||||
This file is part of the GNUstep GUI Library.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with this library; see the file COPYING.LIB.
|
||||
If not, write to the Free Software Foundation,
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
#include <Foundation/Foundation.h>
|
||||
|
||||
@interface RTFProducer: NSObject
|
||||
{
|
||||
@public
|
||||
NSAttributedString *text;
|
||||
NSMutableDictionary *fontDict;
|
||||
NSMutableDictionary *colorDict;
|
||||
NSMutableDictionary *docDict;
|
||||
|
||||
NSColor *fgColor;
|
||||
NSColor *bgColor;
|
||||
NSFont *currentFont;
|
||||
/*
|
||||
NSMutableParagraphStyle *paragraph;
|
||||
*/
|
||||
}
|
||||
|
||||
+ (NSData*) RTFDFromAttributedString: (NSAttributedString*) aText
|
||||
documentAttributes: (NSDictionary*)dict;
|
||||
|
||||
@end
|
674
Source/Parsers/RTFProducer.m
Normal file
674
Source/Parsers/RTFProducer.m
Normal file
|
@ -0,0 +1,674 @@
|
|||
/*
|
||||
RTFProducer.m
|
||||
|
||||
Writes out a NSAttributedString as RTF
|
||||
|
||||
Copyright (C) 1999 Free Software Foundation, Inc.
|
||||
|
||||
Author: Daniel Bðhringer
|
||||
Date: November 1999
|
||||
Modifications: Fred Kiefer <FredKiefer@gmx.de>
|
||||
Date: June 2000
|
||||
|
||||
This file is part of the GNUstep GUI Library.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with this library; see the file COPYING.LIB.
|
||||
If not, write to the Free Software Foundation,
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
#include <Foundation/Foundation.h>
|
||||
#include <AppKit/AppKit.h>
|
||||
#include "RTFProducer.h"
|
||||
|
||||
// FIXME: Should be defined in a central place
|
||||
#define PAPERSIZE @"PaperSize"
|
||||
#define LEFTMARGIN @"LeftMargin"
|
||||
#define RIGHTMARGIN @"RightMargin"
|
||||
#define TOPMARGIN @"TopMargin"
|
||||
#define BUTTOMMARGIN @"ButtomMargin"
|
||||
|
||||
#define points2twips(a) ((a)*20.0)
|
||||
|
||||
@interface RTFProducer (Private)
|
||||
|
||||
- (NSString*) headerString;
|
||||
- (NSString*) trailerString;
|
||||
- (NSString*) bodyString;
|
||||
- (NSString*) RTFDStringFromAttributedString: (NSAttributedString*)aText
|
||||
documentAttributes: (NSDictionary*)dict;
|
||||
@end
|
||||
|
||||
@interface NSString (Replacing)
|
||||
- (NSString*) stringByReplacingEveryOccurrenceOfString: (NSString*)aString
|
||||
withString: (NSString*)other;
|
||||
@end
|
||||
|
||||
@implementation NSString (Replacing)
|
||||
|
||||
- (NSString*) stringByReplacingEveryOccurrenceOfString: (NSString*)aString
|
||||
withString: (NSString*)other
|
||||
{
|
||||
unsigned len = [self length];
|
||||
NSMutableString *erg = [NSMutableString string];
|
||||
NSRange currRange = [self rangeOfString: aString];
|
||||
unsigned prevLocation = 0;
|
||||
|
||||
while (currRange.length > 0)
|
||||
{
|
||||
if (currRange.location > 0)
|
||||
{
|
||||
NSRange r;
|
||||
|
||||
r = NSMakeRange(prevLocation, currRange.location - prevLocation);
|
||||
[erg appendString: [self substringWithRange: r]];
|
||||
}
|
||||
[erg appendString: other];
|
||||
currRange.location += currRange.length;
|
||||
currRange.length = len - currRange.location;
|
||||
prevLocation = currRange.location;
|
||||
currRange = [self rangeOfString: aString
|
||||
options: NSLiteralSearch
|
||||
range: currRange];
|
||||
}
|
||||
if (prevLocation < len)
|
||||
{
|
||||
NSRange r;
|
||||
|
||||
r = NSMakeRange(prevLocation, len - prevLocation);
|
||||
[erg appendString: [self substringWithRange: r]];
|
||||
}
|
||||
|
||||
return erg;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation RTFProducer
|
||||
|
||||
+ (NSData*) RTFDFromAttributedString: (NSAttributedString*) aText
|
||||
documentAttributes: (NSDictionary*)dict
|
||||
{
|
||||
RTFProducer *new = [self new];
|
||||
NSData *data = [[new RTFDStringFromAttributedString: aText
|
||||
documentAttributes: dict]
|
||||
dataUsingEncoding: NSISOLatin1StringEncoding];
|
||||
|
||||
RELEASE(new);
|
||||
return data;
|
||||
}
|
||||
|
||||
- (id)init
|
||||
{
|
||||
/*
|
||||
* maintain a dictionary for the used colours
|
||||
* (for rtf-header generation)
|
||||
*/
|
||||
colorDict = [NSMutableDictionary new];
|
||||
/*
|
||||
* maintain a dictionary for the used fonts
|
||||
* (for rtf-header generation)
|
||||
*/
|
||||
fontDict = [NSMutableDictionary new];
|
||||
|
||||
currentFont = nil;
|
||||
ASSIGN(fgColor, [NSColor textColor]);
|
||||
ASSIGN(bgColor, [NSColor textBackgroundColor]);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
RELEASE(text);
|
||||
RELEASE(fontDict);
|
||||
RELEASE(colorDict);
|
||||
RELEASE(docDict);
|
||||
|
||||
RELEASE(currentFont);
|
||||
RELEASE(fgColor);
|
||||
RELEASE(bgColor);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation RTFProducer (Private)
|
||||
|
||||
- (NSString*) fontTable
|
||||
{
|
||||
// write Font Table
|
||||
if ([fontDict count])
|
||||
{
|
||||
NSMutableString *fontlistString = [NSMutableString string];
|
||||
NSEnumerator *fontEnum;
|
||||
NSString *currFont;
|
||||
NSArray *keyArray;
|
||||
|
||||
keyArray = [fontDict allKeys];
|
||||
keyArray = [keyArray sortedArrayUsingSelector: @selector(compare:)];
|
||||
|
||||
fontEnum = [keyArray objectEnumerator];
|
||||
while ((currFont = [fontEnum nextObject]) != nil)
|
||||
{
|
||||
NSString *fontFamily;
|
||||
NSString *detail;
|
||||
|
||||
if ([currFont isEqualToString: @"Symbol"])
|
||||
fontFamily = @"tech";
|
||||
else if ([currFont isEqualToString: @"Helvetica"])
|
||||
fontFamily = @"swiss";
|
||||
else if ([currFont isEqualToString: @"Courier"])
|
||||
fontFamily = @"modern";
|
||||
else if ([currFont isEqualToString: @"Times"])
|
||||
fontFamily = @"roman";
|
||||
else
|
||||
fontFamily = @"nil";
|
||||
|
||||
detail = [NSString stringWithFormat: @"%@\\f%@ %@;",
|
||||
[fontDict objectForKey: currFont], fontFamily, currFont];
|
||||
[fontlistString appendString: detail];
|
||||
}
|
||||
return [NSString stringWithFormat: @"{\\fonttbl%@}\n", fontlistString];
|
||||
}
|
||||
else
|
||||
return @"";
|
||||
}
|
||||
|
||||
- (NSString*) colorTable
|
||||
{
|
||||
// write Colour table
|
||||
if ([colorDict count])
|
||||
{
|
||||
NSMutableString *result;
|
||||
unsigned int count = [colorDict count];
|
||||
NSMutableArray *list = [NSMutableArray arrayWithCapacity: count];
|
||||
NSEnumerator *keyEnum = [colorDict keyEnumerator];
|
||||
id next;
|
||||
int i;
|
||||
|
||||
while ((next = [keyEnum nextObject]) != nil)
|
||||
{
|
||||
NSNumber *cn = [colorDict objectForKey: next];
|
||||
[list insertObject: next atIndex: [cn intValue]-1];
|
||||
}
|
||||
|
||||
result = (NSMutableString*)[NSMutableString stringWithString: @"{\\colortbl;"];
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
NSColor *color = [[list objectAtIndex: i]
|
||||
colorUsingColorSpaceName: NSCalibratedRGBColorSpace];
|
||||
[result appendString: [NSString stringWithFormat:
|
||||
@"\\red%d\\green%d\\blue%d;",
|
||||
(int)([color redComponent]*255),
|
||||
(int)([color greenComponent]*255),
|
||||
(int)([color blueComponent]*255)]];
|
||||
}
|
||||
|
||||
[result appendString: @"}\n"];
|
||||
return result;
|
||||
}
|
||||
else
|
||||
return @"";
|
||||
}
|
||||
|
||||
- (NSString*) documentAttributes
|
||||
{
|
||||
if (docDict != nil)
|
||||
{
|
||||
NSMutableString *result;
|
||||
NSString *detail;
|
||||
NSValue *val;
|
||||
NSNumber *num;
|
||||
|
||||
result = (NSMutableString*)[NSMutableString string];
|
||||
|
||||
val = [docDict objectForKey: PAPERSIZE];
|
||||
if (val != nil)
|
||||
{
|
||||
NSSize size = [val sizeValue];
|
||||
detail = [NSString stringWithFormat: @"\\paperw%d \\paperh%d",
|
||||
(int)points2twips(size.width),
|
||||
(int)points2twips(size.height)];
|
||||
[result appendString: detail];
|
||||
}
|
||||
|
||||
num = [docDict objectForKey: LEFTMARGIN];
|
||||
if (num != nil)
|
||||
{
|
||||
float f = [num floatValue];
|
||||
detail = [NSString stringWithFormat: @"\\margl%d",
|
||||
(int)points2twips(f)];
|
||||
[result appendString: detail];
|
||||
}
|
||||
num = [docDict objectForKey: RIGHTMARGIN];
|
||||
if (num != nil)
|
||||
{
|
||||
float f = [num floatValue];
|
||||
detail = [NSString stringWithFormat: @"\\margr%d",
|
||||
(int)points2twips(f)];
|
||||
[result appendString: detail];
|
||||
}
|
||||
num = [docDict objectForKey: TOPMARGIN];
|
||||
if (num != nil)
|
||||
{
|
||||
float f = [num floatValue];
|
||||
detail = [NSString stringWithFormat: @"\\margt%d",
|
||||
(int)points2twips(f)];
|
||||
[result appendString: detail];
|
||||
}
|
||||
num = [docDict objectForKey: BUTTOMMARGIN];
|
||||
if (num != nil)
|
||||
{
|
||||
float f = [num floatValue];
|
||||
detail = [NSString stringWithFormat: @"\\margb%d",
|
||||
(int)points2twips(f)];
|
||||
[result appendString: detail];
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
else
|
||||
return @"";
|
||||
}
|
||||
|
||||
- (NSString*) headerString
|
||||
{
|
||||
NSMutableString *result;
|
||||
|
||||
result = (NSMutableString*)[NSMutableString stringWithString: @"{\\rtf1\\ansi"];
|
||||
|
||||
[result appendString: [self fontTable]];
|
||||
[result appendString: [self colorTable]];
|
||||
[result appendString: [self documentAttributes]];
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
- (NSString*) trailerString
|
||||
{
|
||||
return @"}";
|
||||
}
|
||||
|
||||
- (NSString*) fontToken: (NSString*) fontName
|
||||
{
|
||||
NSString *fCount = [fontDict objectForKey: fontName];
|
||||
|
||||
if (fCount == nil)
|
||||
{
|
||||
unsigned count = [fontDict count];
|
||||
|
||||
fCount = [NSString stringWithFormat: @"\\f%d", count];
|
||||
[fontDict setObject: fCount forKey: fontName];
|
||||
}
|
||||
|
||||
return fCount;
|
||||
}
|
||||
|
||||
- (int) numberForColor: (NSColor*)color
|
||||
{
|
||||
unsigned int cn;
|
||||
NSNumber *num = [colorDict objectForKey: color];
|
||||
|
||||
if (num == nil)
|
||||
{
|
||||
cn = [colorDict count] + 1;
|
||||
|
||||
[colorDict setObject: [NSNumber numberWithInt: cn]
|
||||
forKey: color];
|
||||
}
|
||||
else
|
||||
cn = [num intValue];
|
||||
|
||||
return cn;
|
||||
}
|
||||
|
||||
- (NSString*) paragraphStyle: (NSParagraphStyle*) paraStyle
|
||||
{
|
||||
NSMutableString *headerString = (NSMutableString *)[NSMutableString
|
||||
stringWithString:
|
||||
@"\\pard\\plain"];
|
||||
int twips;
|
||||
|
||||
if (paraStyle == nil)
|
||||
return headerString;
|
||||
|
||||
switch ([paraStyle alignment])
|
||||
{
|
||||
case NSRightTextAlignment:
|
||||
[headerString appendString: @"\\qr"];
|
||||
break;
|
||||
case NSCenterTextAlignment:
|
||||
[headerString appendString: @"\\qc"];
|
||||
break;
|
||||
case NSLeftTextAlignment:
|
||||
[headerString appendString: @"\\ql"];
|
||||
break;
|
||||
case NSJustifiedTextAlignment:
|
||||
[headerString appendString: @"\\qj"];
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
// write first line indent and left indent
|
||||
twips = (int)points2twips([paraStyle firstLineHeadIndent]);
|
||||
if (twips != 0.0)
|
||||
{
|
||||
[headerString appendString: [NSString stringWithFormat:
|
||||
@"\\fi%d",
|
||||
twips]];
|
||||
}
|
||||
twips = (int)points2twips([paraStyle headIndent]);
|
||||
if (twips != 0.0)
|
||||
{
|
||||
[headerString appendString: [NSString stringWithFormat:
|
||||
@"\\li%d",
|
||||
twips]];
|
||||
}
|
||||
twips = (int)points2twips([paraStyle tailIndent]);
|
||||
if (twips != 0.0)
|
||||
{
|
||||
[headerString appendString: [NSString stringWithFormat:
|
||||
@"\\ri%d",
|
||||
twips]];
|
||||
}
|
||||
twips = (int)points2twips([paraStyle paragraphSpacing]);
|
||||
if (twips != 0.0)
|
||||
{
|
||||
[headerString appendString: [NSString stringWithFormat:
|
||||
@"\\sa%d",
|
||||
twips]];
|
||||
}
|
||||
twips = (int)points2twips([paraStyle minimumLineHeight]);
|
||||
if (twips != 0.0)
|
||||
{
|
||||
[headerString appendString: [NSString stringWithFormat:
|
||||
@"\\sl%d",
|
||||
twips]];
|
||||
}
|
||||
twips = (int)points2twips([paraStyle maximumLineHeight]);
|
||||
if (twips != 0.0)
|
||||
{
|
||||
[headerString appendString: [NSString stringWithFormat:
|
||||
@"\\sl-%d",
|
||||
twips]];
|
||||
}
|
||||
// FIXME: Tab definitions are still missing
|
||||
|
||||
return headerString;
|
||||
}
|
||||
|
||||
- (NSString*) runStringForString: (NSString*) substring
|
||||
attributes: (NSDictionary*) attributes
|
||||
paragraphStart: (BOOL) first
|
||||
{
|
||||
NSMutableString *result = [NSMutableString stringWithCapacity:
|
||||
[substring length]*2];
|
||||
NSMutableString *headerString = [NSMutableString stringWithCapacity: 20];
|
||||
NSMutableString *trailerString = [NSMutableString stringWithCapacity: 20];
|
||||
NSEnumerator *attribEnum;
|
||||
id currAttrib;
|
||||
|
||||
if (first)
|
||||
{
|
||||
NSParagraphStyle *paraStyle = [attributes objectForKey:
|
||||
NSParagraphStyleAttributeName];
|
||||
[headerString appendString: [self paragraphStyle: paraStyle]];
|
||||
DESTROY(currentFont);
|
||||
}
|
||||
|
||||
/*
|
||||
* analyze attributes of current run
|
||||
*
|
||||
* FIXME: All the character attributes should be output relative to the font
|
||||
* attributes of the paragraph. So if the paragraph has underline on it should
|
||||
* still be possible to switch it off for some characters, which currently is
|
||||
* not possible.
|
||||
*/
|
||||
attribEnum = [attributes keyEnumerator];
|
||||
while ((currAttrib = [attribEnum nextObject]) != nil)
|
||||
{
|
||||
if ([currAttrib isEqualToString: NSFontAttributeName])
|
||||
{
|
||||
/*
|
||||
* handle fonts
|
||||
*/
|
||||
NSFont *font;
|
||||
NSString *fontName;
|
||||
NSFontTraitMask traits;
|
||||
|
||||
font = [attributes objectForKey: NSFontAttributeName];
|
||||
fontName = [font familyName];
|
||||
traits = [[NSFontManager sharedFontManager] traitsOfFont: font];
|
||||
|
||||
/*
|
||||
* font name
|
||||
*/
|
||||
if (currentFont == nil ||
|
||||
![fontName isEqualToString: [currentFont familyName]])
|
||||
{
|
||||
[headerString appendString: [self fontToken: fontName]];
|
||||
}
|
||||
/*
|
||||
* font size
|
||||
*/
|
||||
if (currentFont == nil ||
|
||||
[font pointSize] != [currentFont pointSize])
|
||||
{
|
||||
int points = (int)[font pointSize]*2;
|
||||
NSString *pString;
|
||||
|
||||
pString = [NSString stringWithFormat: @"\\fs%d", points];
|
||||
[headerString appendString: pString];
|
||||
}
|
||||
/*
|
||||
* font attributes
|
||||
*/
|
||||
if (traits & NSItalicFontMask)
|
||||
{
|
||||
[headerString appendString: @"\\i"];
|
||||
[trailerString appendString: @"\\i0"];
|
||||
}
|
||||
if (traits & NSBoldFontMask)
|
||||
{
|
||||
[headerString appendString: @"\\b"];
|
||||
[trailerString appendString: @"\\b0"];
|
||||
}
|
||||
|
||||
if (first)
|
||||
ASSIGN(currentFont, font);
|
||||
}
|
||||
else if ([currAttrib isEqualToString: NSForegroundColorAttributeName])
|
||||
{
|
||||
NSColor *color = [attributes objectForKey: NSForegroundColorAttributeName];
|
||||
if (![color isEqual: fgColor])
|
||||
{
|
||||
[headerString appendString: [NSString stringWithFormat:
|
||||
@"\\cf%d",
|
||||
[self numberForColor: color]]];
|
||||
[trailerString appendString: @"\\cf0"];
|
||||
}
|
||||
}
|
||||
else if ([currAttrib isEqualToString: NSBackgroundColorAttributeName])
|
||||
{
|
||||
NSColor *color = [attributes objectForKey: NSBackgroundColorAttributeName];
|
||||
if (![color isEqual: bgColor])
|
||||
{
|
||||
[headerString appendString: [NSString stringWithFormat:
|
||||
@"\\cb%d",
|
||||
[self numberForColor: color]]];
|
||||
[trailerString appendString: @"\\cb0"];
|
||||
}
|
||||
}
|
||||
else if ([currAttrib isEqualToString: NSUnderlineStyleAttributeName])
|
||||
{
|
||||
[headerString appendString: @"\\ul"];
|
||||
[trailerString appendString: @"\\ulnone"];
|
||||
}
|
||||
else if ([currAttrib isEqualToString: NSSuperscriptAttributeName])
|
||||
{
|
||||
NSNumber *value = [attributes objectForKey: NSSuperscriptAttributeName];
|
||||
int svalue = [value intValue] * 6;
|
||||
|
||||
if (svalue > 0)
|
||||
{
|
||||
[headerString appendString: [NSString stringWithFormat:
|
||||
@"\\up%d", svalue]];
|
||||
[trailerString appendString: @"\\up0"];
|
||||
}
|
||||
else if (svalue < 0)
|
||||
{
|
||||
[headerString appendString: [NSString stringWithFormat:
|
||||
@"\\dn-%d", svalue]];
|
||||
[trailerString appendString: @"\\dn0"];
|
||||
}
|
||||
}
|
||||
else if ([currAttrib isEqualToString: NSBaselineOffsetAttributeName])
|
||||
{
|
||||
NSNumber *value = [attributes objectForKey: NSBaselineOffsetAttributeName];
|
||||
int svalue = (int)[value floatValue] * 2;
|
||||
|
||||
if (svalue > 0)
|
||||
{
|
||||
[headerString appendString: [NSString stringWithFormat:
|
||||
@"\\up%d", svalue]];
|
||||
[trailerString appendString: @"\\up0"];
|
||||
}
|
||||
else if (svalue < 0)
|
||||
{
|
||||
[headerString appendString: [NSString stringWithFormat:
|
||||
@"\\dn-%d", svalue]];
|
||||
[trailerString appendString: @"\\dn0"];
|
||||
}
|
||||
}
|
||||
else if ([currAttrib isEqualToString: NSAttachmentAttributeName])
|
||||
{
|
||||
}
|
||||
else if ([currAttrib isEqualToString: NSLigatureAttributeName])
|
||||
{
|
||||
}
|
||||
else if ([currAttrib isEqualToString: NSKernAttributeName])
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: There should be a more efficient way to replace these
|
||||
substring = [substring stringByReplacingString: @"\\"
|
||||
withString: @"\\\\"];
|
||||
substring = [substring stringByReplacingString: @"\n"
|
||||
withString: @"\\par\n"];
|
||||
substring = [substring stringByReplacingString: @"\t"
|
||||
withString: @"\\tab "];
|
||||
substring = [substring stringByReplacingString: @"{"
|
||||
withString: @"\\{"];
|
||||
substring = [substring stringByReplacingString: @"}"
|
||||
withString: @"\\}"];
|
||||
// FIXME: All characters not in the standard encoding must be
|
||||
// replaced by \'xx
|
||||
|
||||
if (!first)
|
||||
{
|
||||
NSString *braces;
|
||||
|
||||
if ([headerString length])
|
||||
braces = [NSString stringWithFormat: @"{%@ %@}",
|
||||
headerString, substring];
|
||||
else
|
||||
braces = substring;
|
||||
|
||||
[result appendString: braces];
|
||||
}
|
||||
else
|
||||
{
|
||||
NSString *nobraces;
|
||||
|
||||
if ([headerString length])
|
||||
nobraces = [NSString stringWithFormat: @"%@ %@",
|
||||
headerString, substring];
|
||||
else
|
||||
nobraces = substring;
|
||||
|
||||
/* This has no result, as the character style is reset for each paragraph
|
||||
if ([trailerString length])
|
||||
nobraces = [NSString stringWithFormat: @"%@%@ ",
|
||||
nobraces, trailerString];
|
||||
*/
|
||||
|
||||
[result appendString: nobraces];
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
- (NSString*) bodyString
|
||||
{
|
||||
NSString *string = [text string];
|
||||
NSMutableString *result = [NSMutableString string];
|
||||
unsigned loc = 0;
|
||||
unsigned length = [string length];
|
||||
|
||||
while (loc < length)
|
||||
{
|
||||
// Range of the current run
|
||||
NSRange currRange = NSMakeRange(loc, 0);
|
||||
// Range of the current paragraph
|
||||
NSRange completeRange = [string lineRangeForRange: currRange];
|
||||
BOOL first = YES;
|
||||
|
||||
while (NSMaxRange(currRange) < NSMaxRange(completeRange)) // save all "runs"
|
||||
{
|
||||
NSDictionary *attributes;
|
||||
NSString *substring;
|
||||
NSString *runString;
|
||||
|
||||
attributes = [text attributesAtIndex: NSMaxRange(currRange)
|
||||
longestEffectiveRange: &currRange
|
||||
inRange: completeRange];
|
||||
substring = [string substringWithRange: currRange];
|
||||
|
||||
runString = [self runStringForString: substring
|
||||
attributes: attributes
|
||||
paragraphStart: first];
|
||||
[result appendString: runString];
|
||||
first = NO;
|
||||
}
|
||||
|
||||
loc = NSMaxRange(completeRange);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
- (NSString*) RTFDStringFromAttributedString: (NSAttributedString*)aText
|
||||
documentAttributes: (NSDictionary*)dict
|
||||
{
|
||||
NSMutableString *output = [NSMutableString string];
|
||||
NSString *headerString;
|
||||
NSString *trailerString;
|
||||
NSString *bodyString;
|
||||
|
||||
ASSIGN(text, aText);
|
||||
ASSIGN(docDict, dict);
|
||||
|
||||
/*
|
||||
* do not change order! (esp. body has to be generated first; builds context)
|
||||
*/
|
||||
bodyString = [self bodyString];
|
||||
trailerString = [self trailerString];
|
||||
headerString = [self headerString];
|
||||
|
||||
[output appendString: headerString];
|
||||
[output appendString: bodyString];
|
||||
[output appendString: trailerString];
|
||||
return (NSString*)output;
|
||||
}
|
||||
@end
|
Loading…
Reference in a new issue