From aad9626e1513e9a919b91f88b737139a91f6ec30 Mon Sep 17 00:00:00 2001 From: rfm Date: Sun, 4 Mar 2007 15:26:35 +0000 Subject: [PATCH] Moved fiels for macos compatibility git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@24759 72102866-910b-0410-8b05-ffd578937521 --- ChangeLog | 8 + Headers/Foundation/Foundation.h | 1 + Headers/Foundation/NSSpellServer.h | 135 +++++++++ Source/GNUmakefile | 2 + Source/NSSpellServer.m | 468 +++++++++++++++++++++++++++++ 5 files changed, 614 insertions(+) create mode 100644 Headers/Foundation/NSSpellServer.h create mode 100644 Source/NSSpellServer.m diff --git a/ChangeLog b/ChangeLog index ed9041f91..b53e916c6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2007-03-04 Richard Frith-Macdonald + + * Headers/Foundation/NSSpellServer.h: Moved from appkit + * Source/NSSpellServer.m: Moved from appkit + * Source/GNUmakefile: Add NSSpellServer + * Headers/Foundation/Foundation.h: Add NSSpellServer + Moved NSSpellServer in from gui/appkit for MacOS-X compatibility + 2007-03-02 Richard Frith-Macdonald * Source/GSHTTPURLHandle.m: Cope with nil authentication info diff --git a/Headers/Foundation/Foundation.h b/Headers/Foundation/Foundation.h index fc260f6d3..333971ec5 100644 --- a/Headers/Foundation/Foundation.h +++ b/Headers/Foundation/Foundation.h @@ -96,6 +96,7 @@ #import #import #import +#import #import #import #import diff --git a/Headers/Foundation/NSSpellServer.h b/Headers/Foundation/NSSpellServer.h new file mode 100644 index 000000000..67efca4b5 --- /dev/null +++ b/Headers/Foundation/NSSpellServer.h @@ -0,0 +1,135 @@ +/* + NSSpellServer.h + + Class to allow a spell checker to be available to other apps + + Copyright (C) 1996 Free Software Foundation, Inc. + + Author: Gregory John Casamento + Date: 2001 + + Author of previous version: Scott Christley + Date: 1996 + + This file is part of the GNUstep Base 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, + 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef _GNUstep_H_NSSpellServer +#define _GNUstep_H_NSSpellServer + +#import + +#import +#import + +#if defined(__cplusplus) +extern "C" { +#endif + +// Forward declarations +@class NSConnection; +@class NSMutableArray; +@class NSMutableDictionary; + +@interface NSSpellServer : NSObject +{ +@private + id _delegate; + BOOL _caseSensitive; + unsigned char _dummy[3]; + NSMutableDictionary *_userDictionaries; + NSString *_currentLanguage; + NSArray *_ignoredWords; + void *_reserved; +} + +// Checking in Your Service +- (BOOL) registerLanguage: (NSString *)language + byVendor: (NSString *)vendor; + +// Assigning a Delegate +- (id) delegate; +- (void) setDelegate: (id)anObject; + +// Running the Service +- (void) run; + +// Checking User Dictionaries +- (BOOL) isWordInUserDictionaries: (NSString *)word + caseSensitive: (BOOL)flag; +@end + +/** + This is an informal protocol since the + NSSpellChecker will need to use a proxy object + to call these methods. + + These methods need to be implemented by the spell service + so that the NSSpellServer instance call call them when + necessary. +*/ +@interface NSObject (NSSpellServerDelegate) +/** + *

+ * This method is called when the user begins spell checking the document. + * The parameters are: sender the spell server instance which + * invoked this method, stringToCheck this is the string which + * the spell service is going to attempt to find misspelled words in, + * language the language to check in, wordCount the + * number of words checked, and countOnly a flag which dictates + * if them method checks the spelling or just counts the words in the given + * string. + *

+ *

+ * Returns a range for any word it finds that is misspelled. + *

+ */ +- (NSRange) spellServer: (NSSpellServer *)sender +findMisspelledWordInString: (NSString *)stringToCheck + language: (NSString *)language + wordCount: (int *)wordCount + countOnly: (BOOL)countOnly; + +/** + * Attempts to guess the correct spelling of word. + */ +- (NSArray *) spellServer: (NSSpellServer *)sender + suggestGuessesForWord: (NSString *)word + inLanguage: (NSString *)language; + +/** + * Records the new word in the user's dictionary for the given language. + */ +- (void) spellServer: (NSSpellServer *)sender + didLearnWord: (NSString *)word + inLanguage: (NSString *)language; + +/** + * Forgets the given word in the user's dictionary for the given language. + */ +- (void) spellServer: (NSSpellServer *)sender + didForgetWord: (NSString *)word + inLanguage: (NSString *)language; +@end + +#if defined(__cplusplus) +} +#endif + +#endif // _GNUstep_H_NSSpellServer diff --git a/Source/GNUmakefile b/Source/GNUmakefile index dff08ecb8..fe84b33e6 100644 --- a/Source/GNUmakefile +++ b/Source/GNUmakefile @@ -230,6 +230,7 @@ NSSet.m \ NSSocketPort.m \ NSSocketPortNameServer.m \ NSSortDescriptor.m \ +NSSpellServer.m \ NSString.m \ NSTask.m \ NSThread.m \ @@ -361,6 +362,7 @@ NSScanner.h \ NSSerialization.h \ NSSet.h \ NSSortDescriptor.h \ +NSSpellServer.h \ NSStream.h \ NSString.h \ NSTask.h \ diff --git a/Source/NSSpellServer.m b/Source/NSSpellServer.m new file mode 100644 index 000000000..eea398c8a --- /dev/null +++ b/Source/NSSpellServer.m @@ -0,0 +1,468 @@ +/** NSSpellServer + + Class to allow a spell checker to be available to other apps. + + Copyright (C) 2001, 1996 Free Software Foundation, Inc. + + Author by: Gregory John Casamento + Date: 2001 + Author: Scott Christley + Date: 1996 + + This file is part of the GNUstep Base 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, + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include "config.h" +#include "Foundation/NSSpellServer.h" +#include "Foundation/NSDictionary.h" +#include "Foundation/NSRunLoop.h" +#include "Foundation/NSFileManager.h" +#include "Foundation/NSUserDefaults.h" +#include "Foundation/NSPathUtilities.h" +#include "Foundation/NSConnection.h" +#include "Foundation/NSProcessInfo.h" +#include "Foundation/NSString.h" +#include "Foundation/NSException.h" +#include "Foundation/NSSet.h" + +/* User dictionary location */ +static NSString *GNU_UserDictionariesDir = @"Dictionaries"; + +// Function to create name for spell server.... +NSString* +GSSpellServerName(NSString *vendor, NSString *language) +{ + NSString *serverName = nil; + + if (language == nil || vendor == nil) + { + return nil; + } + + serverName = [[vendor stringByAppendingString: language] + stringByAppendingString: @"SpellChecker"]; + + return serverName; +} + +@implementation NSSpellServer + +// Class methods ++ (void) initialize +{ + if (self == [NSSpellServer class]) + { + // Initial version + [self setVersion: 1]; + } +} + +// Non-private Instance methods +- (id) init +{ + NSArray *userLanguages = [NSUserDefaults userLanguages]; + NSString *currentLanguage = [userLanguages objectAtIndex: 0]; + + if ((self = [super init]) != nil) + { + _delegate = nil; + _ignoredWords = nil; + ASSIGN(_userDictionaries, [NSMutableDictionary dictionary]); + ASSIGN(_currentLanguage, currentLanguage); + } + + return self; +} + +// Cleanup when deallocated +- (void) dealloc +{ + RELEASE(_userDictionaries); + RELEASE(_currentLanguage); + [super dealloc]; +} + +// Checking in Your Service + +/** + * This method vends the spell server to the Distributed Objects system + * so that it can be connected to by clients. + */ +- (BOOL) registerLanguage: (NSString *)language + byVendor: (NSString *)vendor +{ + NSString *serverName = GSSpellServerName(vendor, language); + NSConnection *connection = nil; + BOOL result = NO; + + if (serverName == nil) + { + return NO; + } + + connection = [[NSConnection alloc] init]; + if (connection) + { + RETAIN(connection); + [connection setRootObject: self]; + result = [connection registerName: serverName]; + } + + return result; +} + +// Assigning a Delegate + +/** + * Return the spell server delegate. + */ +- (id) delegate +{ + return _delegate; +} + +/** + * This method is used to set the delegate of the spellserver. + * When a spelling service is run the spell server is vended out + * to DO. The spelling service must instantiate an instance of + * this class and set itself to be the delegate. This allows + * the service to respond to messages sent by the client. + */ +- (void) setDelegate: (id)anObject +{ + /* FIXME - we should not retain the delegate ! */ + RETAIN(anObject); + ASSIGN(_delegate, anObject); +} + +// Running the Service +/** + * Initiate the run loop of this service. Once the spell server + * object is vended, this method is called so that the server can + * start responding to the messages sent by the client. These + * messages are passed on to the NSSpellServer instance's delegate. + */ +- (void) run +{ + // Start the runloop explicitly. + [[NSRunLoop currentRunLoop] run]; +} + +// Private method +// Determine the path to the dictionary +/** + * Path to the dictionary for the specified language. + */ +- (NSString *) _pathToDictionary: (NSString *)currentLanguage +{ + NSString *path = nil; + NSString *user_gsroot = nil; + + user_gsroot = [NSSearchPathForDirectoriesInDomains(NSUserDirectory, + NSUserDomainMask, YES) lastObject]; + + if (currentLanguage != nil) + { + NSString *dirPath = nil; + NSFileManager *mgr = [NSFileManager defaultManager]; + + // Build the path and try to get the dictionary + dirPath = [user_gsroot stringByAppendingPathComponent: GNU_UserDictionariesDir]; + path = [dirPath stringByAppendingPathComponent: currentLanguage]; + + if (![mgr fileExistsAtPath: path ]) + { + if ([mgr fileExistsAtPath: dirPath]) + { + // The directory exists create the file. + NSArray *emptyDict = [NSArray array]; + + if (![emptyDict writeToFile: path atomically: YES]) + { + NSLog(@"Failed to create %@",path); + path = nil; + } + } + else + { + // The directory does not exist create it. + if ([mgr createDirectoryAtPath: dirPath attributes: nil]) + { + // Directory created. Now create the empty file. + NSArray *emptyDict = [NSArray array]; + + if (![emptyDict writeToFile: path atomically: YES]) + { + NSLog(@"Failed to create %@",path); + path = nil; + } + } + else + { + NSLog(@"Failed to create %@",dirPath); + path = nil; + } + } + } + } + + return path; +} + +// Private method +/** Open up dictionary stored in the user's directory. */ +- (NSMutableSet *) _openUserDictionary: (NSString *)language +{ + NSString *path = nil; + NSMutableSet *words = nil; + + if ((words = [_userDictionaries objectForKey: language]) == nil) + { + if ((path = [self _pathToDictionary: language]) != nil) + { + NSArray *wordarray = [NSArray arrayWithContentsOfFile: path]; + if (wordarray == nil) + { + NSLog(@"Unable to load user dictionary from path %@",path); + } + else + { + words = [NSMutableSet setWithArray: wordarray]; + [_userDictionaries setObject: words forKey: language]; + } + } + else + { + NSLog(@"Unable to find user dictionary at: %@", path); + } + } + + // successful in opening the desired dictionary.. + return words; +} + +// Checking User Dictionaries +/** Check if word is in dict, flag determines if the search is case sensitive. */ +- (BOOL) _isWord: (NSString *)word + inDictionary: (NSSet *)dict + caseSensitive: (BOOL)flag +{ + BOOL result = NO; + NSString *dictWord = nil; + NSEnumerator *setEnumerator = nil; + + // Catch the odd cases before they start trouble later on... + if (word == nil || dict == nil) + { + return NO; // avoid checking, if NIL. + } + + if ([word length] == 0 || [dict count] == 0) + { + return NO; // avoid checking, if has no length. + } + + // Check the dictionary for the word... + setEnumerator = [dict objectEnumerator]; + while ((dictWord = [setEnumerator nextObject]) && result == NO) + { + // If the case is important then uppercase both strings + // and compare, otherwise do the comparison. + if (flag == NO) + { + NSString *upperWord = [word uppercaseString]; + NSString *upperDictWord = [dictWord uppercaseString]; + + result = [upperWord isEqualToString: upperDictWord]; + } + else + { + result = [word isEqualToString: dictWord]; + } + } + + if (result == NO && _ignoredWords) + { + NSEnumerator *arrayEnumerator = [_ignoredWords objectEnumerator]; + NSString *iword = nil; + + while ((iword = [arrayEnumerator nextObject]) && result == NO) + { + // If the case is important then uppercase both strings + // and compare, otherwise do the comparison. + if (flag == NO) + { + NSString *upperWord = [word uppercaseString]; + NSString *upperIWord = [iword uppercaseString]; + + result = [upperWord isEqualToString: upperIWord]; + } + else + { + result = [word isEqualToString: iword]; + } + } + } + + return result; +} + +// Checking User Dictionaries +/** +Checks to see if the word is in the user's dictionary. The user dictionary +is a set of words learned by the spell service for that particular user. +*/ +- (BOOL) isWordInUserDictionaries: (NSString *)word + caseSensitive: (BOOL)flag +{ + NSSet *userDict = [self _openUserDictionary: _currentLanguage]; + BOOL result = NO; + + if (userDict) + { + result = [self _isWord: word + inDictionary: userDict + caseSensitive: flag]; + } + + return result; +} + +/** Save the dictionary stored in user's directory. */ +- (BOOL) _saveUserDictionary: (NSString *)language +{ + NSString *path = nil; + + if ((path = [self _pathToDictionary: language]) != nil) + { + NSMutableSet *set = [_userDictionaries objectForKey: language]; + if (![[set allObjects] writeToFile: path atomically: YES]) + { + NSLog(@"Unable to save dictionary to path %@",path); + return NO; + } + } + else + { + NSLog(@"Unable to save dictionary at: %@", path); + return NO; + } + // successful in saving the desired dictionary.. + return YES; +} + +/** Learn a new word and put it into the dictionary. */ +- (BOOL) _learnWord: (NSString *)word + inDictionary: (NSString *)language +{ + NSMutableSet *set = [self _openUserDictionary: language]; + [set addObject: word]; + + NS_DURING + { + [_delegate spellServer: self + didLearnWord: word + inLanguage: language]; + } + NS_HANDLER + { + NSLog(@"Call to delegate cause the following exception: %@", + [localException reason]); + } + NS_ENDHANDLER + + return [self _saveUserDictionary: language]; +} + +/** Forget a word and remove it from the dictionary. */ +- (BOOL)_forgetWord: (NSString *)word + inDictionary: (NSString *)language +{ + NSMutableSet *set = [self _openUserDictionary: language]; + [set removeObject: word]; + + NS_DURING + { + [_delegate spellServer: self + didForgetWord: word + inLanguage: language]; + } + NS_HANDLER + { + NSLog(@"Call to delegate caused following exception: %@", + [localException reason]); + } + NS_ENDHANDLER + + return [self _saveUserDictionary: language]; +} + +/** Find a misspelled word. */ +- (NSRange) _findMisspelledWordInString: (NSString *)stringToCheck + language: (NSString *)language + ignoredWords: (NSArray *)ignoredWords + wordCount: (int *)wordCount + countOnly: (BOOL)countOnly +{ + NSRange r = NSMakeRange(0,0); + + // Forward to delegate + NS_DURING + { + ASSIGN(_ignoredWords,ignoredWords); + r = [_delegate spellServer: self + findMisspelledWordInString: stringToCheck + language: language + wordCount: wordCount + countOnly: countOnly]; + _ignoredWords = nil; + } + NS_HANDLER + { + NSLog(@"Call to delegate caused the following exception: %@", + [localException reason]); + } + NS_ENDHANDLER + + return r; +} + +/** Suggest a correction for the word. */ +- (NSArray *) _suggestGuessesForWord: (NSString *)word + inLanguage: (NSString *)language +{ + NSArray *words = nil; + + // Forward to delegate + NS_DURING + { + words = [_delegate spellServer: self + suggestGuessesForWord: word + inLanguage: language]; + } + NS_HANDLER + { + NSLog(@"Call to delegate caused the following exception: %@", + [localException reason]); + } + NS_ENDHANDLER + + return words; +} + +@end