Extended support for RTF

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/gui/trunk@6697 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
Fred Kiefer 2000-06-16 17:00:17 +00:00
parent 69214d4cbe
commit 474b1eec6b

View file

@ -4,6 +4,8 @@
Author: Stefan Bðhringer (stefan.boehringer@uni-bochum.de) Author: Stefan Bðhringer (stefan.boehringer@uni-bochum.de)
Date: Dec 1999 Date: Dec 1999
Author: Fred Kiefer <FredKiefer@gmx.de>
Date: June 2000
This file is part of the GNUstep GUI Library. This file is part of the GNUstep GUI Library.
@ -23,9 +25,10 @@
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/ */
#import <Foundation/Foundation.h> #include <Foundation/Foundation.h>
#import <AppKit/AppKit.h> #include <AppKit/AppKit.h>
#import "Parsers/rtfConsumer.h" #include "Parsers/rtfConsumer.h"
#include "Parsers/rtfConsumerFunctions.h"
/* we have to satisfy the scanner with a stream reading function */ /* we have to satisfy the scanner with a stream reading function */
typedef struct { typedef struct {
@ -53,54 +56,77 @@ readNSString(StringContext *ctxt)
we must implement from the rtfConsumerSkeleton.h file (Supporting files) we must implement from the rtfConsumerSkeleton.h file (Supporting files)
this includes the yacc error handling and output this includes the yacc error handling and output
*/ */
#define GSfontDictName @"fonts"
#define GScurrentTextPosition @"textPosition"
#define GSresultName @"result"
#define GSchanged @"changed"
#define GSparagraph @"paragraph" // Hold the attributs of the current run
#define GSfontName @"fontName" @interface RTFAttribute: NSObject <NSCopying>
#define GSfontSize @"fontSize"
#define GSbold @"bold"
#define GSitalic @"italic"
#define GSunderline @"underline"
#define GSscript @"script"
#define GSdocumentAttributes @"documentAttributes"
#define CTXT ((NSMutableDictionary *)ctxt)
#define FONTS [CTXT objectForKey: GSfontDictName]
#define RESULT [CTXT objectForKey: GSresultName]
#define CHANGED [[CTXT objectForKey: GSchanged] boolValue]
#define SETCHANGED(flag) [CTXT setObject: [NSNumber numberWithBool: flag] forKey: GSchanged]
#define PARAGRAPH [CTXT objectForKey: GSparagraph]
#define halfpoints2points(a) ((a)/2.0)
// FIXME: How to convert twips to points???
#define twips2points(a) ((a)/500.0)
static int textPosition(void *ctxt)
{ {
return [[CTXT objectForKey: GScurrentTextPosition] intValue]; @public
BOOL changed;
NSParagraphStyle *paragraph;
NSColor *fgColour;
NSColor *bgColour;
NSString *fontName;
float fontSize;
BOOL bold;
BOOL italic;
BOOL underline;
int script;
} }
static NSFont *currentFont(void *ctxt) - (NSFont*) currentFont;
@end
@implementation RTFAttribute
- (id) init
{
NSFont *font = [NSFont userFontOfSize:12];
ASSIGN(fontName, [font familyName]);
fontSize = 12.0;
italic = NO;
bold = NO;
underline = NO;
script = 0;
paragraph = [NSMutableParagraphStyle defaultParagraphStyle];
changed = YES;
return self;
}
- (void) dealloc
{
RELEASE(paragraph);
RELEASE(fontName);
RELEASE(fgColour);
RELEASE(bgColour);
[super dealloc];
}
- (id) copyWithZone: (NSZone*)zone
{
RTFAttribute *new = [isa allocWithZone: zone];
new->paragraph = [paragraph copyWithZone: zone];
new->fontName = [fontName copyWithZone: zone];
new->fontSize = fontSize;
new->italic = italic;
new->bold = bold;
new->underline = underline;
new->script = script;
new->changed = NO;
return new;
}
- (NSFont*) currentFont
{ {
NSFont *font; NSFont *font;
BOOL boldOn;
BOOL italicOn;
NSString *name;
float size;
NSFontTraitMask traits = 0; NSFontTraitMask traits = 0;
int weight; int weight;
name = [CTXT objectForKey: GSfontName]; if (bold)
size = [[CTXT objectForKey: GSfontSize] floatValue];
boldOn = [[CTXT objectForKey: GSbold] boolValue];
italicOn = [[CTXT objectForKey: GSitalic] boolValue];
if (boldOn)
{ {
weight = 9; weight = 9;
traits |= NSBoldFontMask; traits |= NSBoldFontMask;
@ -111,7 +137,7 @@ static NSFont *currentFont(void *ctxt)
traits |= NSUnboldFontMask; traits |= NSUnboldFontMask;
} }
if (italicOn) if (italic)
{ {
traits |= NSItalicFontMask; traits |= NSItalicFontMask;
} }
@ -120,12 +146,147 @@ static NSFont *currentFont(void *ctxt)
traits |= NSUnitalicFontMask; traits |= NSUnitalicFontMask;
} }
font = [[NSFontManager sharedFontManager] fontWithFamily: name font = [[NSFontManager sharedFontManager] fontWithFamily: fontName
traits: traits traits: traits
weight: weight weight: weight
size: size]; size: fontSize];
return font; return font;
} }
@end
@interface RTFConsumer: NSObject
{
@public
NSMutableDictionary *documentAttributes;
NSMutableDictionary *fonts;
NSMutableArray *colours;
NSMutableArray *attrs;
NSMutableAttributedString *result;
int textPosition;
int ignore;
}
- (NSDictionary*) documentAttributes;
- (RTFAttribute*) attr;
- (void) push;
- (void) pop;
- (NSAttributedString*) result;
@end
@implementation RTFConsumer
- (id) init
{
RTFAttribute *attr = [RTFAttribute new];
textPosition = 0;
ignore = 0;
result = [[NSMutableAttributedString alloc] init];
ASSIGN(documentAttributes, [NSMutableDictionary dictionary]);
ASSIGN(fonts, [NSMutableDictionary dictionary]);
ASSIGN(attrs, [NSMutableArray array]);
ASSIGN(colours, [NSMutableArray array]);
[attrs addObject: attr];
return self;
}
- (void)dealloc
{
RELEASE(fonts);
RELEASE(attrs);
RELEASE(colours);
RELEASE(result);
RELEASE(documentAttributes);
[super dealloc];
}
- (NSDictionary*) documentAttributes
{
RETAIN(documentAttributes);
return AUTORELEASE(documentAttributes);
}
- (RTFAttribute*) attr
{
return [attrs lastObject];
}
- (void) push
{
[attrs addObject: [[attrs lastObject] copy]];
}
- (void) pop
{
[attrs removeLastObject];
}
- (NSAttributedString*) result
{
RETAIN(result);
return AUTORELEASE(result);
}
- (NSAttributedString*) parseRTF: (NSData *)rtfData
documentAttributes: (NSDictionary **)dict
{
CREATE_AUTORELEASE_POOL(pool);
RTFscannerCtxt scanner;
StringContext stringCtxt;
NSString *rtfString = [[NSString alloc]
initWithData: rtfData
encoding: NSASCIIStringEncoding];
// Has this RFTConsumer allready been used? Is so, reset!
if (textPosition)
[self init];
initStringContext(&stringCtxt, rtfString);
lexInitContext(&scanner, &stringCtxt, (int (*)(void*))readNSString);
NS_DURING
GSRTFparse((void *)self, &scanner);
NS_HANDLER
NSLog(@"Problem during RTF Parsing: %@",
[localException reason]);
//[localException raise];
NS_ENDHANDLER
RELEASE(pool);
// document attributes
if (dict)
*dict = [self documentAttributes];
return [self result];
}
@end
#define FONTS ((RTFConsumer *)ctxt)->fonts
#define COLOURS ((RTFConsumer *)ctxt)->colours
#define RESULT ((RTFConsumer *)ctxt)->result
#define IGNORE ((RTFConsumer *)ctxt)->ignore
#define TEXTPOSITION ((RTFConsumer *)ctxt)->textPosition
#define DOCUMENTATTRIBUTES ((RTFConsumer*)ctxt)->documentAttributes
#define CTXT [((RTFConsumer *)ctxt) attr]
#define CHANGED CTXT->changed
#define PARAGRAPH CTXT->paragraph
#define FONTNAME CTXT->fontName
#define SCRIPT CTXT->script
#define ITALIC CTXT->italic
#define BOLD CTXT->bold
#define UNDERLINE CTXT->underline
#define FGCOLOUR CTXT->fgColour
#define BGCOLOUR CTXT->bgColour
#define PAPERSIZE @"PaperSize"
#define LEFTMARGIN @"LeftMargin"
#define RIGHTMARGIN @"RightMargin"
#define TOPMARGIN @"TopMargin"
#define BUTTOMMARGIN @"ButtomMargin"
/* handle errors (this is the yacc error mech) */ /* handle errors (this is the yacc error mech) */
void GSRTFerror(const char *msg) void GSRTFerror(const char *msg)
@ -146,22 +307,6 @@ void GSRTFgenericRTFcommand(void *ctxt, RTFcmd cmd)
//Start: we're doing some initialization //Start: we're doing some initialization
void GSRTFstart(void *ctxt) void GSRTFstart(void *ctxt)
{ {
NSFont *font = [NSFont userFontOfSize:12];
[CTXT setObject: [NSNumber numberWithInt:0] forKey: GScurrentTextPosition];
[CTXT setObject: [NSMutableDictionary dictionary] forKey: GSfontDictName];
SETCHANGED(YES);
[CTXT setObject: [NSMutableParagraphStyle defaultParagraphStyle]
forKey: GSparagraph];
[CTXT setObject: [font familyName] forKey: GSfontName];
[CTXT setObject: [NSNumber numberWithFloat: 12.0] forKey: GSfontSize];
[CTXT setObject: [NSNumber numberWithBool: NO] forKey: GSbold];
[CTXT setObject: [NSNumber numberWithBool: NO] forKey: GSitalic];
[CTXT setObject: [NSNumber numberWithBool: NO] forKey: GSunderline];
[CTXT setObject: [NSNumber numberWithInt: 0] forKey: GSscript];
[RESULT beginEditing]; [RESULT beginEditing];
} }
@ -172,44 +317,50 @@ void GSRTFstop(void *ctxt)
[RESULT endEditing]; [RESULT endEditing];
} }
void GSRTFopenBlock(void *ctxt) void GSRTFopenBlock(void *ctxt, BOOL ignore)
{ {
// FIXME: Should push the current state on a stack if (!IGNORE)
[(RTFConsumer *)ctxt push];
// Switch off any output for ignored block statements
if (ignore)
IGNORE++;
} }
void GSRTFcloseBlock(void *ctxt) void GSRTFcloseBlock(void *ctxt, BOOL ignore)
{ {
// FIXME: Should pop the current state from a stack if (ignore)
IGNORE--;
if (!IGNORE)
[(RTFConsumer *)ctxt pop];
} }
void GSRTFmangleText(void *ctxt, const char *text) void GSRTFmangleText(void *ctxt, const char *text)
{ {
int oldPosition = textPosition(ctxt); int oldPosition = TEXTPOSITION;
int textlen = strlen(text); int textlen = strlen(text);
int newPosition = oldPosition + textlen; int newPosition = oldPosition + textlen;
NSRange insertionRange = NSMakeRange(oldPosition,0); NSRange insertionRange = NSMakeRange(oldPosition,0);
NSDictionary *attributes; NSDictionary *attributes;
NSFont *font; NSFont *font;
if (textlen) if (!IGNORE && textlen)
{ {
[CTXT setObject:[NSNumber numberWithInt: newPosition] TEXTPOSITION = newPosition;
forKey: GScurrentTextPosition];
[RESULT replaceCharactersInRange: insertionRange [RESULT replaceCharactersInRange: insertionRange
withString: [NSString stringWithCString:text]]; withString: [NSString stringWithCString:text]];
if (CHANGED) if (CHANGED)
{ {
font = currentFont(ctxt); font = [CTXT currentFont];
attributes = [NSDictionary dictionaryWithObjectsAndKeys: attributes = [NSDictionary dictionaryWithObjectsAndKeys:
font, NSFontAttributeName, font, NSFontAttributeName,
[CTXT objectForKey: GSscript], NSSuperscriptAttributeName, SCRIPT, NSSuperscriptAttributeName,
PARAGRAPH, NSParagraphStyleAttributeName, PARAGRAPH, NSParagraphStyleAttributeName,
nil]; nil];
[RESULT setAttributes: attributes range: [RESULT setAttributes: attributes range:
NSMakeRange(oldPosition, textlen)]; NSMakeRange(oldPosition, textlen)];
SETCHANGED(NO); CHANGED = NO;
} }
} }
} }
@ -224,7 +375,7 @@ void GSRTFregisterFont(void *ctxt, const char *fontName,
{ {
[NSException raise:NSInvalidArgumentException [NSException raise:NSInvalidArgumentException
format:@"Error in RTF (font omitted?), position:%d", format:@"Error in RTF (font omitted?), position:%d",
textPosition(ctxt)]; TEXTPOSITION];
} }
// exclude trailing ';' from fontName // exclude trailing ';' from fontName
fontNameString = [NSString stringWithCString: fontName fontNameString = [NSString stringWithCString: fontName
@ -243,14 +394,14 @@ void GSRTFfontNumber(void *ctxt, int fontNumber)
[NSException raise: NSInvalidArgumentException [NSException raise: NSInvalidArgumentException
format: @"Error in RTF (referring to undefined font \\f%d), position:%d", format: @"Error in RTF (referring to undefined font \\f%d), position:%d",
fontNumber, fontNumber,
textPosition(ctxt)]; TEXTPOSITION];
} }
else else
{ {
if (![fontName isEqual: [CTXT objectForKey: GSfontName]]) if (![fontName isEqual: FONTNAME])
{ {
[CTXT setObject: fontName forKey: GSfontName]; ASSIGN(FONTNAME, fontName);
SETCHANGED(YES); CHANGED = YES;
} }
} }
} }
@ -260,28 +411,77 @@ void GSRTFfontSize(void *ctxt, int fontSize)
{ {
float size = halfpoints2points(fontSize); float size = halfpoints2points(fontSize);
if (size != [[CTXT objectForKey: GSfontSize] floatValue]) if (size != CTXT->fontSize)
{ {
[CTXT setObject: [NSNumber numberWithFloat: size] CTXT->fontSize = size;
forKey: GSfontSize]; CHANGED = YES;
SETCHANGED(YES);
} }
} }
void GSRTFpaperWidth(void *ctxt, int width) void GSRTFpaperWidth(void *ctxt, int width)
{ {
float fwidth = twips2points(width);
NSMutableDictionary *dict = DOCUMENTATTRIBUTES;
NSValue *val = [dict objectForKey: PAPERSIZE];
NSSize size;
if (val == nil)
size = NSMakeSize(fwidth, 792);
else
{
size = [val sizeValue];
size.width = fwidth;
}
[dict setObject: [NSValue valueWithSize: size] forKey: PAPERSIZE];
} }
void GSRTFpaperHeight(void *ctxt, int height) void GSRTFpaperHeight(void *ctxt, int height)
{ {
float fheight = twips2points(height);
NSMutableDictionary *dict = DOCUMENTATTRIBUTES;
NSValue *val = [dict objectForKey: PAPERSIZE];
NSSize size;
if (val == nil)
size = NSMakeSize(612, fheight);
else
{
size = [val sizeValue];
size.height = fheight;
}
[dict setObject: [NSValue valueWithSize: size] forKey: PAPERSIZE];
} }
void GSRTFmarginLeft(void *ctxt, int margin) void GSRTFmarginLeft(void *ctxt, int margin)
{ {
float fmargin = twips2points(margin);
NSMutableDictionary *dict = DOCUMENTATTRIBUTES;
[dict setObject: [NSNumber numberWithFloat: fmargin] forKey: LEFTMARGIN];
} }
void GSRTFmarginRight(void *ctxt, int margin) void GSRTFmarginRight(void *ctxt, int margin)
{ {
float fmargin = twips2points(margin);
NSMutableDictionary *dict = DOCUMENTATTRIBUTES;
[dict setObject: [NSNumber numberWithFloat: fmargin] forKey: RIGHTMARGIN];
}
void GSRTFmarginTop(void *ctxt, int margin)
{
float fmargin = twips2points(margin);
NSMutableDictionary *dict = DOCUMENTATTRIBUTES;
[dict setObject: [NSNumber numberWithFloat: fmargin] forKey: TOPMARGIN];
}
void GSRTFmarginButtom(void *ctxt, int margin)
{
float fmargin = twips2points(margin);
NSMutableDictionary *dict = DOCUMENTATTRIBUTES;
[dict setObject: [NSNumber numberWithFloat: fmargin] forKey: BUTTOMMARGIN];
} }
void GSRTFfirstLineIndent(void *ctxt, int indent) void GSRTFfirstLineIndent(void *ctxt, int indent)
@ -289,10 +489,11 @@ void GSRTFfirstLineIndent(void *ctxt, int indent)
NSMutableParagraphStyle *para = PARAGRAPH; NSMutableParagraphStyle *para = PARAGRAPH;
float findent = twips2points(indent); float findent = twips2points(indent);
if ([para firstLineHeadIndent] != findent) // for attributed strings only positiv indent is allowed
if ((findent >= 0.0) && ([para firstLineHeadIndent] != findent))
{ {
[para setFirstLineHeadIndent: findent]; [para setFirstLineHeadIndent: findent];
SETCHANGED(YES); CHANGED = YES;
} }
} }
@ -301,10 +502,11 @@ void GSRTFleftIndent(void *ctxt, int indent)
NSMutableParagraphStyle *para = PARAGRAPH; NSMutableParagraphStyle *para = PARAGRAPH;
float findent = twips2points(indent); float findent = twips2points(indent);
if ([para headIndent] != findent) // for attributed strings only positiv indent is allowed
if ((findent >= 0.0) && ([para headIndent] != findent))
{ {
[para setHeadIndent: findent]; [para setHeadIndent: findent];
SETCHANGED(YES); CHANGED = YES;
} }
} }
@ -315,7 +517,7 @@ void GSRTFalignCenter(void *ctxt)
if ([para alignment] != NSCenterTextAlignment) if ([para alignment] != NSCenterTextAlignment)
{ {
[para setAlignment: NSCenterTextAlignment]; [para setAlignment: NSCenterTextAlignment];
SETCHANGED(YES); CHANGED = YES;
} }
} }
@ -326,7 +528,7 @@ void GSRTFalignLeft(void *ctxt)
if ([para alignment] != NSLeftTextAlignment) if ([para alignment] != NSLeftTextAlignment)
{ {
[para setAlignment: NSLeftTextAlignment]; [para setAlignment: NSLeftTextAlignment];
SETCHANGED(YES); CHANGED = YES;
} }
} }
@ -337,7 +539,7 @@ void GSRTFalignRight(void *ctxt)
if ([para alignment] != NSRightTextAlignment) if ([para alignment] != NSRightTextAlignment)
{ {
[para setAlignment: NSRightTextAlignment]; [para setAlignment: NSRightTextAlignment];
SETCHANGED(YES); CHANGED = YES;
} }
} }
@ -345,23 +547,39 @@ void GSRTFstyle(void *ctxt, int style)
{ {
} }
void GSRTFaddColor(void *ctxt, int red, int green, int blue)
{
NSColor *colour = [NSColor colorWithCalibratedRed: red/255.0
green: green/255.0
blue: blue/255.0
alpha: 1.0];
[COLOURS addObject: colour];
}
void GSRTFaddDefaultColor(void *ctxt)
{
[COLOURS addObject: [NSColor textColor]];
}
void GSRTFcolorbg(void *ctxt, int color) void GSRTFcolorbg(void *ctxt, int color)
{ {
ASSIGN(BGCOLOUR, [COLOURS objectAtIndex: color]);
} }
void GSRTFcolorfg(void *ctxt, int color) void GSRTFcolorfg(void *ctxt, int color)
{ {
ASSIGN(FGCOLOUR, [COLOURS objectAtIndex: color]);
} }
void GSRTFsubscript(void *ctxt, int script) void GSRTFsubscript(void *ctxt, int script)
{ {
script = (int) (-halfpoints2points(script) / 3.0); script = (int) (-halfpoints2points(script) / 3.0);
if (script != [[CTXT objectForKey: GSscript] intValue]) if (script != SCRIPT)
{ {
[CTXT setObject: [NSNumber numberWithInt: script] SCRIPT = script;
forKey: GSscript]; CHANGED = YES;
SETCHANGED(YES);
} }
} }
@ -369,68 +587,50 @@ void GSRTFsuperscript(void *ctxt, int script)
{ {
script = (int) (halfpoints2points(script) / 3.0); script = (int) (halfpoints2points(script) / 3.0);
if (script != [[CTXT objectForKey: GSscript] intValue]) if (script != SCRIPT)
{ {
[CTXT setObject: [NSNumber numberWithInt: script] SCRIPT = script;
forKey: GSscript]; CHANGED = YES;
SETCHANGED(YES);
} }
} }
void GSRTFitalic(void *ctxt, BOOL state) void GSRTFitalic(void *ctxt, BOOL state)
{ {
if (state != [[CTXT objectForKey: GSitalic] boolValue]) if (state != ITALIC)
{ {
[CTXT setObject: [NSNumber numberWithBool: state] forKey: GSitalic]; ITALIC = state;
SETCHANGED(YES); CHANGED = YES;
} }
} }
void GSRTFbold(void *ctxt, BOOL state) void GSRTFbold(void *ctxt, BOOL state)
{ {
if (state != [[CTXT objectForKey: GSbold] boolValue]) if (state != BOLD)
{ {
[CTXT setObject: [NSNumber numberWithBool: state] forKey: GSbold]; BOLD = state;
SETCHANGED(YES); CHANGED = YES;
} }
} }
void GSRTFunderline(void *ctxt, BOOL state) void GSRTFunderline(void *ctxt, BOOL state)
{ {
if (state != [[CTXT objectForKey: GSunderline] boolValue]) if (state != UNDERLINE)
{ {
[CTXT setObject: [NSNumber numberWithBool: state] forKey: GSunderline]; UNDERLINE = state;
SETCHANGED(YES); CHANGED = YES;
} }
} }
BOOL parseRTFintoAttributedString(NSString *rtfString, NSAttributedString *parseRTFintoAttributedString(NSData *rtfData,
NSMutableAttributedString *result, NSDictionary **dict)
NSDictionary **dict)
{ {
RTFscannerCtxt scanner; RTFConsumer *consumer = [RTFConsumer new];
StringContext stringCtxt; NSAttributedString *result;
NSMutableDictionary *myDict = [NSMutableDictionary dictionary];
[myDict setObject: result forKey: GSresultName];
initStringContext(&stringCtxt, rtfString);
lexInitContext(&scanner, &stringCtxt, (int (*)(void*))readNSString);
GSRTFparse(myDict, &scanner);
// document attributes result = [consumer parseRTF: rtfData documentAttributes: dict];
if (dict) RELEASE(consumer);
(*dict)=[myDict objectForKey: GSdocumentAttributes];
return YES; return result;
}
NSMutableAttributedString *attributedStringFromRTF(NSString *rtfString)
{
NSMutableAttributedString *result = [[NSMutableAttributedString alloc] init];
parseRTFintoAttributedString(rtfString, result, NULL);
return AUTORELEASE(result);
} }