From fc32db5a61f6e33a9fe10b01478d5041be6ec780 Mon Sep 17 00:00:00 2001 From: gcasa Date: Thu, 21 Jun 2001 01:05:11 +0000 Subject: [PATCH] Added NSSpellChecker, NSSpellServer implementation. Added stubbed out spell service and the GUI for the spell checker. git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/gui/trunk@10215 72102866-910b-0410-8b05-ffd578937521 --- Headers/gnustep/gui/NSSpellChecker.h | 38 +- Headers/gnustep/gui/NSSpellServer.h | 71 ++- Panels/GNUmakefile | 2 +- Panels/SpellPanel.gmodel | 810 +++++++++++++++++++++++++++ Source/NSSpellChecker.m | 589 ++++++++++++++++++- Source/NSSpellServer.m | 403 +++++++++++-- Tools/GNUmakefile | 4 +- Tools/GSspell.m | 104 ++++ Tools/GSspellInfo.plist | 8 + 9 files changed, 1918 insertions(+), 111 deletions(-) create mode 100644 Panels/SpellPanel.gmodel create mode 100644 Tools/GSspell.m create mode 100644 Tools/GSspellInfo.plist diff --git a/Headers/gnustep/gui/NSSpellChecker.h b/Headers/gnustep/gui/NSSpellChecker.h index e339400a3..d37e0d42e 100644 --- a/Headers/gnustep/gui/NSSpellChecker.h +++ b/Headers/gnustep/gui/NSSpellChecker.h @@ -3,11 +3,14 @@ Class which is interface to spell-checking service - Copyright (C) 1996 Free Software Foundation, Inc. + Copyright (C) 1996, 2001 Free Software Foundation, Inc. - Author: Scott Christley + Author: Gregory John Casamento + Date: 2001 + + Author: Scott Christley Date: 1996 - + This file is part of the GNUstep GUI Library. This library is free software; you can redistribute it and/or @@ -32,14 +35,40 @@ #include #include +@class NSProxy; @class NSString; @class NSArray; @class NSView; @class NSPanel; +@class NSDictionary; +@class NSMutableDictionary; @interface NSSpellChecker : NSObject { - // Attributes +@private + /* Non-GUI attributes */ + id _serverProxy; + NSString *_language; + NSMutableDictionary *_ignoredWords; + + // Variables to keep state... + int _position; + int _currentTag; + BOOL _wrapFlag; + + // GUI ... + id _wordField; + id _accessoryView; + id _dictionaryPulldown; + id _spellPanel; + + // Buttons... (so we can enable/disable, if necessary) + id _learnButton; + id _forgetButton; + id _ignoreButton; + id _guessButton; + id _findNextButton; + id _correctButton; } // @@ -89,6 +118,5 @@ - (void)updateSpellingPanelWithMisspelledWord:(NSString *)word; @end - #endif // _GNUstep_H_NSSpellChecker diff --git a/Headers/gnustep/gui/NSSpellServer.h b/Headers/gnustep/gui/NSSpellServer.h index e98fed5e7..54b998b7e 100644 --- a/Headers/gnustep/gui/NSSpellServer.h +++ b/Headers/gnustep/gui/NSSpellServer.h @@ -5,7 +5,10 @@ Copyright (C) 1996 Free Software Foundation, Inc. - Author: Scott Christley + Author: Gregory John Casamento + Date: 2000 + + Author of previous version: Scott Christley Date: 1996 This file is part of the GNUstep GUI Library. @@ -30,55 +33,61 @@ #define _GNUstep_H_NSSpellServer #include -#include +#include + +// Forward declarations +@class NSConnection; +@class NSMutableArray; +@class NSMutableDictionary; @interface NSSpellServer : NSObject - { - // Attributes +@private + id _delegate; + BOOL _caseSensitive; + NSMutableDictionary *_userDictionaries; } -// // 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; - -// -// Methods Implemented by the Delegate -// -- (NSRange)spellServer:(NSSpellServer *)sender -findMisspelledWordInString:(NSString *)stringToCheck -language:(NSString *)language -wordCount:(int *)wordCount -countOnly:(BOOL)countOnly; -- (NSArray *)spellServer:(NSSpellServer *)sender - suggestGuessesForWord:(NSString *)word -inLanguage:(NSString *)language; -- (void)spellServer:(NSSpellServer *)sender - didLearnWord:(NSString *)word -inLanguage:(NSString *)language; -- (void)spellServer:(NSSpellServer *)sender - didForgetWord:(NSString *)word -inLanguage:(NSString *)language; - @end +// +// NOTE: This is an informal protocol since the +// NSSpellChecker will need to use a proxy object +// to call these methods. If they are defined on +// NSObject, then the compiler won't complain +// about not being able to find the method. (GJC) +// +@interface NSObject (NSSpellServerDelegate) +- (NSRange)spellServer:(NSSpellServer *)sender +findMisspelledWordInString:(NSString *)stringToCheck + language:(NSString *)language + wordCount:(int *)wordCount + countOnly:(BOOL)countOnly; + +- (NSArray *)spellServer:(NSSpellServer *)sender + suggestGuessesForWord:(NSString *)word + inLanguage:(NSString *)language; + +- (void)spellServer:(NSSpellServer *)sender + didLearnWord:(NSString *)word + inLanguage:(NSString *)language; + +- (void)spellServer:(NSSpellServer *)sender + didForgetWord:(NSString *)word + inLanguage:(NSString *)language; +@end #endif // _GNUstep_H_NSSpellServer diff --git a/Panels/GNUmakefile b/Panels/GNUmakefile index 0d2b27a3b..917070245 100644 --- a/Panels/GNUmakefile +++ b/Panels/GNUmakefile @@ -35,7 +35,7 @@ include $(GNUSTEP_MAKEFILES)/common.make include ../Version -PANELS = ColorPanel.gmodel SavePanel.gmodel +PANELS = ColorPanel.gmodel SavePanel.gmodel SpellPanel.gmodel -include GNUmakefile.preamble -include GNUmakefile.local diff --git a/Panels/SpellPanel.gmodel b/Panels/SpellPanel.gmodel new file mode 100644 index 000000000..6e61285c0 --- /dev/null +++ b/Panels/SpellPanel.gmodel @@ -0,0 +1,810 @@ +{ + "Object 1" = {elements = ("Object 2"); isa = NSMutableArray; }; + "Object 2" = { + className = NSSpellChecker; + isa = IMCustomObject; + realObject = "Object 3"; + }; + "Object 3" = { + delegate = nil; + isa = NSApplication; + keyWindow = nil; + mainMenu = nil; + mainWindow = nil; + windows = "Object 4"; + }; + "Object 4" = { + elements = ("Object 5", "Object 9", "Object 11"); + isa = NSMutableArray; + }; + "Object 5" = { + backgroundColor = "Object 8"; + backingType = 0; + contentFrame = "{x=0.000000; y=0.000000; width=256.000000; height=128.000000}"; + contentView = "Object 6"; + frameAutosaveName = nil; + hidesOnDeactivate = NO; + initialFirstResponder = nil; + isAutodisplay = NO; + isReleasedWhenClosed = NO; + isVisible = NO; + isa = NSWindow; + level = 0; + maxSize = "{width=340282346638528860000000000000000000000.000000; height=340282346638528860000000000000000000000.000000}"; + minSize = "{width=0.000000; height=0.000000}"; + representedFilename = ""; + styleMask = 0; + title = ""; + }; + "Object 6" = { + autoresizesSubviews = YES; + autoresizingMask = 0; + bounds = "{x=0.000000; y=0.000000; width=256.000000; height=128.000000}"; + frame = "{x=0.000000; y=0.000000; width=256.000000; height=128.000000}"; + interfaceStyle = 0; + isa = NSView; + nextKeyView = nil; + nextResponder = "Object 5"; + postsBoundsChangedNotifications = YES; + postsFrameChangedNotifications = YES; + previousKeyView = nil; + subviews = "Object 7"; + superview = nil; + }; + "Object 7" = {elements = (); isa = NSMutableArray; }; + "Object 8" = { + alpha = 1.000000; + blue = 0.666667; + brightness = 0.666667; + colorSpaceName = NSCalibratedRGBColorSpace; + green = 0.666667; + hue = 0.000000; + isa = NSColor; + red = 0.666667; + saturation = 0.000000; + }; + "Object 9" = { + backgroundColor = "Object 8"; + backingType = 0; + contentFrame = "{x=0.000000; y=0.000000; width=193.000000; height=208.000000}"; + contentView = "Object 10"; + frameAutosaveName = nil; + hidesOnDeactivate = NO; + initialFirstResponder = nil; + isAutodisplay = NO; + isReleasedWhenClosed = NO; + isVisible = NO; + isa = NSWindow; + level = 0; + maxSize = "{width=340282346638528860000000000000000000000.000000; height=340282346638528860000000000000000000000.000000}"; + minSize = "{width=0.000000; height=0.000000}"; + representedFilename = ""; + styleMask = 0; + title = ""; + }; + "Object 10" = { + autoresizesSubviews = YES; + autoresizingMask = 0; + bounds = "{x=0.000000; y=0.000000; width=193.000000; height=208.000000}"; + frame = "{x=0.000000; y=0.000000; width=193.000000; height=208.000000}"; + interfaceStyle = 0; + isa = NSView; + nextKeyView = nil; + nextResponder = "Object 9"; + postsBoundsChangedNotifications = YES; + postsFrameChangedNotifications = YES; + previousKeyView = nil; + subviews = "Object 7"; + superview = nil; + }; + "Object 11" = { + backgroundColor = "Object 8"; + backingType = 2; + becomesKeyOnlyIfNeeded = NO; + contentFrame = "{x=428.000000; y=164.000000; width=186.000000; height=304.000000}"; + contentView = "Object 12"; + frameAutosaveName = nil; + hidesOnDeactivate = NO; + initialFirstResponder = nil; + isAutodisplay = YES; + isFloatingPanel = NO; + isReleasedWhenClosed = NO; + isVisible = NO; + isa = NSPanel; + level = 0; + maxSize = "{width=340282346638528860000000000000000000000.000000; height=340282346638528860000000000000000000000.000000}"; + minSize = "{width=0.000000; height=0.000000}"; + representedFilename = ""; + styleMask = 10; + title = Spelling; + worksWhenModal = NO; + }; + "Object 12" = { + autoresizesSubviews = YES; + autoresizingMask = 0; + bounds = "{x=0.000000; y=0.000000; width=186.000000; height=304.000000}"; + frame = "{x=1.000000; y=9.000000; width=186.000000; height=304.000000}"; + interfaceStyle = 0; + isa = NSView; + nextKeyView = nil; + nextResponder = "Object 11"; + postsBoundsChangedNotifications = YES; + postsFrameChangedNotifications = YES; + previousKeyView = nil; + subviews = "Object 13"; + superview = nil; + }; + "Object 13" = { + elements = ( + "Object 14", + "Object 17", + "Object 19", + "Object 21", + "Object 22", + "Object 24", + "Object 34" + ); + isa = NSMutableArray; + }; + "Object 14" = { + autoresizesSubviews = NO; + autoresizingMask = 38; + bounds = "{x=0.000000; y=0.000000; width=72.000000; height=24.000000}"; + cell = "Object 15"; + frame = "{x=16.000000; y=40.000000; width=72.000000; height=24.000000}"; + ignoresMultiClick = NO; + interfaceStyle = 0; + isEnabled = YES; + isa = NSButton; + nextKeyView = nil; + nextResponder = "Object 12"; + postsBoundsChangedNotifications = YES; + postsFrameChangedNotifications = YES; + previousKeyView = nil; + subviews = "Object 7"; + superview = "Object 12"; + tag = 0; + }; + "Object 15" = { + action = nil; + alignment = 2; + alternateImage = nil; + alternateTitle = ""; + delay = 0.200000; + entryType = 0; + font = "Object 16"; + highlightsBy = 14; + image = nil; + imagePosition = 0; + interval = 0.025000; + isBezeled = NO; + isBordered = YES; + isContinuous = NO; + isEditable = NO; + isEnabled = YES; + isScrollable = NO; + isSelectable = NO; + isTransparent = NO; + isa = NSButtonCell; + keyEquivalent = ""; + keyEquivalentFont = "Object 16"; + keyEquivalentModifierMask = 0; + sendActionMask = 0; + showsStateBy = 0; + state = 0; + stringValue = 0; + tag = 0; + target = nil; + title = Ignore; + type = 1; + wraps = YES; + }; + "Object 16" = {isa = NSFont; name = Helvetica; size = 12.000000; }; + "Object 17" = { + autoresizesSubviews = NO; + autoresizingMask = 35; + bounds = "{x=0.000000; y=0.000000; width=72.000000; height=24.000000}"; + cell = "Object 18"; + frame = "{x=96.000000; y=40.000000; width=72.000000; height=24.000000}"; + ignoresMultiClick = NO; + interfaceStyle = 0; + isEnabled = YES; + isa = NSButton; + nextKeyView = nil; + nextResponder = "Object 12"; + postsBoundsChangedNotifications = YES; + postsFrameChangedNotifications = YES; + previousKeyView = nil; + subviews = "Object 7"; + superview = "Object 12"; + tag = 0; + }; + "Object 18" = { + action = nil; + alignment = 2; + alternateImage = nil; + alternateTitle = ""; + delay = 0.200000; + entryType = 0; + font = "Object 16"; + highlightsBy = 14; + image = nil; + imagePosition = 0; + interval = 0.025000; + isBezeled = NO; + isBordered = YES; + isContinuous = NO; + isEditable = NO; + isEnabled = YES; + isScrollable = NO; + isSelectable = NO; + isTransparent = NO; + isa = NSButtonCell; + keyEquivalent = ""; + keyEquivalentFont = "Object 16"; + keyEquivalentModifierMask = 0; + sendActionMask = 0; + showsStateBy = 0; + state = 0; + stringValue = 0; + tag = 0; + target = nil; + title = Guess; + type = 1; + wraps = YES; + }; + "Object 19" = { + autoresizesSubviews = NO; + autoresizingMask = 35; + bounds = "{x=0.000000; y=0.000000; width=72.000000; height=24.000000}"; + cell = "Object 20"; + frame = "{x=96.000000; y=8.000000; width=72.000000; height=24.000000}"; + ignoresMultiClick = NO; + interfaceStyle = 0; + isEnabled = YES; + isa = NSButton; + nextKeyView = nil; + nextResponder = "Object 12"; + postsBoundsChangedNotifications = YES; + postsFrameChangedNotifications = YES; + previousKeyView = nil; + subviews = "Object 7"; + superview = "Object 12"; + tag = 0; + }; + "Object 20" = { + action = nil; + alignment = 2; + alternateImage = nil; + alternateTitle = ""; + delay = 0.200000; + entryType = 0; + font = "Object 16"; + highlightsBy = 14; + image = nil; + imagePosition = 0; + interval = 0.025000; + isBezeled = NO; + isBordered = YES; + isContinuous = NO; + isEditable = NO; + isEnabled = YES; + isScrollable = NO; + isSelectable = NO; + isTransparent = NO; + isa = NSButtonCell; + keyEquivalent = ""; + keyEquivalentFont = "Object 16"; + keyEquivalentModifierMask = 0; + sendActionMask = 0; + showsStateBy = 0; + state = 0; + stringValue = 0; + tag = 0; + target = nil; + title = Correct; + type = 1; + wraps = YES; + }; + "Object 21" = { + acceptsArrowKeys = NO; + allowsBranchSelection = NO; + allowsEmptySelection = YES; + allowsMultipleSelection = NO; + autoresizesSubviews = NO; + autoresizingMask = 18; + bounds = "{x=0.000000; y=0.000000; width=152.000000; height=113.000000}"; + cell = nil; + delegate = nil; + doubleAction = nil; + frame = "{x=16.000000; y=96.000000; width=152.000000; height=113.000000}"; + hasHorizontalScroller = NO; + ignoresMultiClick = NO; + interfaceStyle = 0; + isEnabled = YES; + isTitled = YES; + isa = NSBrowser; + maxVisibleColumns = 1; + minColumnWidth = 1; + nextKeyView = nil; + nextResponder = "Object 12"; + path = ""; + pathSeparator = /; + postsBoundsChangedNotifications = YES; + postsFrameChangedNotifications = YES; + previousKeyView = nil; + reusesColumns = NO; + sendsActionOnArrowKeys = NO; + separatesColumns = YES; + subviews = "Object 7"; + superview = "Object 12"; + tag = 0; + takesTitleFromPreviousColumn = YES; + }; + "Object 22" = { + autoresizesSubviews = NO; + autoresizingMask = 38; + bounds = "{x=0.000000; y=0.000000; width=72.000000; height=24.000000}"; + cell = "Object 23"; + frame = "{x=16.000000; y=8.000000; width=72.000000; height=24.000000}"; + ignoresMultiClick = NO; + interfaceStyle = 0; + isEnabled = YES; + isa = NSButton; + nextKeyView = nil; + nextResponder = "Object 12"; + postsBoundsChangedNotifications = YES; + postsFrameChangedNotifications = YES; + previousKeyView = nil; + subviews = "Object 7"; + superview = "Object 12"; + tag = 0; + }; + "Object 23" = { + action = nil; + alignment = 2; + alternateImage = nil; + alternateTitle = ""; + delay = 0.200000; + entryType = 0; + font = "Object 16"; + highlightsBy = 14; + image = nil; + imagePosition = 0; + interval = 0.025000; + isBezeled = NO; + isBordered = YES; + isContinuous = NO; + isEditable = NO; + isEnabled = YES; + isScrollable = NO; + isSelectable = NO; + isTransparent = NO; + isa = NSButtonCell; + keyEquivalent = ""; + keyEquivalentFont = "Object 16"; + keyEquivalentModifierMask = 0; + sendActionMask = 0; + showsStateBy = 0; + state = 0; + stringValue = 0; + tag = 0; + target = nil; + title = "Find Next"; + type = 1; + wraps = YES; + }; + "Object 24" = { + autoresizesSubviews = NO; + autoresizingMask = 10; + borderType = 3; + bounds = "{x=0.000000; y=0.000000; width=152.000000; height=89.000000}"; + contentView = "Object 26"; + contentViewMargins = "{width=5.000000; height=5.000000}"; + frame = "{x=16.000000; y=216.000000; width=152.000000; height=89.000000}"; + interfaceStyle = 0; + isa = NSBox; + nextKeyView = nil; + nextResponder = "Object 12"; + postsBoundsChangedNotifications = YES; + postsFrameChangedNotifications = YES; + previousKeyView = nil; + subviews = "Object 25"; + superview = "Object 12"; + title = Dictionary; + titleFont = "Object 16"; + titlePosition = 2; + }; + "Object 25" = {elements = ("Object 26"); isa = NSMutableArray; }; + "Object 26" = { + autoresizesSubviews = YES; + autoresizingMask = 0; + bounds = "{x=0.000000; y=0.000000; width=138.000000; height=66.000000}"; + frame = "{x=7.000000; y=7.000000; width=138.000000; height=66.000000}"; + interfaceStyle = 0; + isa = NSView; + nextKeyView = nil; + nextResponder = "Object 24"; + postsBoundsChangedNotifications = YES; + postsFrameChangedNotifications = YES; + previousKeyView = nil; + subviews = "Object 27"; + superview = "Object 24"; + }; + "Object 27" = { + elements = ("Object 28", "Object 30", "Object 32"); + isa = NSMutableArray; + }; + "Object 28" = { + autoresizesSubviews = NO; + autoresizingMask = 35; + bounds = "{x=0.000000; y=0.000000; width=64.000000; height=24.000000}"; + cell = "Object 29"; + frame = "{x=72.000000; y=0.000000; width=64.000000; height=24.000000}"; + ignoresMultiClick = NO; + interfaceStyle = 0; + isEnabled = YES; + isa = NSButton; + nextKeyView = nil; + nextResponder = "Object 26"; + postsBoundsChangedNotifications = YES; + postsFrameChangedNotifications = YES; + previousKeyView = nil; + subviews = "Object 7"; + superview = "Object 26"; + tag = 0; + }; + "Object 29" = { + action = nil; + alignment = 2; + alternateImage = nil; + alternateTitle = ""; + delay = 0.200000; + entryType = 0; + font = "Object 16"; + highlightsBy = 14; + image = nil; + imagePosition = 0; + interval = 0.025000; + isBezeled = NO; + isBordered = YES; + isContinuous = NO; + isEditable = NO; + isEnabled = YES; + isScrollable = NO; + isSelectable = NO; + isTransparent = NO; + isa = NSButtonCell; + keyEquivalent = ""; + keyEquivalentFont = "Object 16"; + keyEquivalentModifierMask = 0; + sendActionMask = 0; + showsStateBy = 0; + state = 0; + stringValue = 0; + tag = 0; + target = nil; + title = Forget; + type = 1; + wraps = YES; + }; + "Object 30" = { + autoresizesSubviews = NO; + autoresizingMask = 38; + bounds = "{x=0.000000; y=0.000000; width=64.000000; height=24.000000}"; + cell = "Object 31"; + frame = "{x=0.000000; y=0.000000; width=64.000000; height=24.000000}"; + ignoresMultiClick = NO; + interfaceStyle = 0; + isEnabled = YES; + isa = NSButton; + nextKeyView = nil; + nextResponder = "Object 26"; + postsBoundsChangedNotifications = YES; + postsFrameChangedNotifications = YES; + previousKeyView = nil; + subviews = "Object 7"; + superview = "Object 26"; + tag = 0; + }; + "Object 31" = { + action = nil; + alignment = 2; + alternateImage = nil; + alternateTitle = ""; + delay = 0.200000; + entryType = 0; + font = "Object 16"; + highlightsBy = 14; + image = nil; + imagePosition = 0; + interval = 0.025000; + isBezeled = NO; + isBordered = YES; + isContinuous = NO; + isEditable = NO; + isEnabled = YES; + isScrollable = NO; + isSelectable = NO; + isTransparent = NO; + isa = NSButtonCell; + keyEquivalent = ""; + keyEquivalentFont = "Object 16"; + keyEquivalentModifierMask = 0; + sendActionMask = 0; + showsStateBy = 0; + state = 0; + stringValue = 0; + tag = 0; + target = nil; + title = Learn; + type = 1; + wraps = YES; + }; + "Object 32" = { + action = nil; + autoresizingMask = 2; + frame = "{x=0.000000; y=32.000000; width=136.000000; height=22.000000}"; + isEnabled = YES; + isa = NSPopUpButton; + itemArray = ("Object 33"); + pullsDown = NO; + tag = 0; + target = nil; + }; + "Object 33" = { + action = nil; + image = nil; + isEnabled = YES; + isa = NSMenuItem; + keyEquivalent = ""; + representedObject = nil; + state = 1; + tag = 0; + target = nil; + title = English; + }; + "Object 34" = { + autoresizesSubviews = NO; + autoresizingMask = 34; + bounds = "{x=0.000000; y=0.000000; width=152.000000; height=21.000000}"; + cell = "Object 35"; + delegate = nil; + errorAction = nil; + frame = "{x=16.000000; y=72.000000; width=152.000000; height=21.000000}"; + ignoresMultiClick = NO; + interfaceStyle = 0; + isEnabled = YES; + isa = NSTextField; + nextKeyView = nil; + nextResponder = "Object 12"; + postsBoundsChangedNotifications = YES; + postsFrameChangedNotifications = YES; + previousKeyView = nil; + subviews = "Object 7"; + superview = "Object 12"; + tag = 0; + }; + "Object 35" = { + action = nil; + alignment = 0; + backgroundColor = "Object 36"; + drawsBackground = YES; + entryType = 0; + font = "Object 16"; + image = nil; + isBezeled = YES; + isBordered = NO; + isContinuous = NO; + isEditable = YES; + isEnabled = YES; + isScrollable = YES; + isSelectable = YES; + isa = NSTextFieldCell; + sendActionMask = 0; + state = 1; + stringValue = ""; + tag = 0; + target = nil; + textColor = "Object 37"; + type = 1; + wraps = NO; + }; + "Object 36" = { + alpha = 1.000000; + blue = 1.000000; + brightness = 1.000000; + colorSpaceName = NSCalibratedRGBColorSpace; + green = 1.000000; + hue = 0.000000; + isa = NSColor; + red = 1.000000; + saturation = 0.000000; + }; + "Object 37" = { + alpha = 1.000000; + blue = 0.000000; + brightness = 0.000000; + colorSpaceName = NSCalibratedRGBColorSpace; + green = 0.000000; + hue = 0.000000; + isa = NSColor; + red = 0.000000; + saturation = 0.000000; + }; + "Object 38" = { + elements = ( + "Object 39", + "Object 41", + "Object 43", + "Object 45", + "Object 47", + "Object 49", + "Object 51", + "Object 53", + "Object 55", + "Object 57", + "Object 59", + "Object 61", + "Object 63", + "Object 65", + "Object 67", + "Object 69", + "Object 71", + "Object 73", + "Object 75", + "Object 77", + "Object 78" + ); + isa = NSMutableArray; + }; + "Object 39" = { + destination = "Object 2"; + isa = IMControlConnector; + label = "Object 40"; + source = "Object 28"; + }; + "Object 40" = {isa = NSString; string = "_forget:"; }; + "Object 41" = { + destination = "Object 2"; + isa = IMControlConnector; + label = "Object 42"; + source = "Object 30"; + }; + "Object 42" = {isa = NSString; string = "_learn:"; }; + "Object 43" = { + destination = "Object 2"; + isa = IMControlConnector; + label = "Object 44"; + source = "Object 17"; + }; + "Object 44" = {isa = NSString; string = "_guess:"; }; + "Object 45" = { + destination = "Object 2"; + isa = IMControlConnector; + label = "Object 46"; + source = "Object 22"; + }; + "Object 46" = {isa = NSString; string = "_findNext:"; }; + "Object 47" = { + destination = "Object 2"; + isa = IMControlConnector; + label = "Object 48"; + source = "Object 19"; + }; + "Object 48" = {isa = NSString; string = "_correct:"; }; + "Object 49" = { + destination = "Object 2"; + isa = IMControlConnector; + label = "Object 50"; + source = "Object 14"; + }; + "Object 50" = {isa = NSString; string = "_ignore:"; }; + "Object 51" = { + destination = "Object 21"; + isa = IMOutletConnector; + label = "Object 52"; + source = "Object 2"; + }; + "Object 52" = {isa = NSString; string = _accessoryView; }; + "Object 53" = { + destination = "Object 34"; + isa = IMOutletConnector; + label = "Object 54"; + source = "Object 2"; + }; + "Object 54" = {isa = NSString; string = _wordField; }; + "Object 55" = { + destination = "Object 11"; + isa = IMOutletConnector; + label = "Object 56"; + source = "Object 2"; + }; + "Object 56" = {isa = NSString; string = _spellPanel; }; + "Object 57" = { + destination = "Object 32"; + isa = IMOutletConnector; + label = "Object 58"; + source = "Object 2"; + }; + "Object 58" = {isa = NSString; string = _dictionaryPulldown; }; + "Object 59" = { + destination = "Object 2"; + isa = IMControlConnector; + label = "Object 60"; + source = "Object 32"; + }; + "Object 60" = {isa = NSString; string = "_switchDictionary:"; }; + "Object 61" = { + destination = "Object 2"; + isa = IMControlConnector; + label = "Object 62"; + source = "Object 21"; + }; + "Object 62" = {isa = NSString; string = "_highlightGuess:"; }; + "Object 63" = { + destination = "Object 2"; + isa = IMOutletConnector; + label = "Object 64"; + source = "Object 11"; + }; + "Object 64" = {isa = NSString; string = delegate; }; + "Object 65" = { + destination = "Object 30"; + isa = IMOutletConnector; + label = "Object 66"; + source = "Object 2"; + }; + "Object 66" = {isa = NSString; string = _learnButton; }; + "Object 67" = { + destination = "Object 28"; + isa = IMOutletConnector; + label = "Object 68"; + source = "Object 2"; + }; + "Object 68" = {isa = NSString; string = _forgetButton; }; + "Object 69" = { + destination = "Object 14"; + isa = IMOutletConnector; + label = "Object 70"; + source = "Object 2"; + }; + "Object 70" = {isa = NSString; string = _ignoreButton; }; + "Object 71" = { + destination = "Object 17"; + isa = IMOutletConnector; + label = "Object 72"; + source = "Object 2"; + }; + "Object 72" = {isa = NSString; string = _guessButton; }; + "Object 73" = { + destination = "Object 22"; + isa = IMOutletConnector; + label = "Object 74"; + source = "Object 2"; + }; + "Object 74" = {isa = NSString; string = _findNextButton; }; + "Object 75" = { + destination = "Object 19"; + isa = IMOutletConnector; + label = "Object 76"; + source = "Object 2"; + }; + "Object 76" = {isa = NSString; string = _correctButton; }; + "Object 77" = { + destination = "Object 2"; + isa = IMOutletConnector; + label = "Object 64"; + source = "Object 21"; + }; + "Object 78" = { + destination = "Object 19"; + isa = IMOutletConnector; + label = "Object 79"; + source = "Object 11"; + }; + "Object 79" = {isa = NSString; string = initialFirstResponder; }; + RootObject = {Connections = "Object 38"; Objects = "Object 1"; isa = GMModel; }; + TopLevelObjects = (RootObject); + Version = 1; +} diff --git a/Source/NSSpellChecker.m b/Source/NSSpellChecker.m index 0cee6c167..312a355ab 100644 --- a/Source/NSSpellChecker.m +++ b/Source/NSSpellChecker.m @@ -3,7 +3,10 @@ Description... - Copyright (C) 1996 Free Software Foundation, Inc. + Copyright (C) 1996, 2000 Free Software Foundation, Inc. + + Author: Gregory John Casamento + Date: 2000 Author: Scott Christley Date: 1996 @@ -27,10 +30,117 @@ */ #include +#include +#include +#include +#include +#include +#include +#include +#include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +// prototype for function to create name for server +NSString *GSSpellServerName(NSString *checkerDictionary, + NSString *language); + +// These are methods which we only want the NSSpellChecker to call. +// The protocol is defined here so that the outside world does not +// have access to these internal methods. +@protocol NSSpellServerPrivateProtocol +- (NSRange)_findMisspelledWordInString: (NSString *)stringToCheck + language: (NSString *)language + learnedDictionaries: (NSArray *)dictionaries + wordCount: (int *)wordCount + countOnly: (BOOL)countOnly; +-(BOOL)_learnWord: (NSString *)word + inDictionary: (NSString *)language; +-(BOOL)_forgetWord: (NSString *)word + inDictionary: (NSString *)language; +- (NSArray *)_suggestGuessesForWord: (NSString *)word + inLanguage: (NSString *)language; +@end + +// Methods needed to get the GSServicesManager +@interface NSApplication(NSSpellCheckerMethods) +- (GSServicesManager *)_listener; +@end + +@implementation NSApplication(NSSpellCheckerMethods) +- (GSServicesManager *)_listener +{ + return _listener; +} +@end + +// Methods in the GSServicesManager to launch the spell server. +@interface GSServicesManager(NSSpellCheckerMethods) +- (id)_launchSpellCheckerForLanguage: (NSString *)language; +- (NSArray *)_languagesForPopUpButton; +@end + +@implementation GSServicesManager(NSSpellCheckerMethods) +- (id)_launchSpellCheckerForLanguage: (NSString *)language +{ + id proxy = nil; + NSDictionary *spellCheckers = [allServices objectForKey: @"BySpell"]; + NSDictionary *checkerDictionary = [spellCheckers objectForKey: language]; + NSString *spellServicePath = [checkerDictionary objectForKey: @"ServicePath"]; + NSString *vendor = [checkerDictionary objectForKey: @"NSSpellChecker"]; + NSDate *finishBy; + + NSString *port = GSSpellServerName(vendor, language); + double seconds = 30.0; + + NSLog(@"Spell Checker Dictionary: %@", spellCheckers); + NSLog(@"Language: %@", language); + NSLog(@"Service to start: %@", spellServicePath); + NSLog(@"Port: %@",port); + + finishBy = [NSDate dateWithTimeIntervalSinceNow: seconds]; + proxy = GSContactApplication(spellServicePath, port, finishBy); + if (proxy == nil) + { + NSRunAlertPanel(nil, + [NSString stringWithFormat: + @"Failed to contact spell checker for language '%@'", language], + @"Continue", nil, nil); + } + else + { + NSLog(@"Set proxy"); + [(NSDistantObject *)proxy + setProtocolForProxy: @protocol(NSSpellServerPrivateProtocol)]; + } + + return proxy; +} + +- (NSArray *)_languagesForPopUpButton +{ + NSDictionary *spellCheckers = [allServices objectForKey: @"BySpell"]; + NSArray *allKeys = [spellCheckers allKeys]; + + return allKeys; +} +@end + +// Shared spell checker instance.... +static NSSpellChecker *__sharedSpellChecker = nil; +static int __documentTag = 0; + +// Implementation of spell checker class @implementation NSSpellChecker - // // Class methods // @@ -48,12 +158,19 @@ // + (NSSpellChecker *)sharedSpellChecker { - return nil; + // Create the shared instance. + if(__sharedSpellChecker == nil) + { + __sharedSpellChecker = [[NSSpellChecker alloc] init]; + } + return __sharedSpellChecker; } + (BOOL)sharedSpellCheckerExists { - return NO; + // If the spell checker has been created, the + // variable will not be nil. + return (__sharedSpellChecker != nil); } // @@ -61,53 +178,232 @@ // + (int)uniqueSpellDocumentTag { - return 0; + NSLog(@"returning unique spell document tag"); + return ++__documentTag; +} + +// +// Internal methods for use by the spellChecker GUI +// +- (void)_populateDictionaryPulldown: (NSArray *)dictionaries; +{ + [_dictionaryPulldown removeAllItems]; + [_dictionaryPulldown addItemsWithTitles: dictionaries]; + [_dictionaryPulldown selectItemWithTitle: _language]; +} + +- (void)_populateAccessoryView: (NSArray *)words +{ + NSLog(@"Populate accessory view.......... %@", words); +} + +- (void)_handleServerDeath: (NSNotification *)notification +{ + NSLog(@"Spell server died"); + RELEASE(_serverProxy); + _serverProxy = nil; +} + +// Support function to start the spell server +- (id)_startServerForLanguage: (NSString *)language +{ + id proxy = nil; + // Start the service for this language + proxy = [[NSApp _listener] _launchSpellCheckerForLanguage: language]; + + if(proxy == nil) + { + NSLog(@"Failed to get the spellserver"); + return nil; + } + + // Retain the proxy, if we got the connection. + // Also make sure that we handle the death of the server + // correctly. + [[NSNotificationCenter defaultCenter] + addObserver: self + selector: @selector(_handleServerDeath:) + name: NSConnectionDidDieNotification + object: [(NSDistantObject *)proxy connectionForProxy]]; + + return proxy; +} + +- (id)_serverProxy +{ + if(_serverProxy == nil) + { + id proxy = [self _startServerForLanguage: _language]; + if(proxy != nil) + { + _serverProxy = proxy; + RETAIN(_serverProxy); + } + } + return _serverProxy; } // // Instance methods // +- init +{ + NSArray *userLanguages = [NSUserDefaults userLanguages]; + + // Set the language to the default for the user. + [super init]; + _language = [userLanguages objectAtIndex: 0]; + _wrapFlag = NO; + _position = 0; + _spellPanel = nil; + _serverProxy = nil; + _currentTag = 0; + _ignoredWords = [NSMutableDictionary dictionary]; + + // Start the server and retain the reference to the + // proxy. + [self _serverProxy]; + RETAIN(_ignoredWords); + + // Load the gmodel file + if(![GMModel loadIMFile: @"SpellPanel" + owner: self]) + { + NSLog(@"NIB file load failed for SpellPanel"); + return nil; + } + + + return self; +} + +- (void)dealloc +{ + RELEASE(_ignoredWords); + RELEASE(_serverProxy); +} + // // Managing the Spelling Panel // - (NSView *)accessoryView { - return nil; + return _accessoryView; } - (void)setAccessoryView:(NSView *)aView -{} +{ + _accessoryView = aView; +} - (NSPanel *)spellingPanel { - return nil; + return _spellPanel; } + // // Checking Spelling // - (int)countWordsInString:(NSString *)aString language:(NSString *)language { - return 0; + int count = 0; + NSRange r = NSMakeRange(0,0); + r = [[self _serverProxy] _findMisspelledWordInString: aString + language: _language + learnedDictionaries: nil + wordCount: &count + countOnly: YES]; + + return count; } - (NSRange)checkSpellingOfString:(NSString *)stringToCheck startingAt:(int)startingOffset { - NSRange r; + int wordCount = 0; + NSRange r = NSMakeRange(0,0); + + r = [self checkSpellingOfString: stringToCheck + startingAt: startingOffset + language: _language + wrap: NO + inSpellDocumentWithTag: 0 + wordCount: &wordCount]; return r; } - (NSRange)checkSpellingOfString:(NSString *)stringToCheck startingAt:(int)startingOffset -language:(NSString *)language - wrap:(BOOL)wrapFlag -inSpellDocumentWithTag:(int)tag - wordCount:(int *)wordCount + language:(NSString *)language + wrap:(BOOL)wrapFlag + inSpellDocumentWithTag:(int)tag + wordCount:(int *)wordCount { - NSRange r; + NSRange r = NSMakeRange(0,0); + NSString *misspelledWord = nil; + NSArray *dictForTag = [self ignoredWordsInSpellDocumentWithTag: tag], + *suggestedWords = nil; + + _currentTag = tag; + // We have no string to work with + if(stringToCheck == nil) + { + return NSMakeRange(0,0); + } + else + // The string is zero length + if([stringToCheck length] == 0) + { + return NSMakeRange(0,0); + } + + // Do this in an exception handling block in ensure that a failure of the + // spellserver does not bring down the application. + NS_DURING + { + // Get the substring and check it. + NSString *substringToCheck = [stringToCheck substringFromIndex: startingOffset]; + r = [[self _serverProxy] _findMisspelledWordInString: substringToCheck + language: _language + learnedDictionaries: dictForTag + wordCount: wordCount + countOnly: NO]; + + if(r.length != 0) + { + // Adjust results relative to the original string + r.location += startingOffset; + } + else + { + if(wrapFlag) + { + // Check the second half of the string + NSString *firstHalfOfString = [stringToCheck + substringToIndex: startingOffset]; + r = [[self _serverProxy] _findMisspelledWordInString: firstHalfOfString + language: _language + learnedDictionaries: dictForTag + wordCount: wordCount + countOnly: NO]; + } + } + + misspelledWord = [stringToCheck substringFromRange: r]; + suggestedWords = [[self _serverProxy] _suggestGuessesForWord: misspelledWord + inLanguage: _language]; + } + NS_HANDLER + { + NSLog(@"%@",[localException reason]); + } + NS_ENDHANDLER + + [self updateSpellingPanelWithMisspelledWord: misspelledWord]; + [self _populateAccessoryView: suggestedWords]; return r; } @@ -117,37 +413,274 @@ inSpellDocumentWithTag:(int)tag // - (NSString *)language { - return nil; + return _language; } - (BOOL)setLanguage:(NSString *)aLanguage { - return NO; + int index = 0; + BOOL result = NO; + + index = [_dictionaryPulldown indexOfItemWithTitle: aLanguage]; + if(index != -1) + { + [_dictionaryPulldown selectItemAtIndex: index]; + result = YES; + } + + return result; } // // Managing the Spelling Process // + +// Remove the ignored word list for this +// document from the dictionary - (void)closeSpellDocumentWithTag:(int)tag -{} - -- (void)ignoreWord:(NSString *)wordToIgnore -inSpellDocumentWithTag:(int)tag -{} - -- (NSArray *)ignoredWordsInSpellDocumentWithTag:(int)tag { - return nil; + NSNumber *key = [NSNumber numberWithInt: tag]; + [_ignoredWords removeObjectForKey: key]; } +// Add a word to the ignored list. +- (void) ignoreWord:(NSString *)wordToIgnore +inSpellDocumentWithTag:(int)tag +{ + NSNumber *key = [NSNumber numberWithInt: tag]; + NSMutableSet *words = [_ignoredWords objectForKey: key]; + + NSLog(@"Ignore: %@",wordToIgnore); + if(![wordToIgnore isEqualToString: @""]) + { + // If there is a dictionary add to it, if not create one. + if(words == nil) + { + words = [NSMutableSet setWithObject: wordToIgnore]; + [_ignoredWords setObject: words forKey: key]; + } + else + { + [words addObject: wordToIgnore]; + } + } + NSLog(@"Words to ignore %@ for doc# %d", words, tag); + +} + +// get the list of ignored words. +- (NSArray *)ignoredWordsInSpellDocumentWithTag:(int)tag +{ + NSNumber *key = [NSNumber numberWithInt: tag]; + NSSet *words = [_ignoredWords objectForKey: key]; + return [words allObjects]; +} + +// set the list of ignored words for a given document - (void)setIgnoredWords:(NSArray *)someWords inSpellDocumentWithTag:(int)tag -{} +{ + NSNumber *key = [NSNumber numberWithInt: tag]; + NSSet *words = [NSSet setWithArray: someWords]; + [_ignoredWords setObject: words forKey: key]; +} - (void)setWordFieldStringValue:(NSString *)aString -{} +{ + [_wordField setStringValue: aString]; +} - (void)updateSpellingPanelWithMisspelledWord:(NSString *)word -{} +{ + [self setWordFieldStringValue: word]; +} +- _learn: (id)sender +{ + NSString *word = [_wordField stringValue]; + BOOL result = NO; + + // Call server and record the learned word. + NS_DURING + { + result = [[self _serverProxy] _learnWord: word + inDictionary: _language]; + } + NS_HANDLER + { + NSLog(@"%@",[localException reason]); + } + NS_ENDHANDLER + + return self; +} + +- _forget: (id)sender +{ + NSString *word = [_wordField stringValue]; + BOOL result = NO; + + // Call the server and remove the word from the learned + // list. + NS_DURING + { + result = [[self _serverProxy] _forgetWord: word + inDictionary: _language]; + } + NS_HANDLER + { + NSLog(@"%@",[localException reason]); + } + NS_ENDHANDLER + + return self; +} + +- _ignore: (id)sender +{ + BOOL processed = NO; + id responder = [[[[NSApplication sharedApplication] mainWindow] contentView] documentView]; + + processed = [responder tryToPerform: @selector(ignoreSpelling:) + with: _wordField]; + if(!processed) + { + NSLog(@"_ignore: No responder found"); + } + + return self; +} + +- _guess: (id)sender +{ + NSString *word = [_wordField stringValue]; + NSArray *guesses = nil; + + NS_DURING + { + guesses = [[self _serverProxy] _suggestGuessesForWord: word + inLanguage: _language]; + if(guesses == nil) + { + NSLog(@"Nil array returned from server"); + } + else + { + // Fill in the view... + [self _populateAccessoryView: guesses]; + } + } + NS_HANDLER + { + NSLog(@"%@",[localException reason]); + guesses = nil; + } + NS_ENDHANDLER + + return self; +} + +- _findNext: (id)sender +{ + BOOL processed = NO; + id responder = [[[[NSApplication sharedApplication] mainWindow] contentView] documentView]; + + processed = [responder tryToPerform: @selector(checkSpelling:) + with: _spellPanel]; + if(!processed) + { + NSLog(@"Call to checkSpelling failed. No responder found"); + } + + return self; +} + +- _correct: (id)sender +{ + BOOL processed = NO; + id responder = [[[[NSApplication sharedApplication] mainWindow] contentView] documentView]; + + processed = [responder tryToPerform: @selector(changeSpelling:) + with: _wordField]; + if(!processed) + { + NSLog(@"Call to changeSpelling failed. No responder found"); + } + + return self; +} + +- _switchDictionary: (id)sender +{ + id proxy = nil; + NSString *language = nil; + + // Start the service for this language + language = [_dictionaryPulldown stringValue]; + if(![language isEqualToString: _language]) + { + NSLog(@"Language = %@",language); + proxy = [self _startServerForLanguage: language]; + if(proxy != nil) + { + ASSIGN(_language, language); + RELEASE(_serverProxy); + _serverProxy = proxy; + RETAIN(_serverProxy); + } + else + { + // Reset the pulldown to the proper language. + [_dictionaryPulldown selectItemWithTitle: _language]; + } + } + + return self; +} + +-(void) awakeFromNib +{ + [self _populateDictionaryPulldown: + [[NSApp _listener] _languagesForPopUpButton]]; + [_accessoryView setDelegate: self]; +} +@end + +@implementation NSSpellChecker(NSBrowserDelegate) +- (BOOL) browser: (NSBrowser*)sender + selectRow: (int)row + inColumn: (int)column +{ + return YES; +} + +- (void) browser: (NSBrowser *)sender +createRowsForColumn: (int)column + inMatrix: (NSMatrix *)matrix +{ + NSLog(@"Create rows"); +} + +- (NSString*) browser: (NSBrowser*)sender + titleOfColumn: (int)column +{ + return @"Guess"; +} + +- (void) browser: (NSBrowser *)sender + willDisplayCell: (id)cell + atRow: (int)row + column: (int)column +{ + NSLog(@"reached 1...."); +} + +/* +- (BOOL) browser: (NSBrowser *)sender + isColumnValid: (int)column +{ + NSLog(@"reached 3...."); + return NO; +} +*/ @end diff --git a/Source/NSSpellServer.m b/Source/NSSpellServer.m index cf6f4c936..f8a2a819f 100644 --- a/Source/NSSpellServer.m +++ b/Source/NSSpellServer.m @@ -3,18 +3,22 @@ Description... + This class provides a + Copyright (C) 1996 Free Software Foundation, Inc. Author: Scott Christley Date: 1996 - + Rewritten by: Gregory Casamento + Date: 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 @@ -28,12 +32,40 @@ #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* 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]) @@ -43,73 +75,354 @@ } } -// -// Instance methods -// -// +// Non-private Instance methods +- init +{ + [super init]; + + _delegate = nil; + _userDictionaries = [NSMutableDictionary dictionary]; + + return self; +} + // Checking in Your Service -// - (BOOL)registerLanguage:(NSString *)language byVendor:(NSString *)vendor { - return NO; + NSString *serverName = GSSpellServerName(vendor, language); + NSConnection *connection = nil; + BOOL result = NO; + + if(serverName == nil) + { + return NO; + } + + connection = [[NSConnection alloc] init]; + if(connection) + { + NSLog(@"Connection created."); + RETAIN(connection); + [connection setRootObject: self]; + result = [connection registerName: serverName]; + if(result) NSLog(@"Registered: %@",serverName); + } + + return result; } -// // Assigning a Delegate -// - (id)delegate { - return nil; + return _delegate; } - (void)setDelegate:(id)anObject -{} +{ + RETAIN(anObject); + ASSIGN(_delegate, anObject); +} -// // Running the Service -// - (void)run -{} +{ + // Start the runloop explicitly. + [[NSRunLoop currentRunLoop] run]; +} -// -// Checking User Dictionaries -// +// Private method +// Determine the path to the dictionary +- (NSString *)_pathToDictionary: (NSString *)currentLanguage +{ + NSString *path = nil; + NSString *user_gsroot = nil; + NSDictionary *env = nil; + + env = [[NSProcessInfo processInfo] environment]; + + user_gsroot = [env objectForKey: @"GNUSTEP_USER_ROOT"]; + 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; + } + } + } + } + + NSLog(@"Path = %@", path); + + 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); + } + } + else + { + NSLog(@"User dictionary for language %@ already opened.", + language); + } + + // successful in opening the desired dictionary.. + return words; +} + +// Checking User Dictionaries +- (BOOL)_isWord: (NSString *)word + inDictionary: (NSSet *)dict + caseSensitive: (BOOL)flag +{ + BOOL result = NO; + NSString *dictWord = nil; + NSEnumerator *setEnumerator = nil, *dictEnumerator = nil; + + NSLog(@"Searching user dictionary"); + // 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... + dictEnumerator = [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]; + } + } + + return result; +} + +// Checking User Dictionaries - (BOOL)isWordInUserDictionaries:(NSString *)word caseSensitive:(BOOL)flag { - return NO; + NSArray *userLanguages = [NSUserDefaults userLanguages]; + NSString *currentLanguage = [userLanguages objectAtIndex: 0]; + NSSet *userDict = [self _openUserDictionary: currentLanguage]; + BOOL result = NO; + + if(userDict) + { + result = [self _isWord: word + inDictionary: userDict + caseSensitive: flag]; + } + + return result; } -// -// Methods Implemented by the Delegate -// -- (NSRange)spellServer:(NSSpellServer *)sender -findMisspelledWordInString:(NSString *)stringToCheck -language:(NSString *)language -wordCount:(int *)wordCount -countOnly:(BOOL)countOnly +// Save the dictionary stored in user's directory. +- (BOOL)_saveUserDictionary: (NSString *)language { - NSRange r; + 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]; + NSLog(@"learnWord...."); + + NS_DURING + { + [_delegate spellServer: self + didLearnWord: word + inLanguage: language]; + } + NS_HANDLER + { + NSLog(@"Spell server delegate throw 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]; + NSLog(@"forgetWord...."); + [set removeObject: word]; + + NS_DURING + { + [_delegate spellServer: self + didForgetWord: word + inLanguage: language]; + } + NS_HANDLER + { + NSLog(@"Spell server delegate throw exception: %@", + [localException reason]); + } + NS_ENDHANDLER + + return [self _saveUserDictionary: language]; +} + +// Find a misspelled word +- (NSRange)_findMisspelledWordInString: (NSString *)stringToCheck + language: (NSString *)language + learnedDictionaries: (NSArray *)dictionaries + wordCount: (int *)wordCount + countOnly: (BOOL)countOnly +{ + NSRange r = NSMakeRange(0,0); + NSLog(@"In _findMispelledWorkInString:...."); + + NSLog(@"%@", _delegate); + + if(dictionaries != nil) + { + // Will put code here to check the user dictionary. + } + else + { + NSLog(@"No user dictionary to check"); + } + + // Forward to delegate + NS_DURING + { + r = [_delegate spellServer: self + findMisspelledWordInString: stringToCheck + language: language + wordCount: wordCount + countOnly: countOnly]; + } + NS_HANDLER + { + NSLog(@"Call to delegate caused the following exception: %@", + [localException reason]); + } + NS_ENDHANDLER return r; } -- (NSArray *)spellServer:(NSSpellServer *)sender - suggestGuessesForWord:(NSString *)word -inLanguage:(NSString *)language +- (NSArray *)_suggestGuessesForWord: (NSString *)word + inLanguage: (NSString *)language { - return nil; + NSArray *words = nil; + + NSLog(@"Entered suggestGuesses...."); + // 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; } - -- (void)spellServer:(NSSpellServer *)sender - didLearnWord:(NSString *)word -inLanguage:(NSString *)language -{} - -- (void)spellServer:(NSSpellServer *)sender - didForgetWord:(NSString *)word -inLanguage:(NSString *)language -{} - @end diff --git a/Tools/GNUmakefile b/Tools/GNUmakefile index b39e02eff..fb248a051 100644 --- a/Tools/GNUmakefile +++ b/Tools/GNUmakefile @@ -35,7 +35,7 @@ include $(GNUSTEP_MAKEFILES)/common.make include ../Version # The applications to be compiled TOOL_NAME = make_services set_show_service -SERVICE_NAME = example +SERVICE_NAME = example GSspell # The source files to be compiled gpbs_OBJC_FILES = gpbs.m Functions.m @@ -44,6 +44,8 @@ set_show_service_OBJC_FILES = set_show_service.m Functions.m example_OBJC_FILES = example.m Functions.m +GSspell_OBJC_FILES = GSspell.m + include GNUmakefile.preamble -include GNUmakefile.local diff --git a/Tools/GSspell.m b/Tools/GSspell.m new file mode 100644 index 000000000..b5fdb1579 --- /dev/null +++ b/Tools/GSspell.m @@ -0,0 +1,104 @@ +/* + GSspell.m + + GNUstep spell checker facility. + + Copyright (C) 2001 Free Software Foundation, Inc. + + Author: Gregory John Casamento + Date: May 2001 + + This file is part of the GNUstep Project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + You should have received a copy of the GNU 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 + +@interface GNUSpellChecker : NSObject +@end + +@implementation GNUSpellChecker +- (NSRange)spellServer:(NSSpellServer *)sender +findMisspelledWordInString:(NSString *)stringToCheck + language:(NSString *)language + wordCount:(int *)wordCount + countOnly:(BOOL)countOnly +{ + int length = 0; + NSRange r = NSMakeRange(0,0); + + NSLog(@"Stubbed out - Finding misspelled word"); + + length = [stringToCheck length]; + if(length < 10) + { + r.length = length; + } + else + { + r.length = 10; + } + + return r; +} + +- (NSArray *)spellServer:(NSSpellServer *)sender + suggestGuessesForWord:(NSString *)word + inLanguage:(NSString *)language +{ + NSArray *array = [NSArray arrayWithObjects: word, @"test", nil]; + + NSLog(@"Stubbed out - returning test guess results: %@", array); + + return array; +} + +- (void)spellServer:(NSSpellServer *)sender + didLearnWord:(NSString *)word + inLanguage:(NSString *)language +{ + NSLog(@"Stubbed out -- Learning word: %@", word); +} + +- (void)spellServer:(NSSpellServer *)sender + didForgetWord:(NSString *)word + inLanguage:(NSString *)language +{ + NSLog(@"Stubbed out -- Forgetting word: %@", word); +} +@end + +#ifdef GNUSTEP +int main(int argc, char** argv, char **env) +#else +int main(int argc, char** argv) +#endif +{ + CREATE_AUTORELEASE_POOL (_pool); + NSSpellServer *aServer = [[NSSpellServer alloc] init]; + if( [aServer registerLanguage: @"English" byVendor: @"GNU"] ) //&& + // [aServer registerLanguage: @"Spanish" byVendor: @"GNU"] && + // [aServer registerLanguage: @"French" byVendor: @"GNU"] ) + { + [aServer setDelegate: [[GNUSpellChecker alloc] init]]; + NSLog(@"Spell server started and waiting."); + [aServer run]; + NSLog(@"Unexpected death of spell checker"); + } + else + { + NSLog(@"Cannot create spell checker instance"); + } + RELEASE(_pool); + return 0; +} diff --git a/Tools/GSspellInfo.plist b/Tools/GSspellInfo.plist new file mode 100644 index 000000000..a4bc234f5 --- /dev/null +++ b/Tools/GSspellInfo.plist @@ -0,0 +1,8 @@ + NSServices = + ( + { + NSExecutable = GSspell; + NSLanguages = (English); + NSSpellChecker = GNU; + } + );