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)
Date: Dec 1999
Author: Fred Kiefer <FredKiefer@gmx.de>
Date: June 2000
This file is part of the GNUstep GUI Library.
@ -23,9 +25,10 @@
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#import <Foundation/Foundation.h>
#import <AppKit/AppKit.h>
#import "Parsers/rtfConsumer.h"
#include <Foundation/Foundation.h>
#include <AppKit/AppKit.h>
#include "Parsers/rtfConsumer.h"
#include "Parsers/rtfConsumerFunctions.h"
/* we have to satisfy the scanner with a stream reading function */
typedef struct {
@ -53,54 +56,77 @@ readNSString(StringContext *ctxt)
we must implement from the rtfConsumerSkeleton.h file (Supporting files)
this includes the yacc error handling and output
*/
#define GSfontDictName @"fonts"
#define GScurrentTextPosition @"textPosition"
#define GSresultName @"result"
#define GSchanged @"changed"
#define GSparagraph @"paragraph"
#define GSfontName @"fontName"
#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)
// Hold the attributs of the current run
@interface RTFAttribute: NSObject <NSCopying>
{
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;
BOOL boldOn;
BOOL italicOn;
NSString *name;
float size;
NSFontTraitMask traits = 0;
int weight;
name = [CTXT objectForKey: GSfontName];
size = [[CTXT objectForKey: GSfontSize] floatValue];
boldOn = [[CTXT objectForKey: GSbold] boolValue];
italicOn = [[CTXT objectForKey: GSitalic] boolValue];
if (boldOn)
if (bold)
{
weight = 9;
traits |= NSBoldFontMask;
@ -111,7 +137,7 @@ static NSFont *currentFont(void *ctxt)
traits |= NSUnboldFontMask;
}
if (italicOn)
if (italic)
{
traits |= NSItalicFontMask;
}
@ -120,12 +146,147 @@ static NSFont *currentFont(void *ctxt)
traits |= NSUnitalicFontMask;
}
font = [[NSFontManager sharedFontManager] fontWithFamily: name
font = [[NSFontManager sharedFontManager] fontWithFamily: fontName
traits: traits
weight: weight
size: size];
size: fontSize];
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) */
void GSRTFerror(const char *msg)
@ -146,22 +307,6 @@ void GSRTFgenericRTFcommand(void *ctxt, RTFcmd cmd)
//Start: we're doing some initialization
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];
}
@ -172,44 +317,50 @@ void GSRTFstop(void *ctxt)
[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)
{
int oldPosition = textPosition(ctxt);
int oldPosition = TEXTPOSITION;
int textlen = strlen(text);
int newPosition = oldPosition + textlen;
NSRange insertionRange = NSMakeRange(oldPosition,0);
NSDictionary *attributes;
NSFont *font;
if (textlen)
if (!IGNORE && textlen)
{
[CTXT setObject:[NSNumber numberWithInt: newPosition]
forKey: GScurrentTextPosition];
TEXTPOSITION = newPosition;
[RESULT replaceCharactersInRange: insertionRange
withString: [NSString stringWithCString:text]];
if (CHANGED)
{
font = currentFont(ctxt);
font = [CTXT currentFont];
attributes = [NSDictionary dictionaryWithObjectsAndKeys:
font, NSFontAttributeName,
[CTXT objectForKey: GSscript], NSSuperscriptAttributeName,
SCRIPT, NSSuperscriptAttributeName,
PARAGRAPH, NSParagraphStyleAttributeName,
nil];
[RESULT setAttributes: attributes range:
NSMakeRange(oldPosition, textlen)];
SETCHANGED(NO);
CHANGED = NO;
}
}
}
@ -224,7 +375,7 @@ void GSRTFregisterFont(void *ctxt, const char *fontName,
{
[NSException raise:NSInvalidArgumentException
format:@"Error in RTF (font omitted?), position:%d",
textPosition(ctxt)];
TEXTPOSITION];
}
// exclude trailing ';' from fontName
fontNameString = [NSString stringWithCString: fontName
@ -243,14 +394,14 @@ void GSRTFfontNumber(void *ctxt, int fontNumber)
[NSException raise: NSInvalidArgumentException
format: @"Error in RTF (referring to undefined font \\f%d), position:%d",
fontNumber,
textPosition(ctxt)];
TEXTPOSITION];
}
else
{
if (![fontName isEqual: [CTXT objectForKey: GSfontName]])
if (![fontName isEqual: FONTNAME])
{
[CTXT setObject: fontName forKey: GSfontName];
SETCHANGED(YES);
ASSIGN(FONTNAME, fontName);
CHANGED = YES;
}
}
}
@ -260,28 +411,77 @@ void GSRTFfontSize(void *ctxt, int fontSize)
{
float size = halfpoints2points(fontSize);
if (size != [[CTXT objectForKey: GSfontSize] floatValue])
if (size != CTXT->fontSize)
{
[CTXT setObject: [NSNumber numberWithFloat: size]
forKey: GSfontSize];
SETCHANGED(YES);
CTXT->fontSize = size;
CHANGED = YES;
}
}
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)
{
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)
{
float fmargin = twips2points(margin);
NSMutableDictionary *dict = DOCUMENTATTRIBUTES;
[dict setObject: [NSNumber numberWithFloat: fmargin] forKey: LEFTMARGIN];
}
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)
@ -289,10 +489,11 @@ void GSRTFfirstLineIndent(void *ctxt, int indent)
NSMutableParagraphStyle *para = PARAGRAPH;
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];
SETCHANGED(YES);
CHANGED = YES;
}
}
@ -301,10 +502,11 @@ void GSRTFleftIndent(void *ctxt, int indent)
NSMutableParagraphStyle *para = PARAGRAPH;
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];
SETCHANGED(YES);
CHANGED = YES;
}
}
@ -315,7 +517,7 @@ void GSRTFalignCenter(void *ctxt)
if ([para alignment] != NSCenterTextAlignment)
{
[para setAlignment: NSCenterTextAlignment];
SETCHANGED(YES);
CHANGED = YES;
}
}
@ -326,7 +528,7 @@ void GSRTFalignLeft(void *ctxt)
if ([para alignment] != NSLeftTextAlignment)
{
[para setAlignment: NSLeftTextAlignment];
SETCHANGED(YES);
CHANGED = YES;
}
}
@ -337,7 +539,7 @@ void GSRTFalignRight(void *ctxt)
if ([para alignment] != 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)
{
ASSIGN(BGCOLOUR, [COLOURS objectAtIndex: color]);
}
void GSRTFcolorfg(void *ctxt, int color)
{
ASSIGN(FGCOLOUR, [COLOURS objectAtIndex: color]);
}
void GSRTFsubscript(void *ctxt, int script)
{
script = (int) (-halfpoints2points(script) / 3.0);
if (script != [[CTXT objectForKey: GSscript] intValue])
if (script != SCRIPT)
{
[CTXT setObject: [NSNumber numberWithInt: script]
forKey: GSscript];
SETCHANGED(YES);
SCRIPT = script;
CHANGED = YES;
}
}
@ -369,68 +587,50 @@ void GSRTFsuperscript(void *ctxt, int script)
{
script = (int) (halfpoints2points(script) / 3.0);
if (script != [[CTXT objectForKey: GSscript] intValue])
if (script != SCRIPT)
{
[CTXT setObject: [NSNumber numberWithInt: script]
forKey: GSscript];
SETCHANGED(YES);
SCRIPT = script;
CHANGED = YES;
}
}
void GSRTFitalic(void *ctxt, BOOL state)
{
if (state != [[CTXT objectForKey: GSitalic] boolValue])
if (state != ITALIC)
{
[CTXT setObject: [NSNumber numberWithBool: state] forKey: GSitalic];
SETCHANGED(YES);
ITALIC = state;
CHANGED = YES;
}
}
void GSRTFbold(void *ctxt, BOOL state)
{
if (state != [[CTXT objectForKey: GSbold] boolValue])
if (state != BOLD)
{
[CTXT setObject: [NSNumber numberWithBool: state] forKey: GSbold];
SETCHANGED(YES);
BOLD = state;
CHANGED = YES;
}
}
void GSRTFunderline(void *ctxt, BOOL state)
{
if (state != [[CTXT objectForKey: GSunderline] boolValue])
if (state != UNDERLINE)
{
[CTXT setObject: [NSNumber numberWithBool: state] forKey: GSunderline];
SETCHANGED(YES);
UNDERLINE = state;
CHANGED = YES;
}
}
BOOL parseRTFintoAttributedString(NSString *rtfString,
NSMutableAttributedString *result,
NSDictionary **dict)
NSAttributedString *parseRTFintoAttributedString(NSData *rtfData,
NSDictionary **dict)
{
RTFscannerCtxt scanner;
StringContext stringCtxt;
NSMutableDictionary *myDict = [NSMutableDictionary dictionary];
[myDict setObject: result forKey: GSresultName];
initStringContext(&stringCtxt, rtfString);
lexInitContext(&scanner, &stringCtxt, (int (*)(void*))readNSString);
GSRTFparse(myDict, &scanner);
RTFConsumer *consumer = [RTFConsumer new];
NSAttributedString *result;
// document attributes
if (dict)
(*dict)=[myDict objectForKey: GSdocumentAttributes];
result = [consumer parseRTF: rtfData documentAttributes: dict];
RELEASE(consumer);
return YES;
}
NSMutableAttributedString *attributedStringFromRTF(NSString *rtfString)
{
NSMutableAttributedString *result = [[NSMutableAttributedString alloc] init];
parseRTFintoAttributedString(rtfString, result, NULL);
return AUTORELEASE(result);
return result;
}