Componentes.Terceros.DevExp.../official/x.38/ExpressSpellChecker/Sources/dxSpellChecker.pas
2008-08-27 11:56:15 +00:00

4102 lines
124 KiB
ObjectPascal

{********************************************************************}
{ }
{ Developer Express Visual Component Library }
{ ExpressSpellChecker }
{ }
{ Copyright (c) 1998-2008 Developer Express Inc. }
{ ALL RIGHTS RESERVED }
{ }
{ The entire contents of this file is protected by U.S. and }
{ International Copyright Laws. Unauthorized reproduction, }
{ reverse-engineering, and distribution of all or any portion of }
{ the code contained in this file is strictly prohibited and may }
{ result in severe civil and criminal penalties and will be }
{ prosecuted to the maximum extent possible under the law. }
{ }
{ RESTRICTIONS }
{ }
{ THIS SOURCE CODE AND ALL RESULTING INTERMEDIATE FILES }
{ (DCU, OBJ, DLL, ETC.) ARE CONFIDENTIAL AND PROPRIETARY TRADE }
{ SECRETS OF DEVELOPER EXPRESS INC. THE REGISTERED DEVELOPER IS }
{ LICENSED TO DISTRIBUTE THE EXPRESSSPELLCHECKER AND ALL }
{ ACCOMPANYING VCL CONTROLS AS PART OF AN EXECUTABLE PROGRAM ONLY. }
{ }
{ THE SOURCE CODE CONTAINED WITHIN THIS FILE AND ALL RELATED }
{ FILES OR ANY PORTION OF ITS CONTENTS SHALL AT NO TIME BE }
{ COPIED, TRANSFERRED, SOLD, DISTRIBUTED, OR OTHERWISE MADE }
{ AVAILABLE TO OTHER INDIVIDUALS WITHOUT EXPRESS WRITTEN CONSENT }
{ AND PERMISSION FROM DEVELOPER EXPRESS INC. }
{ }
{ CONSULT THE END USER LICENSE AGREEMENT FOR INFORMATION ON }
{ ADDITIONAL RESTRICTIONS. }
{ }
{********************************************************************}
unit dxSpellChecker;
{$I cxVer.inc}
interface
uses
Types, Windows, SysUtils, Messages, Classes, Graphics, cxClasses, Controls,
Forms, StdCtrls, cxControls, dxSpellCheckerRules, dxSpellCheckerAlgorithms,
cxLookAndFeels, cxTextEdit, cxRichEdit, Menus;
type
TdxCustomSpellChecker = class;
TdxSpellCheckerWordList = class;
TdxSpellCheckerTextParser = class;
TdxCustomSpellCheckerDictionary = class;
TdxSpellCheckerSuggestionList = class;
TdxSpellCheckerSpellingOptions = class;
TdxSpellCheckerCheckAsYouTypeOptions = class;
EdxSpellCheckerException = class(Exception);
{ TdxSpellCheckerLanguages }
TdxSpellCheckerLanguages = class(TLanguages)
public
function GetDefaultLanguageLCID: DWORD;
function GetLCID(const AName: string): DWORD;
end;
{ TdxSpellCheckerSuggestion }
TdxSpellCheckerSuggestion = class
private
FDictionary: TdxCustomSpellCheckerDictionary;
FDistance: Integer;
FWord: WideString;
public
constructor Create(const AWord: WideString;
ADictionary: TdxCustomSpellCheckerDictionary; ADistance: Integer);
property Dictionary: TdxCustomSpellCheckerDictionary read FDictionary;
property Distance: Integer read FDistance;
property Word: WideString read FWord;
end;
{ TdxSpellCheckerSuggestionList }
TdxSpellCheckerSuggestionList = class(TcxObjectList)
private
function GetItem(Index: Integer): TdxSpellCheckerSuggestion;
public
procedure Add(const AWord: WideString;
ADictionary: TdxCustomSpellCheckerDictionary; ADistance: Integer);
procedure Delete(AIndex: Integer);
procedure FixCapitalization(const AMask: WideString);
procedure RemoveDuplicates;
procedure SortByWord;
procedure SortByDistance;
procedure SaveToStrings(AStrings: TStrings);
property Items[Index: Integer]: TdxSpellCheckerSuggestion read GetItem; default;
end;
{ TdxSpellCheckerReplacementItem }
TdxSpellCheckerReplacementItem = class
private
FReplacement: WideString;
FText: WideString;
public
constructor Create(const AText, AReplacement: WideString);
property Replacement: WideString read FReplacement;
property Text: WideString read FText;
end;
{ TdxSpellCheckerReplacementList }
TdxSpellCheckerReplacementList = class(TcxObjectList)
private
FAllowDuplicates: Boolean;
function GetItem(AIndex: Integer): TdxSpellCheckerReplacementItem;
public
constructor Create(AllowDuplicates: Boolean = False);
procedure Add(const AText, AReplacement: WideString);
function FindReplacement(const AText: WideString): TdxSpellCheckerReplacementItem;
procedure SortByText;
property Items[Index: Integer]: TdxSpellCheckerReplacementItem read GetItem; default;
end;
{ TdxSpellCheckerCustomEditAdapter }
TdxSpellCheckerCustomEditAdapter = class(TObject)
protected
FEdit: TWinControl;
FText: WideString;
FSelStart: Integer;
FSelLength: Integer;
function EditorHandleAllocated: Boolean;
function GetEditorHandle: THandle; virtual;
function GetHideSelection: Boolean; virtual; abstract;
function GetReadOnly: Boolean; virtual; abstract;
function GetSelLength: Integer; virtual; abstract;
function GetSelStart: Integer; virtual; abstract;
function GetSelText: string; virtual; abstract;
function GetText: WideString; virtual;
procedure Post(AUpdateValue: Boolean = True); virtual;
procedure SetHideSelection(AValue: Boolean); virtual; abstract;
procedure SetSelLength(AValue: Integer); virtual; abstract;
procedure SetSelStart(AValue: Integer); virtual; abstract;
procedure SetSelText(const AValue: string); virtual; abstract;
function IsInplace: Boolean;
public
constructor Create(AEdit: TWinControl); virtual;
procedure ClearSelection; virtual; abstract;
procedure GetSpellingBounds(out ASpellingStart, ASpellingEnd: Integer); virtual;
property EditorHandle: THandle read GetEditorHandle;
property HideSelection: Boolean read GetHideSelection write SetHideSelection;
property ReadOnly: Boolean read GetReadOnly;
property SelLength: Integer read GetSelLength write SetSelLength;
property SelStart: Integer read GetSelStart write SetSelStart;
property SelText: string read GetSelText write SetSelText;
property Text: WideString read GetText;
end;
{ TdxSpellCheckercxTextEditAdapter }
TdxSpellCheckercxTextEditAdapter = class(TdxSpellCheckerCustomEditAdapter)
private
function GetEdit: TcxCustomTextEdit;
protected
function GetHideSelection: Boolean; override;
function GetReadOnly: Boolean; override;
function GetSelLength: Integer; override;
function GetSelStart: Integer; override;
function GetSelText: string; override;
procedure SetHideSelection(AValue: Boolean); override;
procedure SetSelLength(AValue: Integer); override;
procedure SetSelStart(AValue: Integer); override;
procedure SetSelText(const AValue: string); override;
property Edit: TcxCustomTextEdit read GetEdit;
public
procedure ClearSelection; override;
end;
{ TdxSpellCheckercxRichEditAdapter }
TdxSpellCheckercxRichEditAdapter = class(TdxSpellCheckercxTextEditAdapter)
private
function GetEdit: TcxCustomRichEdit;
protected
function GetReadOnly: Boolean; override;
function GetText: WideString; override;
property Edit: TcxCustomRichEdit read GetEdit;
end;
{ TdxSpellCheckerEditAdapter }
TdxSpellCheckerEditAdapter = class(TdxSpellCheckerCustomEditAdapter)
private
function GetEdit: TCustomEdit;
protected
function GetHideSelection: Boolean; override;
function GetReadOnly: Boolean; override;
function GetSelLength: Integer; override;
function GetSelStart: Integer; override;
function GetSelText: string; override;
procedure SetHideSelection(AValue: Boolean); override;
procedure SetSelLength(AValue: Integer); override;
procedure SetSelStart(AValue: Integer); override;
procedure SetSelText(const AValue: string); override;
property Edit: TCustomEdit read GetEdit;
public
procedure ClearSelection; override;
end;
{ TdxSpellCheckerTextParser }
TdxSpellCheckerSentence = record
StartTextPosition: Integer;
StartWordPosition: Integer;
Text: WideString;
end;
TdxSpellCheckerTextParser = class(TdxCustomSpellCheckerTextHelper)
private
FSpellChecker: TdxCustomSpellChecker;
function LastWideCharIsSpace(const S: WideString): Boolean;
protected
FDelimiters: WideString;
FUrlDelimiters: WideString;
FPrevWord: WideString;
FSpellingEnd: Integer;
FSpellingStart: Integer;
FText: WideString;
function IsDelimiter(AChar: WideChar): Boolean;
function IsUrlDelimiter(AChar: WideChar): Boolean;
procedure UpdateTextInfo(AAdapter: TdxSpellCheckerCustomEditAdapter); virtual;
property SpellChecker: TdxCustomSpellChecker read FSpellChecker;
public
constructor Create(ASpellChecker: TdxCustomSpellChecker); virtual;
destructor Destroy; override;
function GetNextWord(var AStart, ALength: Integer; out ADelimiters: WideString): WideString; virtual;
function GetPrevWord: WideString; override;
function WordExists(const AWord: WideString): Boolean; override;
function GetNextDelimiterPosition(var AStart: Integer; ADirection: Integer): Boolean;
function GetSentence(APos: Integer): TdxSpellCheckerSentence; virtual;
function GetSuggestions(const AWord: WideString): TdxSpellCheckerSuggestionList; virtual;
property Delimiters: WideString read FDelimiters write FDelimiters;
property UrlDelimiters: WideString read FUrlDelimiters write FUrlDelimiters;
property Text: WideString read FText;
end;
TdxSpellCheckerTextParserClass = class of TdxSpellCheckerTextParser;
{ TdxSpellCheckerUndoItem }
TdxSpellCheckerUndoItem = class
private
FMisspelledWord: WideString;
FMisspelledWordPosition: Integer;
FPrevWord: WideString;
FReplacement: WideString;
public
constructor Create(const AMisspelledWord, AReplacement, APrevWord: WideString; AMisspelledWordPosition: Integer);
property MisspelledWord: WideString read FMisspelledWord;
property MisspelledWordPosition: Integer read FMisspelledWordPosition;
property PrevWord: WideString read FPrevWord;
property Replacement: WideString read FReplacement;
end;
{ TdxSpellCheckerUndoManager }
TdxSpellCheckerUndoManager = class(TPersistent)
private
FUndoList: TcxObjectList;
function GetCount: Integer;
function GetItem(AIndex: Integer): TdxSpellCheckerUndoItem;
function GetLast: TdxSpellCheckerUndoItem;
public
constructor Create;
destructor Destroy; override;
procedure Add(const AMisspelledWord, AReplacement, APrevWord: WideString; AMisspelledWordPosition: Integer);
procedure UndoLast;
property Count: Integer read GetCount;
property Last: TdxSpellCheckerUndoItem read GetLast;
property Items[AIndex: Integer]: TdxSpellCheckerUndoItem read GetItem; default;
end;
{ TdxSpellCheckerCustomCheckMode }
TdxSpellCheckerCustomCheckMode = class(TPersistent)
private
FAdapter: TdxSpellCheckerCustomEditAdapter;
FParser: TdxSpellCheckerTextParser;
FSpellChecker: TdxCustomSpellChecker;
FSpellingEnd: Integer;
FSpellingStart: Integer;
function GetPrevWord: WideString;
procedure SetPrevWord(const AValue: WideString);
procedure SetSpellingEnd(const AValue: Integer);
procedure SetSpellingStart(const AValue: Integer);
protected
FLastCode: TdxSpellCheckerSpellingCode;
FMisspelledLen: Integer;
FMisspelledStart: Integer;
FMisspelledWord: WideString;
function CheckWord(const AWord: WideString): TdxSpellCheckerSpellingCode; virtual;
procedure CreateParser; virtual;
function GetNextWord(out AWord: WideString): Boolean; virtual;
function GetOwner: TPersistent; override;
function GetParserClass: TdxSpellCheckerTextParserClass; virtual;
function InternalProcessWord(const AWord: WideString): Boolean; virtual;
function IsNeedChangeWord(const AWord: WideString;
out AReplacement: WideString): Boolean; virtual;
function IsNeedDeleteWord(const AWord: WideString): Boolean; virtual;
function IsNeedIgnoreWord(const AWord: WideString): Boolean; virtual;
function IsValidWord(const AWord: WideString): Boolean; virtual;
procedure SaveSelection; virtual;
procedure SelectMisspelledWord; virtual;
procedure SelectMisspelledWordAfterUndo; virtual;
procedure UpdateByDictionary(ADictionary: TdxCustomSpellCheckerDictionary); virtual;
procedure UpdateSpellingBounds(ADelta: Integer); virtual;
procedure UpdateTextInfo; virtual;
procedure ValidateSpellingBounds; virtual;
property PrevWord: WideString read GetPrevWord write SetPrevWord;
property SpellingEnd: Integer read FSpellingEnd write SetSpellingEnd;
property SpellingStart: Integer read FSpellingStart write SetSpellingStart;
public
constructor Create(AOwner: TdxCustomSpellChecker; AAdapter: TdxSpellCheckerCustomEditAdapter); virtual;
destructor Destroy; override;
procedure Add; virtual;
function CanUndo: Boolean; virtual;
procedure Change(const AWord: WideString); virtual;
procedure ChangeAll(const AWord: WideString); virtual;
procedure Delete; virtual;
procedure DeleteAll; virtual;
function GetSuggestions(const AWord: WideString): TdxSpellCheckerSuggestionList; virtual;
function GetNextMisspelledWord: Boolean; virtual;
procedure Ignore; virtual;
procedure IgnoreAll; virtual;
procedure UndoLast; virtual;
property Adapter: TdxSpellCheckerCustomEditAdapter read FAdapter;
property LastCode: TdxSpellCheckerSpellingCode read FLastCode;
property MisspelledWord: WideString read FMisspelledWord;
property Parser: TdxSpellCheckerTextParser read FParser;
property SpellChecker: TdxCustomSpellChecker read FSpellChecker;
end;
TdxSpellCheckerCustomCheckModeClass = class of TdxSpellCheckerCustomCheckMode;
{ TdxSpellCheckerDialogCheckMode }
TdxSpellCheckerDialogCheckMode = class(TdxSpellCheckerCustomCheckMode)
private
FCheckedSelection: Boolean;
FSaveHideSelection: Boolean;
FSaveSelLength: Integer;
FSaveSelStart: Integer;
FUndoManager: TdxSpellCheckerUndoManager;
function GetLanguages: TdxSpellCheckerLanguages;
protected
procedure CreateParser; override;
function IsCheckingSelectedText: Boolean; virtual;
procedure SaveSelection; override;
procedure ValidateSpellingBounds; override;
procedure ValidateSpellingBoundsAfterUndo;
property UndoManager: TdxSpellCheckerUndoManager read FUndoManager;
public
constructor Create(AOwner: TdxCustomSpellChecker; AAdapter: TdxSpellCheckerCustomEditAdapter); override;
destructor Destroy; override;
function CanUndo: Boolean; override;
procedure Change(const AWord: WideString); override;
procedure Delete; override;
procedure Ignore; override;
function ShowDialog: Integer; virtual;
procedure UndoLast; override;
property Languages: TdxSpellCheckerLanguages read GetLanguages;
end;
{ TdxSpellCheckerOutlookCheckMode }
TdxSpellCheckerOutlookCheckMode = class(TdxSpellCheckerDialogCheckMode)
protected
procedure SelectMisspelledWordAfterUndo; override;
public
function ShowDialog: Integer; override;
end;
{ TdxSpellCheckerWordCheckMode }
TdxSpellCheckerWordCheckMode = class(TdxSpellCheckerDialogCheckMode)
private
function GetMisspelledSentence: TdxSpellCheckerSentence;
protected
procedure SelectMisspelledWordAfterUndo; override;
public
procedure ChangeSentence(const ASentence: WideString); virtual;
function ShowDialog: Integer; override;
property MisspelledSentence: TdxSpellCheckerSentence read GetMisspelledSentence;
end;
{ TdxSpellCheckerWordList }
TdxSpellCheckerWordList = class
private
FCount: Integer;
FLangID: Cardinal;
FLock: TRTLCriticalSection;
FTable: PPointerList;
FTableSize: Integer;
function GetCodePage: Cardinal;
protected
function ElfHash(P: PWideChar): Integer;
function FindWord(const S: WideString): PWideChar;
function NewWord(S: PWideChar): PWideChar;
function AllocWord(ACharCount: Cardinal): PWideChar;
procedure DisposeWord(AWord: PWideChar);
function GetNextWord(AWord: PWideChar): Pointer;
procedure SetNextWord(AWord: PWideChar; AValue: Pointer);
function WordLength(AWord: PWideChar): Integer;
property CodePage: Cardinal read GetCodePage;
public
constructor Create(ALangID: Cardinal; ATableSize: Integer);
destructor Destroy; override;
procedure Add(const S: WideString);
procedure Clear;
function Find(const S: WideString): Boolean;
procedure LoadFromStrings(AStrings: TStrings);
procedure SaveToStrings(AStrings: TStrings);
property Count: Integer read FCount;
property LangID: Cardinal read FLangID write FLangID;
end;
{ TdxSpellCheckerSuggestionBuilder }
TdxSpellCheckerSuggestionBuilder = class
private
FAlphabet: WideString;
FDictionary: TdxCustomSpellCheckerDictionary;
FSuggestions: TdxSpellCheckerSuggestionList;
FWord: WideString;
procedure SetAlphabet(const AValue: WideString);
protected
function CanAddToSuggestions(const ATestWord: WideString): Boolean; virtual;
procedure DoAddSuggestions; virtual; abstract;
property Alphabet: WideString read FAlphabet write SetAlphabet;
property Dictionary: TdxCustomSpellCheckerDictionary read FDictionary;
property Suggestions: TdxSpellCheckerSuggestionList read FSuggestions;
property Word: WideString read FWord;
public
constructor Create(ADictionary: TdxCustomSpellCheckerDictionary); virtual;
procedure AddSuggestions(const AWord: WideString; ASuggestions: TdxSpellCheckerSuggestionList); virtual;
end;
{ TdxNearMissStrategy }
TdxNearMissStrategy = class(TdxSpellCheckerSuggestionBuilder)
protected
procedure CheckAddToSuggestions(const ATestWord: WideString; ADistance: Integer = 2);
procedure CheckChangeOneLetter;
procedure CheckInsertLetter;
procedure CheckInsertSpace;
procedure CheckDeleteLetter;
procedure DoAddSuggestions; override;
procedure InterchangeTwoLetters;
end;
{ TdxDictionaryLoadThread }
TdxDictionaryLoadThread = class(TcxThread)
private
FDictionary: TdxCustomSpellCheckerDictionary;
protected
procedure Execute; override;
property Dictionary: TdxCustomSpellCheckerDictionary read FDictionary;
public
constructor Create(ADictionary: TdxCustomSpellCheckerDictionary);
function IsLoadComplete: Boolean;
end;
{ TdxCustomSpellCheckerDictionary }
TdxSpellCheckerDictionaryLoadingEvent = procedure (Sender: TdxCustomSpellCheckerDictionary; var AHandled: Boolean) of object;
TdxSpellCheckerDictionaryLoadedEvent = procedure (Sender: TdxCustomSpellCheckerDictionary) of object;
TdxSpellCheckerDictionaryLoadMode = (dlmDefault, dlmDirectLoad, dlmThreadedLoad);
TdxCustomSpellCheckerDictionary = class(TPersistent)
private
FAlphabet: WideString;
FCodePage: Cardinal;
FEnabled: Boolean;
FLanguage: DWORD;
FLoaded: Boolean;
FLoadThread: TdxDictionaryLoadThread;
FSpellChecker: TdxCustomSpellChecker;
FWords: TdxSpellCheckerWordList;
FOnLoading: TdxSpellCheckerDictionaryLoadingEvent;
FOnLoaded: TdxSpellCheckerDictionaryLoadedEvent;
function GetActive: Boolean;
function GetWordCount: Integer;
procedure SetEnabled(AValue: Boolean);
procedure SetCodePage(AValue: Cardinal);
procedure SetLanguage(const AValue: DWORD);
protected
function CanLoad: Boolean; virtual;
procedure Cleanup; virtual;
function CreateSuggestionBuilder: TdxSpellCheckerSuggestionBuilder; virtual;
procedure DirectLoad; virtual;
procedure DoActivate; virtual;
function DoLoad: Boolean; virtual;
procedure DoLoadedEvent; virtual;
function DoLoadingEvent: Boolean; virtual;
function DoUnload: Boolean; virtual;
function GetActiveAlphabet: WideString; virtual;
function GetDisplayName: string; virtual;
procedure LoadingComplete; virtual;
function LoadingTerminated: Boolean; {$IFDEF DELPHI9} inline; {$ENDIF}
procedure LoadUsingThread; virtual;
procedure ThreadDone(Sender: TObject); virtual;
procedure Update; virtual;
procedure UpdateLoadedOnLoadEvent;
property LoadThread: TdxDictionaryLoadThread read FLoadThread;
property Words: TdxSpellCheckerWordList read FWords;
public
constructor Create(ASpellChecker: TdxCustomSpellChecker); virtual;
destructor Destroy; override;
procedure Assign(Source: TPersistent); override;
procedure Activate;
function HasWord(const AWord: WideString): Boolean; virtual;
procedure Clear;
procedure Load(AMode: TdxSpellCheckerDictionaryLoadMode = dlmDefault);
procedure Unload;
property Active: Boolean read GetActive;
property Alphabet: WideString read FAlphabet write FAlphabet;
property CodePage: Cardinal read FCodePage write SetCodePage default CP_ACP;
property Enabled: Boolean read FEnabled write SetEnabled default True;
property Language: DWORD read FLanguage write SetLanguage default 0;
property Loaded: Boolean read FLoaded;
property SpellChecker: TdxCustomSpellChecker read FSpellChecker;
property WordCount: Integer read GetWordCount;
property OnLoaded: TdxSpellCheckerDictionaryLoadedEvent read FOnLoaded write FOnLoaded;
property OnLoading: TdxSpellCheckerDictionaryLoadingEvent read FOnLoading write FOnLoading;
end;
TdxCustomSpellCheckerDictionaryClass = class of TdxCustomSpellCheckerDictionary;
{ TdxUserSpellCheckerDictionary }
TdxUserSpellCheckerDictionaryOption = (udFileMustExist, udSaveOnUnload);
TdxUserSpellCheckerDictionaryOptions = set of TdxUserSpellCheckerDictionaryOption;
TdxUserSpellCheckerDictionary = class(TdxCustomSpellCheckerDictionary)
private
FDictionaryPath: TFileName;
FOptions: TdxUserSpellCheckerDictionaryOptions;
protected
function DoLoad: Boolean; override;
function DoUnload: Boolean; override;
function GetDisplayName: string; override;
public
constructor Create(ASpellChecker: TdxCustomSpellChecker); override;
procedure Assign(Source: TPersistent); override;
procedure AddWord(const AWord: WideString);
procedure LoadFromStrings(AStrings: TStrings);
procedure SaveToStrings(AStrings: TStrings);
published
property Alphabet;
property CodePage;
property Enabled;
property DictionaryPath: TFileName read FDictionaryPath write FDictionaryPath;
property Options: TdxUserSpellCheckerDictionaryOptions read FOptions write FOptions default [udSaveOnUnload];
property OnLoaded;
property OnLoading;
end;
{ TdxSpellCheckerDictionaryItem }
TdxSpellCheckerDictionaries = class;
TdxSpellCheckerDictionaryItem = class(TCollectionItem)
private
FDictionaryType: TdxCustomSpellCheckerDictionary;
FDictionaryTypeClass: TdxCustomSpellCheckerDictionaryClass;
FDictionaryEvents: TNotifyEvent;
function GetCollection: TdxSpellCheckerDictionaries;
function GetDictionaryTypeClassName: string;
procedure SetDictionaryType(AValue: TdxCustomSpellCheckerDictionary);
procedure SetDictionaryTypeClassName(const AValue: string);
procedure SetDictionaryTypeClass(AValue: TdxCustomSpellCheckerDictionaryClass);
protected
function GetDisplayName: string; override;
procedure RecreateDictionaryType;
public
destructor Destroy; override;
procedure Assign(Source: TPersistent); override;
property Collection: TdxSpellCheckerDictionaries read GetCollection;
property DictionaryTypeClass: TdxCustomSpellCheckerDictionaryClass read FDictionaryTypeClass write SetDictionaryTypeClass;
published
property DictionaryTypeClassName: string read GetDictionaryTypeClassName write SetDictionaryTypeClassName;
property DictionaryType: TdxCustomSpellCheckerDictionary read FDictionaryType write SetDictionaryType;
property DictionaryEvents: TNotifyEvent read FDictionaryEvents write FDictionaryEvents;
end;
{ TdxSpellCheckerDictionaries }
TdxSpellCheckerDictionaries = class(TCollection)
private
FSpellChecker: TdxCustomSpellChecker;
function GetItem(Index: Integer): TdxSpellCheckerDictionaryItem;
procedure SetItem(Index: Integer; AValue: TdxSpellCheckerDictionaryItem);
protected
function GetOwner: TPersistent; override;
property SpellChecker: TdxCustomSpellChecker read FSpellChecker;
public
constructor Create(ASpellChecker: TdxCustomSpellChecker);
function Add: TdxSpellCheckerDictionaryItem;
function GetNamePath: string; override;
property Items[Index: Integer]: TdxSpellCheckerDictionaryItem read GetItem write SetItem; default;
end;
{ TdxSpellCheckerSpellingOptions }
TdxSpellCheckerSpellingOptionsChangedEvent = procedure (Sender: TdxSpellCheckerSpellingOptions) of object;
TdxSpellCheckerSpellingOptions = class(TPersistent)
private
FSpellChecker: TdxCustomSpellChecker;
FIgnoreMixedCaseWords: Boolean;
FIgnoreUpperCaseWords: Boolean;
FIgnoreMarkupTags: Boolean;
FIgnoreRepeatedWords: Boolean;
FCheckSelectedTextFirst: Boolean;
FIgnoreUrls: Boolean;
FCheckFromCursorPos: Boolean;
FIgnoreEmails: Boolean;
FIgnoreWordsWithNumbers: Boolean;
FOnChanged: TdxSpellCheckerSpellingOptionsChangedEvent;
procedure SetCheckFromCursorPos(AValue: Boolean);
procedure SetCheckSelectedTextFirst(AValue: Boolean);
procedure SetIgnoreEmails(AValue: Boolean);
procedure SetIgnoreMarkupTags(AValue: Boolean);
procedure SetIgnoreMixedCaseWords(AValue: Boolean);
procedure SetIgnoreRepeatedWords(AValue: Boolean);
procedure SetIgnoreUpperCaseWords(AValue: Boolean);
procedure SetIgnoreUrls(AValue: Boolean);
procedure SetIgnoreWordsWithNumbers(AValue: Boolean);
protected
procedure Changed; virtual;
procedure DoChanged; virtual;
procedure PopulateRules(ARules: TdxSpellCheckerRules;
AParser: TdxSpellCheckerTextParser); virtual;
property SpellChecker: TdxCustomSpellChecker read FSpellChecker;
property IgnoreMarkupTags: Boolean read FIgnoreMarkupTags write SetIgnoreMarkupTags default True;
public
constructor Create(ASpellChecker: TdxCustomSpellChecker); virtual;
procedure Assign(Source: TPersistent); override;
property OnChanged: TdxSpellCheckerSpellingOptionsChangedEvent read FOnChanged write FOnChanged;
published
property CheckFromCursorPos: Boolean read FCheckFromCursorPos write SetCheckFromCursorPos default False;
property CheckSelectedTextFirst: Boolean read FCheckSelectedTextFirst write SetCheckSelectedTextFirst default True;
property IgnoreEmails: Boolean read FIgnoreEmails write SetIgnoreEmails default True;
property IgnoreMixedCaseWords: Boolean read FIgnoreMixedCaseWords write SetIgnoreMixedCaseWords default True;
property IgnoreRepeatedWords: Boolean read FIgnoreRepeatedWords write SetIgnoreRepeatedWords default False;
property IgnoreUpperCaseWords: Boolean read FIgnoreUpperCaseWords write SetIgnoreUpperCaseWords default True;
property IgnoreUrls: Boolean read FIgnoreUrls write SetIgnoreUrls default True;
property IgnoreWordsWithNumbers: Boolean read FIgnoreWordsWithNumbers write SetIgnoreWordsWithNumbers default True;
end;
{ TdxSpellCheckerCheckAsYouTypeOptions }
TdxSpellCheckerUnderlineStyle = (usAuto, usWavyLine, usLine);
TdxSpellCheckerPopupMenuItem = (scmiAddToDictionary, scmiDelete, scmiIgnoreAll, scmiSpelling, scmiSuggestions);
TdxSpellCheckerPopupMenuItems = set of TdxSpellCheckerPopupMenuItem;
TdxSpellCheckerCheckAsYouTypeOptionsChangedEvent = procedure(
ASender: TdxSpellCheckerCheckAsYouTypeOptions) of object;
TdxSpellCheckerCheckAsYouTypeOptions = class(TPersistent)
private
FActive: Boolean;
FModifyControlPopupMenu: Boolean;
FPopupMenu: TComponent;
FPopupMenuItems: TdxSpellCheckerPopupMenuItems;
FSpellChecker: TdxCustomSpellChecker;
FSuggestionCount: Integer;
FUnderlineColor: TColor;
FUnderlineStyle: TdxSpellCheckerUnderlineStyle;
FOnChanged: TdxSpellCheckerCheckAsYouTypeOptionsChangedEvent;
procedure SetActive(AValue: Boolean);
procedure SetPopupMenu(AValue: TComponent);
procedure SetModifyControlPopupMenu(AValue: Boolean);
procedure SetPopupMenuItems(AValue: TdxSpellCheckerPopupMenuItems);
procedure SetSuggestionCount(AValue: Integer);
procedure SetUnderlineColor(AValue: TColor);
procedure SetUnderlineStyle(AValue: TdxSpellCheckerUnderlineStyle);
protected
procedure Changed; virtual;
procedure DoChanged; virtual;
procedure Notification(AComponent: TComponent; AOperation: TOperation); virtual;
property SpellChecker: TdxCustomSpellChecker read FSpellChecker;
public
constructor Create(ASpellChecker: TdxCustomSpellChecker); virtual;
procedure Assign(Source: TPersistent); override;
property OnChanged: TdxSpellCheckerCheckAsYouTypeOptionsChangedEvent
read FOnChanged write FOnChanged;
published
property Active: Boolean read FActive write SetActive default False;
property ModifyControlPopupMenu: Boolean read FModifyControlPopupMenu
write SetModifyControlPopupMenu default True;
property PopupMenu: TComponent read FPopupMenu write SetPopupMenu;
property PopupMenuItems: TdxSpellCheckerPopupMenuItems read FPopupMenuItems
write SetPopupMenuItems default [scmiAddToDictionary, scmiDelete, scmiIgnoreAll, scmiSpelling, scmiSuggestions];
property SuggestionCount: Integer read FSuggestionCount write SetSuggestionCount default 5;
property UnderlineColor: TColor read FUnderlineColor write SetUnderlineColor default clRed;
property UnderlineStyle: TdxSpellCheckerUnderlineStyle read FUnderlineStyle
write SetUnderlineStyle default usAuto;
end;
{ TdxSpellCheckerCustomCheckAsYouTypeManager }
TdxSpellCheckerCustomCheckAsYouTypeManager = class(TcxIUnknownObject, IdxSpellCheckerEditHelper)
private
FSpellChecker: TdxCustomSpellChecker;
function GetIsSpellCheckerReady: Boolean;
function GetOptions: TdxSpellCheckerCheckAsYouTypeOptions;
protected
function DoCheckAsYouTypeStart(AControl: TWinControl): Boolean; virtual;
function GetCheckMode: TdxSpellCheckerCustomCheckMode; virtual;
procedure DoCheckAsYouTypeFinish(AControl: TWinControl); virtual;
procedure DoOptionsChanged; virtual; abstract;
procedure InnerShowPopupMenu(APopup: TComponent; const P: TPoint);
procedure Reset; virtual;
procedure SpellingOptionsChanged; virtual;
procedure StartManualSpelling(AAdapter: TdxSpellCheckerCustomEditAdapter); virtual;
procedure ValidateRules(AParser: TdxSpellCheckerTextParser); virtual;
public
constructor Create(ASpellChecker: TdxCustomSpellChecker); virtual;
procedure BeginManualCheck; virtual;
procedure EndManualCheck; virtual;
procedure Refresh(AFullRefresh: Boolean = False); virtual; abstract;
// IdxSpellCheckerEditHelper
procedure CheckAsYouTypeFinish; virtual; abstract;
procedure CheckAsYouTypeStart(AControl: TWinControl); virtual; abstract;
procedure DoDrawMisspelleds(AControl: TWinControl); virtual; abstract;
function IsSpellCheckerDialogControl(AWnd: THandle): Boolean; virtual; abstract;
procedure LayoutChanged(AControl: TWinControl); virtual; abstract;
function QueryPopup(APopup: TComponent; const P: TPoint): Boolean; virtual; abstract;
procedure SelectionChanged(AControl: TWinControl); virtual; abstract;
procedure TextChanged(AControl: TWinControl); virtual; abstract;
property IsSpellCheckerReady: Boolean read GetIsSpellCheckerReady;
property Options: TdxSpellCheckerCheckAsYouTypeOptions read GetOptions;
property SpellChecker: TdxCustomSpellChecker read FSpellChecker;
end;
{ TdxCustomSpellChecker }
TdxSpellCheckerSpellingFormType = (sftOutlook, sftWord);
TdxSpellCheckerEvent = procedure (Sender: TdxCustomSpellChecker) of object;
TdxSpellCheckerCheckWordEvent = procedure (Sender: TdxCustomSpellChecker;
const AWord: WideString; out AValid: Boolean; var AHandled: Boolean) of object;
TdxSpellCheckerAddWordEvent = procedure (AUserDictionary: TdxUserSpellCheckerDictionary;
const AWord: WideString; var AHandled: Boolean) of object;
TdxSpellCheckerEnabledDictionariesLoadedEvent = procedure (Sender: TdxCustomSpellChecker;
const AWord: WideString; var AHandled: Boolean) of object;
TdxSpellCheckerSpellingComplete = procedure (Sender: TdxCustomSpellChecker;
var AHandled: Boolean) of object;
TdxSpellCheckerCheckAsYouTypeEvent = procedure (Sender: TdxCustomSpellChecker;
AControl: TWinControl) of object;
TdxSpellCheckerCheckAsYouTypePopupEvent = procedure(ASender: TdxCustomSpellChecker;
APopupMenu: TComponent; var AHandled: Boolean) of object;
TdxSpellCheckerCheckAsYouTypeStartEvent = procedure (Sender: TdxCustomSpellChecker;
AControl: TWinControl; var AAllow: Boolean) of object;
TdxSpellCheckerCheckControlInContainerEvent = procedure (Sender: TdxCustomSpellChecker;
AControl: TWinControl; var AAllow: Boolean; var AContinue: Boolean) of object;
TdxSpellCheckerGetSuggestionsEvent = procedure (Sender: TdxCustomSpellChecker;
ASuggestions: TdxSpellCheckerSuggestionList) of object;
TdxCustomSpellChecker = class(TComponent)
private
FAutoLoadDictionaries: Boolean;
FChangeList: TdxSpellCheckerReplacementList;
FCheckAsYouTypeManager: TdxSpellCheckerCustomCheckAsYouTypeManager;
FCheckAsYouTypeOptions: TdxSpellCheckerCheckAsYouTypeOptions;
FCheckGroupMode: Boolean;
FCheckingContainer: Boolean;
FCheckMode: TdxSpellCheckerCustomCheckMode;
FCreating: Boolean;
FDeleteList: TdxSpellCheckerWordList;
FDialogLookAndFeel: TcxLookAndFeel;
FDictionaryItems: TdxSpellCheckerDictionaries;
FIgnoreList: TdxSpellCheckerWordList;
FLanguages: TdxSpellCheckerLanguages;
FLastDialogResult: Integer;
FRules: TdxSpellCheckerRules;
FSimilarity: TdxStringSimilarityCalculator;
FSpellingFormType: TdxSpellCheckerSpellingFormType;
FSpellingOptions: TdxSpellCheckerSpellingOptions;
FUseThreadedLoad: Boolean;
FOnAddWord: TdxSpellCheckerAddWordEvent;
FOnAfterCheck: TdxSpellCheckerEvent;
FOnBeforeCheck: TdxSpellCheckerEvent;
FOnCheckAsYouTypeFinish: TdxSpellCheckerCheckAsYouTypeEvent;
FOnCheckAsYouTypeStart: TdxSpellCheckerCheckAsYouTypeStartEvent;
FOnCheckControlInContainer: TdxSpellCheckerCheckControlInContainerEvent;
FOnCheckWord: TdxSpellCheckerCheckWordEvent;
FOnEnabledDictionariesLoaded: TdxSpellCheckerEvent;
FOnGetSuggestions: TdxSpellCheckerGetSuggestionsEvent;
FOnCheckAsYouTypePopup: TdxSpellCheckerCheckAsYouTypePopupEvent;
FOnSpellingComplete: TdxSpellCheckerSpellingComplete;
function GetActiveDictionary(
Index: Integer): TdxCustomSpellCheckerDictionary;
function GetActiveDictionaryCount: Integer;
function GetCheckMode: TdxSpellCheckerCustomCheckMode;
function GetDictionary(Index: Integer): TdxCustomSpellCheckerDictionary;
function GetDictionaryCount: Integer;
function GetEnabledDictionary(
Index: Integer): TdxCustomSpellCheckerDictionary;
function GetEnabledDictionaryCount: Integer;
function GetUserDictionary(Index: Integer): TdxUserSpellCheckerDictionary;
function GetUserDictionaryCount: Integer;
procedure SetCheckAsYouTypeOptions(AValue: TdxSpellCheckerCheckAsYouTypeOptions);
procedure SetDialogLookAndFeel(AValue: TcxLookAndFeel);
procedure SetDictionaryItems(AValue: TdxSpellCheckerDictionaries);
procedure SetSpellingOptions(AValue: TdxSpellCheckerSpellingOptions);
protected
procedure AddToIgnoreList(const AWord: WideString); virtual;
procedure CheckCallEnabledDictionariesLoaded;
function CreateSimilarity: TdxStringSimilarityCalculator; virtual;
function CreateSpellingOptions: TdxSpellCheckerSpellingOptions; virtual;
function DoAddWord(AUserDictionary: TdxUserSpellCheckerDictionary;
const AWord: WideString): Boolean; virtual;
procedure DoAfterCheck; virtual;
procedure DoBeforeCheck; virtual;
procedure DoCheck(ADialogCheckMode: TdxSpellCheckerDialogCheckMode); virtual;
procedure DoCheckAsYouTypeFinish(AControl: TWinControl); virtual;
function DoCheckAsYouTypePopup(APopup: TComponent): Boolean; virtual;
function DoCheckAsYouTypeStart(AControl: TWinControl): Boolean; virtual;
procedure DoCheckContainer(AContainer: TWinControl; ARecursive: Boolean); virtual;
function DoCheckControlInContainer(AControl: TWinControl; var AContinue: Boolean): Boolean; virtual;
function DoCheckWord(const AWord: WideString; var AValid: Boolean): Boolean; virtual;
procedure DoEnabledDictionariesLoaded; virtual;
procedure DoGetSuggestions(ASuggestions: TdxSpellCheckerSuggestionList); virtual;
function DoSpellingComplete: Boolean; virtual;
procedure BeginManualCheck;
procedure EndManualCheck;
function GetDialogCheckModeClass: TdxSpellCheckerCustomCheckModeClass; virtual;
procedure InternalCheck(AAdapter: TdxSpellCheckerCustomEditAdapter); virtual;
procedure LoadDictionariesDirect(AIgnoreDisabled: Boolean = True); virtual;
procedure LoadDictionariesUsingThread(AIgnoreDisabled: Boolean = True); virtual;
procedure Loaded; override;
procedure Notification(AComponent: TComponent; Operation: TOperation); override;
procedure SpellingComplete;
procedure SpellingOptionsChanged; virtual;
procedure ValidateRules(AParser: TdxSpellCheckerTextParser); virtual;
procedure UpdateByDictionary(ADictionary: TdxCustomSpellCheckerDictionary); virtual;
procedure UpdateCheckAsYouTypeManagerState; virtual;
property ChangeList: TdxSpellCheckerReplacementList read FChangeList;
property CheckAsYouTypeManager: TdxSpellCheckerCustomCheckAsYouTypeManager read FCheckAsYouTypeManager;
property CheckingContainer: Boolean read FCheckingContainer;
property DeleteList: TdxSpellCheckerWordList read FDeleteList;
property IgnoreList: TdxSpellCheckerWordList read FIgnoreList;
property Languages: TdxSpellCheckerLanguages read FLanguages;
property OnAddWord: TdxSpellCheckerAddWordEvent read FOnAddWord write FOnAddWord;
property OnAfterCheck: TdxSpellCheckerEvent read FOnAfterCheck write FOnAfterCheck;
property OnBeforeCheck: TdxSpellCheckerEvent read FOnBeforeCheck write FOnBeforeCheck;
property OnCheckAsYouTypeFinish: TdxSpellCheckerCheckAsYouTypeEvent
read FOnCheckAsYouTypeFinish write FOnCheckAsYouTypeFinish;
property OnCheckAsYouTypePopup: TdxSpellCheckerCheckAsYouTypePopupEvent
read FOnCheckAsYouTypePopup write FOnCheckAsYouTypePopup;
property OnCheckAsYouTypeStart: TdxSpellCheckerCheckAsYouTypeStartEvent
read FOnCheckAsYouTypeStart write FOnCheckAsYouTypeStart;
property OnCheckControlInContainer: TdxSpellCheckerCheckControlInContainerEvent
read FOnCheckControlInContainer write FOnCheckControlInContainer;
property OnCheckWord: TdxSpellCheckerCheckWordEvent read FOnCheckWord write FOnCheckWord;
property OnEnabledDictionariesLoaded: TdxSpellCheckerEvent
read FOnEnabledDictionariesLoaded write FOnEnabledDictionariesLoaded;
property OnGetSuggestions: TdxSpellCheckerGetSuggestionsEvent
read FOnGetSuggestions write FOnGetSuggestions;
property OnSpellingComplete: TdxSpellCheckerSpellingComplete
read FOnSpellingComplete write FOnSpellingComplete;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
procedure Check(AEdit: TCustomEdit); overload;
procedure Check(AEdit: TcxCustomTextEdit); overload;
procedure CheckContainer(AContainer: TWinControl; ARecursive: Boolean);
procedure AddWordToUserDictionary(const AWord: WideString);
function FindDictionaryByWord(const AWord: WideString): TdxCustomSpellCheckerDictionary;
function FindFirstEnabledUserDictionary: TdxUserSpellCheckerDictionary;
function GetSuggestions(const AWord: WideString): TdxSpellCheckerSuggestionList;
function HasWordInDictionaries(const AWord: WideString): Boolean;
function HasEnabledUserDictionary: Boolean;
function IsValidWord(const AWord: WideString): Boolean;
procedure PopulateLanguages(AList: TStrings);
procedure ShowSpellingCompleteMessage; virtual;
procedure LoadDictionaries(AIgnoreDisabled: Boolean = True);
procedure UnloadDictionaries;
function GetTwoWordsDistance(const AWord1, AWord2: WideString): Integer;
property ActiveDictionaries[Index: Integer]: TdxCustomSpellCheckerDictionary read GetActiveDictionary;
property ActiveDictionaryCount: Integer read GetActiveDictionaryCount;
property AutoLoadDictionaries: Boolean read FAutoLoadDictionaries write FAutoLoadDictionaries default False;
property CheckMode: TdxSpellCheckerCustomCheckMode read GetCheckMode;
property CheckAsYouTypeOptions: TdxSpellCheckerCheckAsYouTypeOptions read FCheckAsYouTypeOptions write SetCheckAsYouTypeOptions;
property DialogLookAndFeel: TcxLookAndFeel read FDialogLookAndFeel write SetDialogLookAndFeel;
property Dictionaries[Index: Integer]: TdxCustomSpellCheckerDictionary read GetDictionary;
property DictionaryCount: Integer read GetDictionaryCount;
property DictionaryItems: TdxSpellCheckerDictionaries read FDictionaryItems write SetDictionaryItems;
property EnabledDictionaries[Index: Integer]: TdxCustomSpellCheckerDictionary read GetEnabledDictionary;
property EnabledDictionaryCount: Integer read GetEnabledDictionaryCount;
property Rules: TdxSpellCheckerRules read FRules;
property SpellingFormType: TdxSpellCheckerSpellingFormType read FSpellingFormType write FSpellingFormType default sftOutlook;
property SpellingOptions: TdxSpellCheckerSpellingOptions read FSpellingOptions write SetSpellingOptions;
property UserDictionaries[Index: Integer]: TdxUserSpellCheckerDictionary read GetUserDictionary;
property UserDictionaryCount: Integer read GetUserDictionaryCount;
property UseThreadedLoad: Boolean read FUseThreadedLoad write FUseThreadedLoad default False;
end;
{ TdxSpellChecker }
TdxSpellChecker = class(TdxCustomSpellChecker)
published
property AutoLoadDictionaries;
property CheckAsYouTypeOptions;
property DialogLookAndFeel;
property DictionaryItems;
property SpellingFormType;
property SpellingOptions;
property UseThreadedLoad;
property OnAddWord;
property OnAfterCheck;
property OnBeforeCheck;
property OnCheckAsYouTypeFinish;
property OnCheckAsYouTypePopup;
property OnCheckAsYouTypeStart;
property OnCheckControlInContainer;
property OnCheckWord;
property OnEnabledDictionariesLoaded;
property OnGetSuggestions;
property OnSpellingComplete;
end;
function GetRegisteredDictionaryTypes: TcxRegisteredClasses;
implementation
uses
Dialogs, cxGeometry, dxOffice11, dxSpellCheckerStrs, dxSpellCheckerUtils,
dxSpellCheckerDialogs, dxISpellDecompressor, dxSpellCheckerCheckAsYouType,
cxContainer, cxEdit;
var
FRegisteredDictionaryTypes: TcxRegisteredClasses;
function GetRegisteredDictionaryTypes: TcxRegisteredClasses;
begin
if FRegisteredDictionaryTypes = nil then
begin
FRegisteredDictionaryTypes := TcxRegisteredClasses.Create;
FRegisteredDictionaryTypes.Sorted := True;
end;
Result := FRegisteredDictionaryTypes;
end;
procedure FreeRegisteredDictionaryTypes;
begin
FreeAndNil(FRegisteredDictionaryTypes);
end;
{ TdxSpellCheckerLanguages }
function TdxSpellCheckerLanguages.GetDefaultLanguageLCID: DWORD;
begin
Result := GetSystemDefaultLCID;
end;
function TdxSpellCheckerLanguages.GetLCID(const AName: string): DWORD;
var
I: Integer;
begin
Result := 0;
for I := 0 to Count - 1 do
begin
if AnsiCompareText(AName, Name[I]) = 0 then
begin
Result := LocaleID[I];
Break;
end;
end;
end;
{ TdxSpellCheckerSuggestion }
constructor TdxSpellCheckerSuggestion.Create(const AWord: WideString;
ADictionary: TdxCustomSpellCheckerDictionary; ADistance: Integer);
begin
inherited Create;
FDictionary := ADictionary;
FWord := AWord;
FDistance := ADistance;
end;
{ TdxSpellCheckerSuggestionList }
procedure TdxSpellCheckerSuggestionList.Add(const AWord: WideString;
ADictionary: TdxCustomSpellCheckerDictionary; ADistance: Integer);
begin
inherited Add(TdxSpellCheckerSuggestion.Create(AWord, ADictionary, ADistance));
end;
procedure TdxSpellCheckerSuggestionList.Delete(AIndex: Integer);
begin
Items[AIndex].Free;
inherited Delete(AIndex);
end;
procedure TdxSpellCheckerSuggestionList.FixCapitalization(const AMask: WideString);
var
I: Integer;
begin
if Length(AMask) = 0 then Exit;
case GetWordCapitalizationType(AMask) of
ctUpper:
for I := 0 to Count - 1 do
with Items[I] do
FWord := WideUpperCase(FWord);
ctCapitalized:
for I := 0 to Count - 1 do
with Items[I] do
if Length(FWord) > 0 then
FWord[1] := WideUpperCase(FWord[1])[1];
end;
end;
procedure TdxSpellCheckerSuggestionList.RemoveDuplicates;
var
I: Integer;
begin
SortByWord;
I := 1;
while I < Count do
begin
while (I < Count) and WideSameText(Items[I].Word, Items[I - 1].Word) do
begin
Items[I].Free;
Delete(I);
end;
Inc(I);
end;
SortByDistance;
end;
procedure TdxSpellCheckerSuggestionList.SaveToStrings(AStrings: TStrings);
var
I: Integer;
begin
AStrings.BeginUpdate;
try
AStrings.Clear;
for I := 0 to Count - 1 do
AStrings.AddObject(Items[I].Word, Pointer(Items[I].Distance));
finally
AStrings.EndUpdate;
end;
end;
function CompareSuggestionsByDistance(Item1, Item2: Pointer): Integer;
begin
Result := TdxSpellCheckerSuggestion(Item1).Distance - TdxSpellCheckerSuggestion(Item2).Distance;
end;
procedure TdxSpellCheckerSuggestionList.SortByDistance;
begin
Sort(CompareSuggestionsByDistance);
end;
function CompareSuggestionsByWord(Item1, Item2: Pointer): Integer;
begin
Result := WideCompareText(TdxSpellCheckerSuggestion(Item1).Word, TdxSpellCheckerSuggestion(Item2).Word);
end;
procedure TdxSpellCheckerSuggestionList.SortByWord;
begin
Sort(CompareSuggestionsByWord);
end;
function TdxSpellCheckerSuggestionList.GetItem(
Index: Integer): TdxSpellCheckerSuggestion;
begin
Result := TdxSpellCheckerSuggestion(inherited Items[Index]);
end;
{ TdxSpellCheckerReplacementItem }
constructor TdxSpellCheckerReplacementItem.Create(
const AText, AReplacement: WideString);
begin
inherited Create;
FText := AText;
FReplacement := AReplacement;
end;
{ TdxSpellCheckerReplacementList }
constructor TdxSpellCheckerReplacementList.Create(AllowDuplicates: Boolean = False);
begin
inherited Create;
Capacity := 256;
FAllowDuplicates := AllowDuplicates;
end;
procedure TdxSpellCheckerReplacementList.Add(
const AText, AReplacement: WideString);
var
AItem: TdxSpellCheckerReplacementItem;
begin
if FAllowDuplicates then
inherited Add(TdxSpellCheckerReplacementItem.Create(AText, AReplacement))
else
begin
AItem := FindReplacement(AText);
if AItem = nil then
begin
inherited Add(TdxSpellCheckerReplacementItem.Create(AText, AReplacement));
SortByText;
end
else
AItem.FReplacement := AReplacement;
end;
end;
function TdxSpellCheckerReplacementList.FindReplacement(
const AText: WideString): TdxSpellCheckerReplacementItem;
var
L, H, I, C: Integer;
begin
Result := nil;
L := 0;
H := Count - 1;
while L <= H do
begin
I := (L + H) shr 1;
C := WideCompareText(TdxSpellCheckerReplacementItem(List^[I]).Text, AText);
if C < 0 then
L := I + 1
else
begin
H := I - 1;
if C = 0 then
begin
Result := TdxSpellCheckerReplacementItem(List^[I]);
Break;
end;
end;
end;
end;
function TdxSpellCheckerReplacementList.GetItem(
AIndex: Integer): TdxSpellCheckerReplacementItem;
begin
Result := TdxSpellCheckerReplacementItem(inherited Items[AIndex]);
end;
function CompareReplacementByText(Item1, Item2: Pointer): Integer;
begin
Result := WideCompareText(TdxSpellCheckerReplacementItem(Item1).Text,
TdxSpellCheckerReplacementItem(Item2).Text);
end;
procedure TdxSpellCheckerReplacementList.SortByText;
begin
Sort(CompareReplacementByText);
end;
{ TdxSpellCheckerCustomEditAdapter }
constructor TdxSpellCheckerCustomEditAdapter.Create(AEdit: TWinControl);
begin
FEdit := AEdit;
end;
procedure TdxSpellCheckerCustomEditAdapter.GetSpellingBounds(
out ASpellingStart, ASpellingEnd: Integer);
begin
ASpellingStart := 1;
if EditorHandleAllocated then
ASpellingEnd := SendMessageW(EditorHandle, WM_GETTEXTLENGTH, 0, 0) + 1
else
ASpellingEnd := Length(FText);
end;
function TdxSpellCheckerCustomEditAdapter.EditorHandleAllocated: Boolean;
begin
Result := (FEdit <> nil) and FEdit.HandleAllocated
end;
function TdxSpellCheckerCustomEditAdapter.GetEditorHandle: THandle;
begin
if EditorHandleAllocated then
Result := FEdit.Handle
else
Result := 0;
end;
function TdxSpellCheckerCustomEditAdapter.GetText: WideString;
var
ALen: Integer;
begin
if EditorHandleAllocated then
begin
ALen := SendMessageW(EditorHandle, WM_GETTEXTLENGTH, 0, 0) + 1;
SetLength(Result, ALen);
GetWindowTextW(EditorHandle, Pointer(Result), ALen);
FText := Result;
end
else
Result := FText;
end;
procedure TdxSpellCheckerCustomEditAdapter.Post(AUpdateValue: Boolean = True);
var
AEdit: IdxSpellCheckerSupport;
begin
if Supports(GetInnerControlContainer(FEdit), IdxSpellCheckerSupport, AEdit) and
AUpdateValue and not EditorHandleAllocated then
begin
FText := PWideChar(FText);
AEdit.SetValue(FText);
end;
end;
function TdxSpellCheckerCustomEditAdapter.IsInplace: Boolean;
var
AContainer: TcxCustomEdit;
begin
AContainer := TcxCustomEdit(GetInnerControlContainer(FEdit));
Result := (AContainer <> nil) and AContainer.IsInplace;
end;
{ TdxSpellCheckercxTextEditAdapter }
procedure TdxSpellCheckercxTextEditAdapter.ClearSelection;
begin
if EditorHandleAllocated then
Edit.ClearSelection
else
SelText := '';
end;
function TdxSpellCheckercxTextEditAdapter.GetHideSelection: Boolean;
begin
Result := Edit.Properties.HideSelection;
end;
function TdxSpellCheckercxTextEditAdapter.GetReadOnly: Boolean;
begin
Result := Edit.Properties.ReadOnly;
end;
function TdxSpellCheckercxTextEditAdapter.GetSelLength: Integer;
begin
Result := Edit.SelLength;
end;
function TdxSpellCheckercxTextEditAdapter.GetSelStart: Integer;
begin
Result := Edit.SelStart
end;
function TdxSpellCheckercxTextEditAdapter.GetSelText: string;
begin
Result := Edit.SelText
end;
procedure TdxSpellCheckercxTextEditAdapter.SetHideSelection(AValue: Boolean);
begin
Edit.Properties.HideSelection := AValue
end;
procedure TdxSpellCheckercxTextEditAdapter.SetSelLength(AValue: Integer);
begin
Edit.SelLength := AValue;
end;
procedure TdxSpellCheckercxTextEditAdapter.SetSelStart(AValue: Integer);
begin
Edit.SelStart := AValue;
end;
procedure TdxSpellCheckercxTextEditAdapter.SetSelText(const AValue: string);
begin
Edit.SelText := AValue;
end;
function TdxSpellCheckercxTextEditAdapter.GetEdit: TcxCustomTextEdit;
begin
Result := TcxCustomTextEdit(FEdit);
end;
{ TdxSpellCheckercxRichEditAdapter }
function TdxSpellCheckercxRichEditAdapter.GetReadOnly: Boolean;
begin
Result := Edit.ActiveProperties.ReadOnly;
end;
function TdxSpellCheckercxRichEditAdapter.GetText: WideString;
var
ASource, ADest: WideString;
ALen: Integer;
begin
ASource := inherited GetText;
ALen := Length(ASource);
SetLength(ADest, ALen);
ALen := AdjustRichLineBreaksW(PWideChar(ADest), PWideChar(ASource),
Edit.RichVersion >= 200);
SetLength(ADest, ALen);
Result := ADest;
end;
function TdxSpellCheckercxRichEditAdapter.GetEdit: TcxCustomRichEdit;
begin
Result := TcxCustomRichEdit(inherited Edit);
end;
{ TdxSpellCheckerEditAdapter }
procedure TdxSpellCheckerEditAdapter.ClearSelection;
begin
SelText := '';
end;
function TdxSpellCheckerEditAdapter.GetHideSelection: Boolean;
begin
if FEdit is TMemo then
Result := TMemo(FEdit).HideSelection
else
if FEdit is TEdit then
Result := TEdit(FEdit).HideSelection
else
Result := False;
end;
function TdxSpellCheckerEditAdapter.GetReadOnly: Boolean;
begin
Result := TEdit(FEdit).ReadOnly;
end;
function TdxSpellCheckerEditAdapter.GetSelLength: Integer;
begin
if EditorHandleAllocated then
Result := Edit.SelLength
else
Result := FSelLength;
end;
function TdxSpellCheckerEditAdapter.GetSelStart: Integer;
begin
if EditorHandleAllocated then
Result := Edit.SelStart
else
Result := FSelStart;
end;
function TdxSpellCheckerEditAdapter.GetSelText: string;
begin
if EditorHandleAllocated then
Result := Edit.SelText
else
Result := Copy(FText, FSelStart, FSelLength);
end;
procedure TdxSpellCheckerEditAdapter.SetHideSelection(AValue: Boolean);
begin
if FEdit is TMemo then
TMemo(FEdit).HideSelection := AValue
else
if FEdit is TEdit then
TEdit(FEdit).HideSelection := AValue;
end;
procedure TdxSpellCheckerEditAdapter.SetSelLength(AValue: Integer);
begin
if EditorHandleAllocated then
Edit.SelLength := AValue;
FSelLength := AValue;
end;
procedure TdxSpellCheckerEditAdapter.SetSelStart(AValue: Integer);
begin
if EditorHandleAllocated then
Edit.SelStart := AValue;
FSelStart := AValue;
end;
procedure TdxSpellCheckerEditAdapter.SetSelText(const AValue: string);
var
AContainer: TWinControl;
AIntf: IdxSpellCheckerSupport;
begin
FText := Copy(FText, 1, FSelStart) + AValue + Copy(FText, FSelStart + FSelLength + 1, Length(FText) - FSelStart - FSelLength);
if EditorHandleAllocated then
begin
AContainer := GetInnerControlContainer(Edit);
if Supports(TObject(AContainer), IdxSpellCheckerSupport, AIntf) then
AIntf.SetSelText(AValue)
else
Edit.SelText := AValue;
end;
end;
function TdxSpellCheckerEditAdapter.GetEdit: TCustomEdit;
begin
Result := TCustomEdit(FEdit);
end;
{ TdxSpellCheckerTextParser }
constructor TdxSpellCheckerTextParser.Create(ASpellChecker: TdxCustomSpellChecker);
begin
inherited Create;
FSpellChecker := ASpellChecker;
FDelimiters := #0#9#10#11#13#32'.,<>=!?:;"()[]{}+|-/\';
FUrlDelimiters := #0#9#10#11#13#32',<>!;()[]{}|';
FText := #0;
end;
destructor TdxSpellCheckerTextParser.Destroy;
begin
inherited Destroy;
end;
function TdxSpellCheckerTextParser.GetNextWord(var AStart, ALength: Integer; out ADelimiters: WideString): WideString;
procedure SkipFirstDelimiters;
begin
if (AStart <= FSpellingEnd) and WideIsSpace(FText[AStart]) then
while (AStart < FSpellingEnd) and WideIsSpace(FText[AStart]) do
begin
ADelimiters := ADelimiters + FText[AStart];
Inc(AStart);
end
else
while (AStart < FSpellingEnd) and not WideIsAlphaNumeric(FText[AStart]) do
begin
ADelimiters := ADelimiters + FText[AStart];
Inc(AStart);
end;
end;
var
APos: Integer;
APreDelimiters: WideString;
begin
ADelimiters := '';
SkipFirstDelimiters;
ALength := 0;
APos := AStart;
while (APos < FSpellingEnd) and not WideIsSpace(FText[APos]) do
Inc(APos);
ALength := APos - AStart;
if ALength = 0 then
Result := ''
else
begin
Result := Copy(FText, AStart, ALength);
if LastWideCharIsSpace(ADelimiters) and IsUrl(Result) then
begin
while (APos > AStart) and IsUrlDelimiter(FText[APos]) do
Dec(APos);
ALength := APos - AStart + 1;
Result := Copy(FText, AStart, ALength);
end
else
begin
while (AStart < FSpellingEnd) and IsDelimiter(FText[AStart]) do
begin
ADelimiters := ADelimiters + FText[AStart];
Inc(AStart);
end;
ALength := 0;
APos := AStart;
while (APos < FSpellingEnd) and not IsDelimiter(FText[APos]) do
Inc(APos);
ALength := APos - AStart;
Result := Copy(FText, AStart, ALength);
if not WideStringContainsAlpha(Result) then
begin
APreDelimiters := ADelimiters + Result;
Inc(AStart, ALength);
Result := GetNextWord(AStart, ALength, ADelimiters);
ADelimiters := APreDelimiters + ADelimiters;
end;
end;
end;
end;
function TdxSpellCheckerTextParser.GetPrevWord: WideString;
begin
Result := FPrevWord;
end;
function TdxSpellCheckerTextParser.IsDelimiter(AChar: WideChar): Boolean;
begin
Result := WideCharPos(AChar, FDelimiters) > 0;
end;
function TdxSpellCheckerTextParser.IsUrlDelimiter(AChar: WideChar): Boolean;
begin
Result := WideCharPos(AChar, FUrlDelimiters) > 0;
end;
function TdxSpellCheckerTextParser.WordExists(const AWord: WideString): Boolean;
begin
Result := SpellChecker.HasWordInDictionaries(AWord);
end;
function TdxSpellCheckerTextParser.GetSentence(APos: Integer): TdxSpellCheckerSentence;
function IsSentenceDelimiters(ACh: WideChar): Boolean;
begin
Result := (ACh = '.') or (WideIsSpace(ACh) and (ACh <> ' '));
end;
function GetSentenceText(var AStartPos: Integer): WideString;
var
AEndPos: Integer;
ALength: Integer;
begin
AEndPos := AStartPos;
while (AStartPos > 0) and not IsSentenceDelimiters(Text[AStartPos]) do
Dec(AStartPos);
while (AStartPos > 0) and (IsSentenceDelimiters(Text[AStartPos]) or (Text[AStartPos] = ' ')) do
Inc(AStartPos);
ALength := Length(FText);
while (AEndPos <= ALength) and (not IsSentenceDelimiters(Text[AEndPos]) or (Text[AEndPos] = '.')) do
Inc(AEndPos);
Result := Copy(Text, AStartPos, AEndPos - AStartPos);
end;
begin
with Result do
begin
StartTextPosition := APos;
Text := GetSentenceText(StartTextPosition);
if StartTextPosition = 0 then
Inc(StartTextPosition);
StartWordPosition := APos - StartTextPosition;
end;
end;
function TdxSpellCheckerTextParser.GetNextDelimiterPosition(var AStart: Integer; ADirection: Integer): Boolean;
begin
while (AStart <= FSpellingEnd) and (AStart >= FSpellingStart) and not WideIsSpace(FText[AStart]) do
Inc(AStart, ADirection);
Result := WideIsSpace(FText[AStart]);
if Result and (ADirection < 0) then
Inc(AStart, ADirection);
end;
function TdxSpellCheckerTextParser.GetSuggestions(
const AWord: WideString): TdxSpellCheckerSuggestionList;
begin
Result := SpellChecker.GetSuggestions(AWord);
end;
procedure TdxSpellCheckerTextParser.UpdateTextInfo(AAdapter: TdxSpellCheckerCustomEditAdapter);
begin
AAdapter.GetSpellingBounds(FSpellingStart, FSpellingEnd);
FText := AAdapter.Text;
end;
function TdxSpellCheckerTextParser.LastWideCharIsSpace(const S: WideString): Boolean;
var
I: Integer;
begin
I := Length(S);
Result := (I > 0) and WideIsSpace(S[I]);
end;
{ TdxSpellCheckerUndoItem }
constructor TdxSpellCheckerUndoItem.Create(const AMisspelledWord, AReplacement, APrevWord: WideString; AMisspelledWordPosition: Integer);
begin
FMisspelledWord := AMisspelledWord;
FReplacement := AReplacement;
FPrevWord := APrevWord;
FMisspelledWordPosition := AMisspelledWordPosition;
end;
{ TdxSpellCheckerUndoManager }
constructor TdxSpellCheckerUndoManager.Create;
begin
FUndoList := TcxObjectList.Create;
end;
destructor TdxSpellCheckerUndoManager.Destroy;
begin
FreeAndNil(FUndoList);
inherited Destroy;
end;
procedure TdxSpellCheckerUndoManager.Add(const AMisspelledWord, AReplacement, APrevWord: WideString; AMisspelledWordPosition: Integer);
begin
FUndoList.Add(TdxSpellCheckerUndoItem.Create(AMisspelledWord, AReplacement, APrevWord, AMisspelledWordPosition));
end;
procedure TdxSpellCheckerUndoManager.UndoLast;
begin
if Count > 0 then
begin
Last.Free;
FUndoList.Delete(Count - 1);
end;
end;
function TdxSpellCheckerUndoManager.GetCount: Integer;
begin
Result := FUndoList.Count;
end;
function TdxSpellCheckerUndoManager.GetItem(AIndex: Integer): TdxSpellCheckerUndoItem;
begin
Result := TdxSpellCheckerUndoItem(FUndoList[AIndex]);
end;
function TdxSpellCheckerUndoManager.GetLast: TdxSpellCheckerUndoItem;
begin
if Count > 0 then
Result := Items[Count - 1]
else
Result := nil;
end;
{ TdxSpellCheckerCustomCheckAsYouTypeManager }
constructor TdxSpellCheckerCustomCheckAsYouTypeManager.Create(
ASpellChecker: TdxCustomSpellChecker);
begin
FSpellChecker := ASpellChecker;
end;
procedure TdxSpellCheckerCustomCheckAsYouTypeManager.BeginManualCheck;
begin
end;
procedure TdxSpellCheckerCustomCheckAsYouTypeManager.EndManualCheck;
begin
end;
procedure TdxSpellCheckerCustomCheckAsYouTypeManager.DoCheckAsYouTypeFinish(
AControl: TWinControl);
begin
SpellChecker.DoCheckAsYouTypeFinish(AControl);
end;
function TdxSpellCheckerCustomCheckAsYouTypeManager.DoCheckAsYouTypeStart(
AControl: TWinControl): Boolean;
begin
Result := SpellChecker.DoCheckAsYouTypeStart(AControl);
end;
procedure TdxSpellCheckerCustomCheckAsYouTypeManager.InnerShowPopupMenu(APopup: TComponent; const P: TPoint);
begin
if not SpellChecker.DoCheckAsYouTypePopup(APopup) then
ShowPopupMenu(nil, APopup, P.X, P.Y);
end;
procedure TdxSpellCheckerCustomCheckAsYouTypeManager.Reset;
begin
end;
procedure TdxSpellCheckerCustomCheckAsYouTypeManager.SpellingOptionsChanged;
begin
if GetCheckMode <> nil then
SpellChecker.ValidateRules(GetCheckMode.Parser);
end;
function TdxSpellCheckerCustomCheckAsYouTypeManager.GetIsSpellCheckerReady: Boolean;
begin
Result := SpellChecker.ActiveDictionaryCount > 0;
end;
function TdxSpellCheckerCustomCheckAsYouTypeManager.GetOptions: TdxSpellCheckerCheckAsYouTypeOptions;
begin
Result := SpellChecker.CheckAsYouTypeOptions;
end;
function TdxSpellCheckerCustomCheckAsYouTypeManager.GetCheckMode: TdxSpellCheckerCustomCheckMode;
begin
Result := nil;
end;
procedure TdxSpellCheckerCustomCheckAsYouTypeManager.StartManualSpelling(
AAdapter: TdxSpellCheckerCustomEditAdapter);
begin
SpellChecker.InternalCheck(AAdapter);
end;
procedure TdxSpellCheckerCustomCheckAsYouTypeManager.ValidateRules(
AParser: TdxSpellCheckerTextParser);
begin
SpellChecker.ValidateRules(AParser);
end;
{ TdxSpellCheckerCustomCheckMode }
constructor TdxSpellCheckerCustomCheckMode.Create(AOwner: TdxCustomSpellChecker;
AAdapter: TdxSpellCheckerCustomEditAdapter);
begin
FSpellChecker := AOwner;
FAdapter := AAdapter;
SaveSelection;
CreateParser;
FMisspelledStart := SpellingStart;
end;
destructor TdxSpellCheckerCustomCheckMode.Destroy;
begin
FreeAndNil(FParser);
inherited Destroy;
end;
procedure TdxSpellCheckerCustomCheckMode.Add;
begin
if SpellChecker.HasEnabledUserDictionary then
SpellChecker.AddWordToUserDictionary(FMisspelledWord);
end;
function TdxSpellCheckerCustomCheckMode.CanUndo: Boolean;
begin
Result := False;
end;
procedure TdxSpellCheckerCustomCheckMode.Change(const AWord: WideString);
var
ADelta: Integer;
begin
SelectMisspelledWord;
ADelta := Length(AWord) - Length(Adapter.SelText);
Adapter.SelText := AWord;
PrevWord := AWord;
UpdateSpellingBounds(ADelta);
UpdateTextInfo;
Inc(FMisspelledStart, Length(AWord));
end;
procedure TdxSpellCheckerCustomCheckMode.ChangeAll(const AWord: WideString);
begin
SpellChecker.ChangeList.Add(MisspelledWord, AWord);
Change(AWord);
end;
function TdxSpellCheckerCustomCheckMode.CheckWord(
const AWord: WideString): TdxSpellCheckerSpellingCode;
begin
if not IsValidWord(AWord) then
begin
FLastCode := SpellChecker.Rules.ErrorCode;
FMisspelledWord := AWord;
end
else
FLastCode := scNoError;
Result := FLastCode;
end;
procedure TdxSpellCheckerCustomCheckMode.Delete;
begin
Inc(FMisspelledLen);
Dec(FMisspelledStart);
SelectMisspelledWord;
Adapter.ClearSelection;
UpdateSpellingBounds(-FMisspelledLen);
UpdateTextInfo;
end;
procedure TdxSpellCheckerCustomCheckMode.DeleteAll;
begin
SpellChecker.DeleteList.Add(MisspelledWord);
Delete;
end;
function TdxSpellCheckerCustomCheckMode.GetNextWord(out AWord: WideString): Boolean;
var
ADelimetrs: WideString;
begin
AWord := Parser.GetNextWord(FMisspelledStart, FMisspelledLen, ADelimetrs);
if AWord = '' then
begin
ValidateSpellingBounds;
AWord := Parser.GetNextWord(FMisspelledStart, FMisspelledLen, ADelimetrs);
end;
if (Length(ADelimetrs) <> GetWideCharCount(' ', ADelimetrs)) then // todo:
PrevWord := '';
Result := FMisspelledLen > 0;
end;
function TdxSpellCheckerCustomCheckMode.GetNextMisspelledWord: Boolean;
var
AWord: WideString;
begin
FMisspelledWord := '';
while GetNextWord(AWord) do
begin
if InternalProcessWord(AWord) then
Continue;
if CheckWord(AWord) <> scNoError then
Break;
PrevWord := AWord;
Inc(FMisspelledStart, FMisspelledLen);
end;
if FMisspelledLen = 0 then
FLastCode := scNoError
else
SelectMisspelledWord;
Result := FLastCode <> scNoError;
end;
function TdxSpellCheckerCustomCheckMode.GetSuggestions(
const AWord: WideString): TdxSpellCheckerSuggestionList;
begin
Result := Parser.GetSuggestions(AWord);
end;
function TdxSpellCheckerCustomCheckMode.InternalProcessWord(
const AWord: WideString): Boolean;
var
AReplacement: WideString;
begin
Result := True;
if IsNeedIgnoreWord(AWord) then
begin
FMisspelledWord := AWord;
Ignore;
end
else
if IsNeedChangeWord(AWord, AReplacement) then
begin
Change(AReplacement);
PrevWord := AReplacement;
end
else
begin
if IsNeedDeleteWord(AWord) then
Delete
else
Result := False;
end;
end;
procedure TdxSpellCheckerCustomCheckMode.Ignore;
begin
Inc(FMisspelledStart, FMisspelledLen);
end;
procedure TdxSpellCheckerCustomCheckMode.IgnoreAll;
begin
SpellChecker.AddToIgnoreList(MisspelledWord);
Ignore;
end;
function TdxSpellCheckerCustomCheckMode.IsValidWord(
const AWord: WideString): Boolean;
begin
Result := SpellChecker.IsValidWord(AWord);
end;
procedure TdxSpellCheckerCustomCheckMode.UndoLast;
begin
end;
procedure TdxSpellCheckerCustomCheckMode.CreateParser;
begin
if FParser = nil then
FParser := GetParserClass.Create(SpellChecker);
Adapter.GetSpellingBounds(FSpellingStart, FSpellingEnd);
Dec(FSpellingStart);
Dec(FSpellingEnd);
Parser.UpdateTextInfo(Adapter);
end;
function TdxSpellCheckerCustomCheckMode.GetOwner: TPersistent;
begin
Result := FSpellChecker;
end;
function TdxSpellCheckerCustomCheckMode.GetParserClass: TdxSpellCheckerTextParserClass;
begin
Result := TdxSpellCheckerTextParser;
end;
function TdxSpellCheckerCustomCheckMode.IsNeedChangeWord(const AWord: WideString;
out AReplacement: WideString): Boolean;
var
AItem: TdxSpellCheckerReplacementItem;
begin
AItem := SpellChecker.ChangeList.FindReplacement(AWord);
Result := Assigned(AItem);
if Result then
AReplacement := AItem.Replacement;
end;
function TdxSpellCheckerCustomCheckMode.IsNeedDeleteWord(const AWord: WideString): Boolean;
begin
Result := SpellChecker.DeleteList.Find(AWord);
end;
function TdxSpellCheckerCustomCheckMode.IsNeedIgnoreWord(const AWord: WideString): Boolean;
begin
Result := SpellChecker.IgnoreList.Find(AWord);
end;
procedure TdxSpellCheckerCustomCheckMode.SaveSelection;
begin
end;
procedure TdxSpellCheckerCustomCheckMode.SelectMisspelledWord;
begin
if FMisspelledLen > 0 then
Adapter.SelStart := FMisspelledStart - 1;
Adapter.SelLength := FMisspelledLen;
end;
procedure TdxSpellCheckerCustomCheckMode.SelectMisspelledWordAfterUndo;
begin
SelectMisspelledWord;
end;
procedure TdxSpellCheckerCustomCheckMode.UpdateByDictionary(
ADictionary: TdxCustomSpellCheckerDictionary);
begin
end;
procedure TdxSpellCheckerCustomCheckMode.UpdateSpellingBounds(ADelta: Integer);
begin
if FMisspelledStart < FSpellingStart then
Inc(FSpellingStart, ADelta);
if FMisspelledStart < FSpellingEnd then
Inc(FSpellingEnd, ADelta);
ValidateSpellingBounds;
end;
procedure TdxSpellCheckerCustomCheckMode.UpdateTextInfo;
begin
Parser.UpdateTextInfo(Adapter);
FParser.FSpellingStart := SpellingStart;
FParser.FSpellingEnd := SpellingEnd;
end;
procedure TdxSpellCheckerCustomCheckMode.ValidateSpellingBounds;
begin
end;
function TdxSpellCheckerCustomCheckMode.GetPrevWord: WideString;
begin
Result := Parser.FPrevWord;
end;
procedure TdxSpellCheckerCustomCheckMode.SetPrevWord(const AValue: WideString);
begin
Parser.FPrevWord := AValue;
end;
procedure TdxSpellCheckerCustomCheckMode.SetSpellingEnd(
const AValue: Integer);
begin
FSpellingEnd := AValue;
end;
procedure TdxSpellCheckerCustomCheckMode.SetSpellingStart(
const AValue: Integer);
begin
FSpellingStart := AValue;
end;
{ TdxSpellCheckerDialogCheckMode }
constructor TdxSpellCheckerDialogCheckMode.Create(AOwner: TdxCustomSpellChecker; AAdapter: TdxSpellCheckerCustomEditAdapter);
begin
inherited Create(AOwner, AAdapter);
FUndoManager := TdxSpellCheckerUndoManager.Create;
FCheckedSelection := False;
end;
destructor TdxSpellCheckerDialogCheckMode.Destroy;
begin
FreeAndNil(FUndoManager);
Adapter.HideSelection := FSaveHideSelection;
Adapter.SelStart := FSaveSelStart;
Adapter.SelLength := FSaveSelLength;
inherited Destroy;
end;
function TdxSpellCheckerDialogCheckMode.CanUndo: Boolean;
begin
Result := FUndoManager.Count > 0;
end;
procedure TdxSpellCheckerDialogCheckMode.Change(const AWord: WideString);
begin
FUndoManager.Add(MisspelledWord, AWord, '', FMisspelledStart - 1);
inherited Change(AWord);
end;
procedure TdxSpellCheckerDialogCheckMode.CreateParser;
begin
inherited CreateParser;
if not SpellChecker.CheckingContainer then
begin
if SpellChecker.SpellingOptions.CheckFromCursorPos or IsCheckingSelectedText then
begin
SpellingStart := FSaveSelStart;
Parser.GetNextDelimiterPosition(FSpellingStart, -1);
end;
if IsCheckingSelectedText then
begin
SpellingEnd := FSaveSelStart + FSaveSelLength;
Parser.GetNextDelimiterPosition(FSpellingEnd, 1);
end;
end;
Inc(FSpellingStart);
Inc(FSpellingEnd);
UpdateTextInfo;
end;
procedure TdxSpellCheckerDialogCheckMode.Delete;
begin
FUndoManager.Add(' ' + MisspelledWord, '', PrevWord, FMisspelledStart - 2);
inherited Delete;
end;
procedure TdxSpellCheckerDialogCheckMode.Ignore;
begin
FUndoManager.Add(MisspelledWord, MisspelledWord, PrevWord, FMisspelledStart - 1);
inherited Ignore;
end;
function TdxSpellCheckerDialogCheckMode.ShowDialog: Integer;
begin
if not Adapter.EditorHandleAllocated then
Adapter.Post;
Result := 0;
end;
function TdxSpellCheckerDialogCheckMode.IsCheckingSelectedText: Boolean;
begin
Result := SpellChecker.SpellingOptions.CheckSelectedTextFirst and
(FSaveSelLength > 0) and not FCheckedSelection;
end;
procedure TdxSpellCheckerDialogCheckMode.UndoLast;
var
AItem: TdxSpellCheckerUndoItem;
begin
AItem := FUndoManager.Last;
if CanUndo and (AItem <> nil) then
begin
Adapter.SelStart := AItem.MisspelledWordPosition;
Adapter.SelLength := Length(AItem.Replacement);
UpdateSpellingBounds(Length(AItem.MisspelledWord) - Adapter.SelLength);
Adapter.SelText := AItem.MisspelledWord;
UpdateTextInfo;
SelectMisspelledWordAfterUndo;
ValidateSpellingBoundsAfterUndo;
PrevWord := AItem.PrevWord;
FUndoManager.UndoLast;
end;
end;
procedure TdxSpellCheckerDialogCheckMode.SaveSelection;
begin
FSaveHideSelection := Adapter.HideSelection;
FSaveSelLength := Adapter.SelLength;
FSaveSelStart := Adapter.SelStart;
Adapter.HideSelection := False;
end;
procedure TdxSpellCheckerDialogCheckMode.ValidateSpellingBounds;
procedure SetBeforeSelectionBounds;
begin
SpellingEnd := SpellingStart;
SpellingStart := 1;
FMisspelledStart := 1;
end;
var
ASpellingStart, ASpellingEnd: Integer;
begin
if (SpellChecker.SpellingOptions.CheckFromCursorPos or IsCheckingSelectedText) and not SpellChecker.CheckingContainer then
begin
Adapter.GetSpellingBounds(ASpellingStart, ASpellingEnd);
if ((FMisspelledStart >= ASpellingEnd) or (FMisspelledStart < SpellingStart)) and (SpellingStart > 1) and
not IsCheckingSelectedText then
begin
SetBeforeSelectionBounds;
UpdateTextInfo;
end
else
if (FMisspelledStart >= SpellingEnd) and IsCheckingSelectedText and
(ASpellingStart = SpellingStart) and (ASpellingEnd = SpellingEnd) and
(MessageDlg(cxGetResourceString(@sdxSpellCheckerSelectionCheckIsFinished), mtInformation, [mbYes, mbNo], 0) = mrYes) then
begin
if SpellingEnd = ASpellingEnd then
SetBeforeSelectionBounds
else
SpellingEnd := ASpellingEnd;
FCheckedSelection := True;
UpdateTextInfo;
end;
end;
end;
procedure TdxSpellCheckerDialogCheckMode.ValidateSpellingBoundsAfterUndo;
var
ASpellingStart, ASpellingEnd: Integer;
begin
Adapter.GetSpellingBounds(ASpellingStart, ASpellingEnd);
if (FMisspelledStart >= SpellingEnd) and (SpellingEnd < ASpellingEnd) then
begin
SpellingStart := SpellingEnd;
SpellingEnd := ASpellingEnd;
UpdateTextInfo;
end;
end;
function TdxSpellCheckerDialogCheckMode.GetLanguages: TdxSpellCheckerLanguages;
begin
Result := SpellChecker.Languages;
end;
{ TdxSpellCheckerOutlookCheckMode }
function TdxSpellCheckerOutlookCheckMode.ShowDialog: Integer;
begin
Result := dxShowOutlookSpellingDialog(SpellChecker);
inherited ShowDialog;
end;
procedure TdxSpellCheckerOutlookCheckMode.SelectMisspelledWordAfterUndo;
var
AItem: TdxSpellCheckerUndoItem;
begin
AItem := FUndoManager.Last;
if AItem <> nil then
FMisspelledStart := FMisspelledStart - Length(AItem.Replacement) + Length(AItem.MisspelledWord);
inherited;
end;
{ TdxSpellCheckerWordCheckMode }
procedure TdxSpellCheckerWordCheckMode.ChangeSentence(const ASentence: WideString);
var
AMisspelledSentence: TdxSpellCheckerSentence;
ADelta: Integer;
begin
AMisspelledSentence := MisspelledSentence;
FUndoManager.Add(AMisspelledSentence.Text, ASentence, '', AMisspelledSentence.StartTextPosition - 1);
Adapter.SelStart := AMisspelledSentence.StartTextPosition - 1;
Adapter.SelLength := Length(AMisspelledSentence.Text);
PrevWord := '';
ADelta := Length(ASentence) - Adapter.SelLength;
Adapter.SelText := ASentence;
UpdateSpellingBounds(ADelta);
UpdateTextInfo;
FMisspelledStart := AMisspelledSentence.StartTextPosition - 1;
end;
procedure TdxSpellCheckerWordCheckMode.SelectMisspelledWordAfterUndo;
var
AItem: TdxSpellCheckerUndoItem;
begin
AItem := FUndoManager.Last;
if AItem <> nil then
begin
FMisspelledStart := AItem.MisspelledWordPosition + 1;
FMisspelledLen := Length(AItem.MisspelledWord);
end;
inherited SelectMisspelledWordAfterUndo;
end;
function TdxSpellCheckerWordCheckMode.ShowDialog: Integer;
begin
Result := dxShowWordSpellingDialog(SpellChecker);
inherited ShowDialog;
end;
function TdxSpellCheckerWordCheckMode.GetMisspelledSentence: TdxSpellCheckerSentence;
begin
Result := Parser.GetSentence(FMisspelledStart);
end;
{ TdxSpellCheckerSuggestionBuilder }
constructor TdxSpellCheckerSuggestionBuilder.Create(
ADictionary: TdxCustomSpellCheckerDictionary);
begin
inherited Create;
FDictionary := ADictionary;
Alphabet := ADictionary.GetActiveAlphabet;
end;
procedure TdxSpellCheckerSuggestionBuilder.AddSuggestions(
const AWord: WideString; ASuggestions: TdxSpellCheckerSuggestionList);
begin
if (ASuggestions = nil) or (Length(AWord) = 0) then Exit;
FSuggestions := ASuggestions;
FWord := WideLowerCase(AWord);
DoAddSuggestions;
end;
function TdxSpellCheckerSuggestionBuilder.CanAddToSuggestions(
const ATestWord: WideString): Boolean;
begin
Result := Dictionary.HasWord(ATestWord);
end;
procedure TdxSpellCheckerSuggestionBuilder.SetAlphabet(const AValue: WideString);
var
I: Integer;
ALower: WideString;
begin
FAlphabet := '';
if Length(AValue) > 0 then
begin
ALower := WideLowerCase(AValue);
for I := 1 to Length(ALower) do
if WideCharPos(ALower[I], FAlphabet) = 0 then
FAlphabet := FAlphabet + ALower[I];
end;
end;
{ TdxNearMissStrategy }
procedure TdxNearMissStrategy.CheckAddToSuggestions(const ATestWord: WideString;
ADistance: Integer = 2);
begin
if CanAddToSuggestions(ATestWord) then
FSuggestions.Add(ATestWord, Dictionary, ADistance);
end;
procedure TdxNearMissStrategy.CheckDeleteLetter;
var
ATestWord: WideString;
ASymbol: WideChar;
ADeletePos, ALen: Integer;
begin
ALen := Length(FWord);
if ALen < 2 then Exit;
ADeletePos := 1;
repeat
ATestWord := FWord;
ASymbol := ATestWord[ADeletePos];
Delete(ATestWord, ADeletePos, 1);
CheckAddToSuggestions(ATestWord);
Inc(ADeletePos);
while (ADeletePos <= ALen) and (ASymbol = FWord[ADeletePos]) do
Inc(ADeletePos);
until ADeletePos > ALen;
end;
procedure TdxNearMissStrategy.InterchangeTwoLetters;
var
ATestWord: WideString;
I, ALen: Integer;
begin
ALen := Length(Word);
if ALen < 2 then Exit;
for I := 1 to ALen - 1 do
begin
if FWord[I] = Word[I + 1] then Continue;
ATestWord := Word;
ATestWord[I] := ATestWord[I + 1];
ATestWord[I + 1] := Word[I];
CheckAddToSuggestions(ATestWord);
end;
end;
procedure TdxNearMissStrategy.CheckChangeOneLetter;
var
ATestWord: WideString;
ASymbol: WideChar;
I, J: Integer;
begin
if Length(Alphabet) = 0 then Exit;
for I := 1 to Length(Word) do
for J := 1 to Length(Alphabet) do
begin
ASymbol := Alphabet[J];
if Word[I] <> ASymbol then
begin
ATestWord := Word;
ATestWord[I] := ASymbol;
CheckAddToSuggestions(ATestWord);
end;
end;
end;
procedure TdxNearMissStrategy.CheckInsertLetter;
var
ATestWord: WideString;
ASymbol: WideChar;
I, AInsertPos, ALen: Integer;
begin
if Length(Alphabet) = 0 then Exit;
ALen := Length(Word);
for I := 1 to Length(Alphabet) do
begin
ASymbol := Alphabet[I];
AInsertPos := 1;
repeat
ATestWord := Word;
while (AInsertPos <= ALen) and (ASymbol = ATestWord[AInsertPos]) do
Inc(AInsertPos);
Insert(ASymbol, ATestWord, AInsertPos);
CheckAddToSuggestions(ATestWord);
if AInsertPos > ALen then
Break
else
Inc(AInsertPos);
until False;
end;
end;
procedure TdxNearMissStrategy.CheckInsertSpace;
var
ATestWord1, ATestWord2: WideString;
I, ALen: Integer;
begin
ALen := Length(Word);
if ALen < 2 then Exit;
for I := 1 to ALen - 1 do
begin
ATestWord1 := Copy(Word, 1, I);
ATestWord2 := Copy(Word, I + 1, ALen);
if CanAddToSuggestions(ATestWord1) and CanAddToSuggestions(ATestWord2) then
FSuggestions.Add(ATestWord1 + ' ' + ATestWord2, Dictionary, 3);
end;
end;
procedure TdxNearMissStrategy.DoAddSuggestions;
begin
CheckInsertLetter;
CheckInsertSpace;
CheckDeleteLetter;
InterchangeTwoLetters;
CheckChangeOneLetter;
end;
{ TdxSpellCheckerWordList }
constructor TdxSpellCheckerWordList.Create(ALangID: Cardinal; ATableSize: Integer);
begin
inherited Create;
InitializeCriticalSection(FLock);
FLangID := ALangID;
FCount := 0;
FTableSize := ATableSize;
FTable := AllocMem(FTableSize * SizeOf(Integer));
end;
destructor TdxSpellCheckerWordList.Destroy;
begin
Clear;
FreeMem(FTable);
DeleteCriticalSection(FLock);
inherited Destroy;
end;
procedure TdxSpellCheckerWordList.Add(const S: WideString);
var
AIndex, ASrcLen, AWordLen: Integer;
AWord, ATemp, P: PWideChar;
begin
ASrcLen := Length(S);
if ASrcLen = 0 then Exit;
EnterCriticalSection(FLock);
try
P := Pointer(S);
AIndex := ElfHash(P) mod FTableSize;
AWord := FTable^[AIndex];
if AWord = nil then
FTable^[AIndex] := NewWord(P)
else
begin
repeat
AWordLen := WordLength(AWord);
if (AWordLen = ASrcLen) and
(CompareStringW(LangID, NORM_IGNORECASE, AWord, AWordLen, P, ASrcLen) = CSTR_EQUAL) then Exit;
ATemp := GetNextWord(AWord);
if ATemp = nil then
begin
SetNextWord(AWord, NewWord(P));
Break;
end;
AWord := ATemp;
until False;
end;
Inc(FCount);
finally
LeaveCriticalSection(FLock);
end;
end;
procedure TdxSpellCheckerWordList.Clear;
var
I: Integer;
AWord, ATemp: PWideChar;
begin
if Count = 0 then Exit;
EnterCriticalSection(FLock);
try
for I := 0 to FTableSize - 1 do
begin
AWord := FTable^[I];
while AWord <> nil do
begin
ATemp := AWord;
AWord := GetNextWord(AWord);
DisposeWord(ATemp);
end;
FTable^[I] := nil;
end;
FCount := 0;
finally
LeaveCriticalSection(FLock);
end;
end;
function TdxSpellCheckerWordList.Find(const S: WideString): Boolean;
begin
Result := FindWord(S) <> nil;
end;
procedure TdxSpellCheckerWordList.LoadFromStrings(AStrings: TStrings);
var
I: Integer;
begin
if AStrings = nil then Exit;
Clear;
for I := 0 to AStrings.Count - 1 do
Add(AStrings[I]);
end;
procedure TdxSpellCheckerWordList.SaveToStrings(AStrings: TStrings);
var
I: Integer;
AWord: PWideChar;
begin
if AStrings = nil then Exit;
AStrings.BeginUpdate;
try
AStrings.Clear;
for I := 0 to FTableSize - 1 do
begin
AWord := FTable^[I];
while AWord <> nil do
begin
AStrings.Add(AWord);
AWord := GetNextWord(AWord);
end;
end;
finally
AStrings.EndUpdate;
end;
end;
function TdxSpellCheckerWordList.ElfHash(P: PWideChar): Integer;
var
I: Integer;
ABuffer: array[0..256] of WideChar;
begin
LCMapStringW(LangID, LCMAP_LOWERCASE, P, -1, @ABuffer, SizeOf(ABuffer) div SizeOf(WideChar));
Result := 0;
Pointer(P) := @ABuffer;
while P^ <> #$00 do
begin
Result := (Result shl 4) + Ord(P^);
I := Result and $F0000000;
if (I <> 0) then
Result := Result xor (I shr 24);
Result := Result and (not I);
Inc(P);
end;
end;
function TdxSpellCheckerWordList.FindWord(const S: WideString): PWideChar;
var
AIndex, ASrcLen, AResultLen: Integer;
P: PWideChar;
begin
Result := nil;
ASrcLen := Length(S);
if ASrcLen = 0 then Exit;
P := Pointer(S);
AIndex := ElfHash(P) mod FTableSize;
Result := FTable^[AIndex];
while Result <> nil do
begin
AResultLen := WordLength(Result);
if (AResultLen = ASrcLen) and
(CompareStringW(LangID, NORM_IGNORECASE, Result, AResultLen, P, ASrcLen) = CSTR_EQUAL) then Exit;
Result := GetNextWord(Result);
end;
end;
function TdxSpellCheckerWordList.NewWord(S: PWideChar): PWideChar;
var
P : PWideChar;
ALength: Integer;
begin
Result := nil;
if S = nil then Exit;
P := S;
while (P^ <> #0) do Inc(P);
ALength := P - S;
if ALength > 0 then
begin
Result := AllocWord(ALength);
Inc(ALength); //include terminated null
Move(S^, Result^, ALength * SizeOf(WideChar));
end;
end;
function TdxSpellCheckerWordList.AllocWord(ACharCount: Cardinal): PWideChar;
var
ASize: Integer;
begin
ASize := (ACharCount + 1) * Sizeof(WideChar); //add terminated null
Inc(ASize, SizeOf(Cardinal) * 3); //Size, Next, Length
GetMem(Result, ASize);
Cardinal(Pointer(Result)^) := ASize; //Size
Inc(PChar(Result), SizeOf(Cardinal));
Pointer(Pointer(Result)^) := nil; //Next
Inc(PChar(Result), SizeOf(Cardinal));
Cardinal(Pointer(Result)^) := ACharCount; //Length
Inc(PChar(Result), SizeOf(Cardinal));
end;
procedure TdxSpellCheckerWordList.DisposeWord(AWord: PWideChar);
begin
if AWord <> nil then
begin
Dec(PChar(AWord), SizeOf(Cardinal) * 3);
FreeMem(AWord, Cardinal(Pointer(AWord)^));
end;
end;
function TdxSpellCheckerWordList.GetNextWord(AWord: PWideChar): Pointer;
begin
if AWord = nil then
Result := nil
else
begin
Dec(PChar(AWord), SizeOf(Cardinal) * 2);
Result := Pointer(Pointer(AWord)^);
end;
end;
procedure TdxSpellCheckerWordList.SetNextWord(AWord: PWideChar; AValue: Pointer);
begin
if AWord <> nil then
begin
Dec(PChar(AWord), SizeOf(Cardinal) * 2);
Pointer(Pointer(AWord)^) := AValue;
end;
end;
function TdxSpellCheckerWordList.WordLength(AWord: PWideChar): Integer;
begin
if AWord = nil then
Result := 0
else
begin
Dec(PChar(AWord), SizeOf(Cardinal));
Result := Cardinal(Pointer(AWord)^);
end;
end;
function TdxSpellCheckerWordList.GetCodePage: Cardinal;
begin
Result := LanguageToCodePage(FLangID);
end;
{ TdxDictionaryLoadThread }
constructor TdxDictionaryLoadThread.Create(
ADictionary: TdxCustomSpellCheckerDictionary);
begin
inherited Create(False);
FDictionary := ADictionary;
OnTerminate := Dictionary.ThreadDone;
end;
function TdxDictionaryLoadThread.IsLoadComplete: Boolean;
begin
Result := not Terminated and Dictionary.Loaded;
end;
procedure TdxDictionaryLoadThread.Execute;
begin
ResetException;
try
with Dictionary do
begin
try
Synchronize(UpdateLoadedOnLoadEvent);
if not Loaded then
FLoaded := DoLoad and not Terminated;
except
FLoaded := False;
raise;
end;
if Loaded then
Synchronize(LoadingComplete);
end;
except
HandleException;
end;
end;
{ TdxCustomSpellCheckerDictionary }
constructor TdxCustomSpellCheckerDictionary.Create(ASpellChecker: TdxCustomSpellChecker);
begin
inherited Create;
FSpellChecker := ASpellChecker;
FEnabled := True;
FCodePage := CP_ACP;
FWords := TdxSpellCheckerWordList.Create(CodePage, 269683);
Language := GetSystemDefaultLangID;
end;
destructor TdxCustomSpellCheckerDictionary.Destroy;
begin
FLoadThread.Free; //don't use FreeAndNil
FLoadThread := nil;
Unload;
FWords.Free;
inherited Destroy;
end;
procedure TdxCustomSpellCheckerDictionary.Assign(Source: TPersistent);
begin
if Source is TdxCustomSpellCheckerDictionary then
begin
FAlphabet := TdxCustomSpellCheckerDictionary(Source).Alphabet;
FCodePage := TdxCustomSpellCheckerDictionary(Source).CodePage;
FEnabled := TdxCustomSpellCheckerDictionary(Source).Enabled;
FLanguage := TdxCustomSpellCheckerDictionary(Source).Language;
end;
end;
procedure TdxCustomSpellCheckerDictionary.Activate;
begin
DoActivate;
end;
procedure TdxCustomSpellCheckerDictionary.Load(
AMode: TdxSpellCheckerDictionaryLoadMode = dlmDefault);
begin
case AMode of
dlmDefault:
begin
if SpellChecker.UseThreadedLoad then
LoadUsingThread
else
DirectLoad;
end;
dlmDirectLoad:
DirectLoad;
dlmThreadedLoad:
LoadUsingThread;
end;
end;
procedure TdxCustomSpellCheckerDictionary.Unload;
begin
if LoadThread <> nil then
LoadThread.Terminate;
if Loaded then
FLoaded := not DoUnload;
if not Loaded then
Cleanup;
Update;
end;
procedure TdxCustomSpellCheckerDictionary.Clear;
begin
Enabled := False;
Unload;
end;
function TdxCustomSpellCheckerDictionary.CanLoad: Boolean;
begin
Result := not Loaded and (FLoadThread = nil);
end;
procedure TdxCustomSpellCheckerDictionary.Cleanup;
begin
Words.Clear;
end;
function TdxCustomSpellCheckerDictionary.CreateSuggestionBuilder: TdxSpellCheckerSuggestionBuilder;
begin
Result := TdxNearMissStrategy.Create(Self);
end;
procedure TdxCustomSpellCheckerDictionary.DirectLoad;
begin
if not CanLoad then Exit;
ShowHourglassCursor;
try
try
FLoaded := DoLoadingEvent or DoLoad;
except
FLoaded := False;
raise;
end;
if Loaded then
LoadingComplete;
finally
HideHourglassCursor;
end;
end;
procedure TdxCustomSpellCheckerDictionary.DoActivate;
begin
Load;
Enabled := True;
end;
function TdxCustomSpellCheckerDictionary.DoLoad: Boolean;
begin
Result := False;
end;
procedure TdxCustomSpellCheckerDictionary.DoLoadedEvent;
begin
if Assigned(FOnLoaded) then
FOnLoaded(Self);
end;
function TdxCustomSpellCheckerDictionary.DoLoadingEvent: Boolean;
begin
Result := False;
if Assigned(FOnLoading) then
FOnLoading(Self, Result);
end;
function TdxCustomSpellCheckerDictionary.DoUnload: Boolean;
begin
Words.Clear;
Result := True;
end;
function TdxCustomSpellCheckerDictionary.GetActiveAlphabet: WideString;
begin
if Alphabet = '' then
Result := CreateDefaultAlphabet(CodePage)
else
Result := Alphabet;
end;
function TdxCustomSpellCheckerDictionary.GetDisplayName: string;
begin
Result := GetRegisteredDictionaryTypes.GetDescriptionByClass(ClassType);
if Result = '' then
Result := ClassName;
end;
procedure TdxCustomSpellCheckerDictionary.LoadingComplete;
begin
DoLoadedEvent;
Update;
end;
function TdxCustomSpellCheckerDictionary.LoadingTerminated: Boolean;
begin
Result := (FLoadThread <> nil) and FLoadThread.Terminated;
end;
procedure TdxCustomSpellCheckerDictionary.LoadUsingThread;
begin
if not CanLoad then Exit;
FreeAndNil(FLoadThread);
FLoadThread := TdxDictionaryLoadThread.Create(Self);
end;
procedure TdxCustomSpellCheckerDictionary.ThreadDone(Sender: TObject);
begin
if not LoadThread.IsLoadComplete then
Cleanup
else
SpellChecker.CheckCallEnabledDictionariesLoaded;
end;
procedure TdxCustomSpellCheckerDictionary.Update;
begin
SpellChecker.UpdateByDictionary(Self);
end;
procedure TdxCustomSpellCheckerDictionary.UpdateLoadedOnLoadEvent;
begin
FLoaded := DoLoadingEvent;
end;
function TdxCustomSpellCheckerDictionary.GetActive: Boolean;
begin
Result := Loaded and Enabled;
end;
function TdxCustomSpellCheckerDictionary.GetWordCount: Integer;
begin
Result := FWords.Count;
end;
function TdxCustomSpellCheckerDictionary.HasWord(
const AWord: WideString): Boolean;
begin
Result := FWords.Find(AWord);
end;
procedure TdxCustomSpellCheckerDictionary.SetEnabled(AValue: Boolean);
begin
if FEnabled <> AValue then
begin
FEnabled := AValue;
if Loaded then
Update;
end;
end;
procedure TdxCustomSpellCheckerDictionary.SetCodePage(AValue: Cardinal);
begin
if FCodePage <> AValue then
begin
FCodePage := AValue;
if Loaded then
begin
Unload;
Load;
Update;
end;
end;
end;
procedure TdxCustomSpellCheckerDictionary.SetLanguage(const AValue: DWORD);
begin
if FLanguage <> AValue then
begin
FLanguage := AValue;
FWords.LangID := FLanguage;
end;
end;
{ TdxUserSpellCheckerDictionary }
constructor TdxUserSpellCheckerDictionary.Create(
ASpellChecker: TdxCustomSpellChecker);
begin
inherited Create(ASpellChecker);
FOptions := [udSaveOnUnload];
end;
procedure TdxUserSpellCheckerDictionary.Assign(Source: TPersistent);
begin
inherited Assign(Source);
if Source is TdxUserSpellCheckerDictionary then
begin
DictionaryPath := TdxUserSpellCheckerDictionary(Source).DictionaryPath;
Options := TdxUserSpellCheckerDictionary(Source).Options;
end;
end;
procedure TdxUserSpellCheckerDictionary.AddWord(const AWord: WideString);
begin
Words.Add(AWord);
Update;
end;
procedure TdxUserSpellCheckerDictionary.LoadFromStrings(AStrings: TStrings);
begin
Words.LoadFromStrings(AStrings);
Update;
end;
procedure TdxUserSpellCheckerDictionary.SaveToStrings(AStrings: TStrings);
begin
if AStrings = nil then Exit;
Words.SaveToStrings(AStrings);
if AStrings is TStringList then
TStringList(AStrings).Sort;
end;
function TdxUserSpellCheckerDictionary.DoLoad: Boolean;
var
AStrings: TStrings;
begin
Result := True;
if not FileExists(DictionaryPath) then
if not (udFileMustExist in Options) then Exit;
AStrings := TStringList.Create;
try
AStrings.LoadFromFile(DictionaryPath);
Words.LoadFromStrings(AStrings);
finally
AStrings.Free;
end;
end;
function TdxUserSpellCheckerDictionary.DoUnload: Boolean;
var
AStrings: TStrings;
begin
Result := True;
if udSaveOnUnload in Options then
begin
AStrings := TStringList.Create;
try
Words.SaveToStrings(AStrings);
try
AStrings.SaveToFile(DictionaryPath);
except
if not (csDestroying in SpellChecker.ComponentState) then
raise;
end;
finally
AStrings.Free;
end;
end;
end;
function TdxUserSpellCheckerDictionary.GetDisplayName: string;
var
AFileName: TFileName;
begin
Result := inherited GetDisplayName;
AFileName := ExtractFileName(DictionaryPath);
if AFileName <> '' then
Result := Format('%s (%s)', [Result, AFileName]);
end;
{ TdxSpellCheckerDictionaryItem }
destructor TdxSpellCheckerDictionaryItem.Destroy;
begin
FreeAndNil(FDictionaryType);
inherited Destroy;
end;
procedure TdxSpellCheckerDictionaryItem.Assign(Source: TPersistent);
begin
if Source is TdxSpellCheckerDictionaryItem then
begin
DictionaryTypeClassName := TdxSpellCheckerDictionaryItem(Source).DictionaryTypeClassName;
DictionaryType := TdxSpellCheckerDictionaryItem(Source).DictionaryType;
end;
end;
function TdxSpellCheckerDictionaryItem.GetDisplayName: string;
begin
if FDictionaryType <> nil then
Result := FDictionaryType.GetDisplayName
else
Result := inherited GetDisplayName;
end;
procedure TdxSpellCheckerDictionaryItem.RecreateDictionaryType;
begin
FreeAndNil(FDictionaryType);
if FDictionaryTypeClass <> nil then
FDictionaryType := FDictionaryTypeClass.Create(Collection.SpellChecker);
end;
function TdxSpellCheckerDictionaryItem.GetCollection: TdxSpellCheckerDictionaries;
begin
Result := TdxSpellCheckerDictionaries(inherited Collection);
end;
function TdxSpellCheckerDictionaryItem.GetDictionaryTypeClassName: string;
begin
if FDictionaryType = nil then
Result := ''
else
Result := FDictionaryType.ClassName;
end;
procedure TdxSpellCheckerDictionaryItem.SetDictionaryType(
AValue: TdxCustomSpellCheckerDictionary);
begin
if (FDictionaryType <> nil) and (AValue <> nil) then
FDictionaryType.Assign(AValue);
end;
procedure TdxSpellCheckerDictionaryItem.SetDictionaryTypeClass(
AValue: TdxCustomSpellCheckerDictionaryClass);
begin
if FDictionaryTypeClass <> AValue then
begin
FDictionaryTypeClass := AValue;
RecreateDictionaryType;
end;
end;
procedure TdxSpellCheckerDictionaryItem.SetDictionaryTypeClassName(
const AValue: string);
begin
if not SameText(DictionaryTypeClassName, AValue) then
begin
with GetRegisteredDictionaryTypes do
DictionaryTypeClass := TdxCustomSpellCheckerDictionaryClass(FindByClassName(AValue));
end;
end;
{ TdxSpellCheckerDictionaries }
constructor TdxSpellCheckerDictionaries.Create(ASpellChecker: TdxCustomSpellChecker);
begin
inherited Create(TdxSpellCheckerDictionaryItem);
FSpellChecker := ASpellChecker;
end;
function TdxSpellCheckerDictionaries.Add: TdxSpellCheckerDictionaryItem;
begin
Result := TdxSpellCheckerDictionaryItem(inherited Add);
end;
function TdxSpellCheckerDictionaries.GetNamePath: string;
var
S: string;
begin
S := SpellChecker.Name;
if S = '' then
S := SpellChecker.GetNamePath;
Result := S + '.' + 'Items';
end;
function TdxSpellCheckerDictionaries.GetOwner: TPersistent;
begin
Result := SpellChecker;
end;
function TdxSpellCheckerDictionaries.GetItem(
Index: Integer): TdxSpellCheckerDictionaryItem;
begin
Result := TdxSpellCheckerDictionaryItem(inherited Items[Index]);
end;
procedure TdxSpellCheckerDictionaries.SetItem(Index: Integer;
AValue: TdxSpellCheckerDictionaryItem);
begin
inherited Items[Index] := AValue;
end;
{ TdxSpellCheckerSpellingOptions }
constructor TdxSpellCheckerSpellingOptions.Create(
ASpellChecker: TdxCustomSpellChecker);
begin
inherited Create;
FSpellChecker := ASpellChecker;
FIgnoreMixedCaseWords := True;
FIgnoreUpperCaseWords := True;
FIgnoreMarkupTags := True;
FIgnoreRepeatedWords := False;
FCheckSelectedTextFirst := True;
FIgnoreUrls := True;
FCheckFromCursorPos := False;
FIgnoreEmails := True;
FIgnoreWordsWithNumbers := True;
end;
procedure TdxSpellCheckerSpellingOptions.Assign(Source: TPersistent);
begin
if Source is TdxSpellCheckerSpellingOptions then
begin
FIgnoreMixedCaseWords := TdxSpellCheckerSpellingOptions(Source).IgnoreMixedCaseWords;
FIgnoreUpperCaseWords := TdxSpellCheckerSpellingOptions(Source).IgnoreUpperCaseWords;
FIgnoreMarkupTags := TdxSpellCheckerSpellingOptions(Source).IgnoreMarkupTags;
FIgnoreRepeatedWords := TdxSpellCheckerSpellingOptions(Source).IgnoreRepeatedWords;
FCheckSelectedTextFirst := TdxSpellCheckerSpellingOptions(Source).CheckSelectedTextFirst;
FIgnoreUrls := TdxSpellCheckerSpellingOptions(Source).IgnoreUrls;
FCheckFromCursorPos := TdxSpellCheckerSpellingOptions(Source).CheckFromCursorPos;
FIgnoreEmails := TdxSpellCheckerSpellingOptions(Source).IgnoreEmails;
FIgnoreWordsWithNumbers := TdxSpellCheckerSpellingOptions(Source).IgnoreWordsWithNumbers;
end;
end;
procedure TdxSpellCheckerSpellingOptions.Changed;
begin
SpellChecker.SpellingOptionsChanged;
DoChanged;
end;
procedure TdxSpellCheckerSpellingOptions.DoChanged;
begin
if Assigned(FOnChanged) then
FOnChanged(Self);
end;
procedure TdxSpellCheckerSpellingOptions.PopulateRules(
ARules: TdxSpellCheckerRules; AParser: TdxSpellCheckerTextParser);
begin
if AParser = nil then
Exit;
if not IgnoreRepeatedWords then
ARules.Add(TdxSpellCheckerRepeatedWordsRule.Create(AParser));
if IgnoreEmails then
ARules.Add(TdxSpellCheckerIgnoreEmailRule.Create(AParser));
if IgnoreMixedCaseWords then
ARules.Add(TdxSpellCheckerIgnoreMixedCaseWordsRule.Create(AParser));
if IgnoreUpperCaseWords then
ARules.Add(TdxSpellCheckerIgnoreUpperCaseWordsRule.Create(AParser));
if IgnoreUrls then
ARules.Add(TdxSpellCheckerIgnoreUrlRule.Create(AParser));
if IgnoreWordsWithNumbers then
ARules.Add(TdxSpellCheckerIgnoreWordsWithNumbersRule.Create(AParser));
end;
procedure TdxSpellCheckerSpellingOptions.SetCheckFromCursorPos(
AValue: Boolean);
begin
if FCheckFromCursorPos <> AValue then
begin
FCheckFromCursorPos := AValue;
Changed;
end;
end;
procedure TdxSpellCheckerSpellingOptions.SetCheckSelectedTextFirst(
AValue: Boolean);
begin
if FCheckSelectedTextFirst <> AValue then
begin
FCheckSelectedTextFirst := AValue;
Changed;
end;
end;
procedure TdxSpellCheckerSpellingOptions.SetIgnoreEmails(
AValue: Boolean);
begin
if FIgnoreEmails <> AValue then
begin
FIgnoreEmails := AValue;
Changed;
end;
end;
procedure TdxSpellCheckerSpellingOptions.SetIgnoreMarkupTags(
AValue: Boolean);
begin
if FIgnoreMarkupTags <> AValue then
begin
FIgnoreMarkupTags := AValue;
Changed;
end;
end;
procedure TdxSpellCheckerSpellingOptions.SetIgnoreMixedCaseWords(
AValue: Boolean);
begin
if FIgnoreMixedCaseWords <> AValue then
begin
FIgnoreMixedCaseWords := AValue;
Changed;
end;
end;
procedure TdxSpellCheckerSpellingOptions.SetIgnoreRepeatedWords(
AValue: Boolean);
begin
if FIgnoreRepeatedWords <> AValue then
begin
FIgnoreRepeatedWords := AValue;
Changed;
end;
end;
procedure TdxSpellCheckerSpellingOptions.SetIgnoreUpperCaseWords(
AValue: Boolean);
begin
if FIgnoreUpperCaseWords <> AValue then
begin
FIgnoreUpperCaseWords := AValue;
Changed;
end;
end;
procedure TdxSpellCheckerSpellingOptions.SetIgnoreUrls(
AValue: Boolean);
begin
if FIgnoreUrls <> AValue then
begin
FIgnoreUrls := AValue;
Changed;
end;
end;
procedure TdxSpellCheckerSpellingOptions.SetIgnoreWordsWithNumbers(
AValue: Boolean);
begin
if FIgnoreWordsWithNumbers <> AValue then
begin
FIgnoreWordsWithNumbers := AValue;
Changed;
end;
end;
{ TdxSpellCheckerCheckAsYouTypeOptions }
constructor TdxSpellCheckerCheckAsYouTypeOptions.Create(
ASpellChecker: TdxCustomSpellChecker);
begin
FSpellChecker := ASpellChecker;
FSuggestionCount := 5;
FUnderlineColor := clRed;
FUnderlineStyle := usAuto;
FModifyControlPopupMenu := True;
FPopupMenuItems := [scmiAddToDictionary, scmiDelete, scmiIgnoreAll, scmiSpelling, scmiSuggestions];
end;
procedure TdxSpellCheckerCheckAsYouTypeOptions.Assign(Source: TPersistent);
begin
if Source is TdxSpellCheckerCheckAsYouTypeOptions then
begin
FSuggestionCount := TdxSpellCheckerCheckAsYouTypeOptions(Source).FSuggestionCount;
FUnderlineColor := TdxSpellCheckerCheckAsYouTypeOptions(Source).FUnderlineColor;
FUnderlineStyle := TdxSpellCheckerCheckAsYouTypeOptions(Source).FUnderlineStyle;
FModifyControlPopupMenu := TdxSpellCheckerCheckAsYouTypeOptions(Source).ModifyControlPopupMenu;
FPopupMenu := TdxSpellCheckerCheckAsYouTypeOptions(Source).PopupMenu;
FPopupMenuItems := TdxSpellCheckerCheckAsYouTypeOptions(Source).PopupMenuItems;
Changed;
end;
end;
procedure TdxSpellCheckerCheckAsYouTypeOptions.Changed;
begin
if SpellChecker.CheckAsYouTypeManager <> nil then
SpellChecker.CheckAsYouTypeManager.DoOptionsChanged;
DoChanged;
end;
procedure TdxSpellCheckerCheckAsYouTypeOptions.DoChanged;
begin
if Assigned(FOnChanged) then
FOnChanged(Self);
end;
procedure TdxSpellCheckerCheckAsYouTypeOptions.Notification(AComponent: TComponent; AOperation: TOperation);
begin
if (AComponent = FPopupMenu) and (AOperation = opRemove) then
PopupMenu := nil;
end;
procedure TdxSpellCheckerCheckAsYouTypeOptions.SetActive(AValue: Boolean);
begin
if FActive <> AValue then
begin
FActive := AValue;
SpellChecker.UpdateCheckAsYouTypeManagerState;
Changed;
end;
end;
procedure TdxSpellCheckerCheckAsYouTypeOptions.SetPopupMenu(AValue: TComponent);
begin
if FPopupMenu <> AValue then
begin
if (FPopupMenu <> nil) and not (csDestroying in FPopupMenu.ComponentState) then
FPopupMenu.RemoveFreeNotification(SpellChecker);
FPopupMenu := AValue;
if FPopupMenu <> nil then
FPopupMenu.FreeNotification(SpellChecker);
Changed;
end;
end;
procedure TdxSpellCheckerCheckAsYouTypeOptions.SetModifyControlPopupMenu(AValue: Boolean);
begin
if AValue <> FModifyControlPopupMenu then
begin
FModifyControlPopupMenu := AValue;
Changed;
end;
end;
procedure TdxSpellCheckerCheckAsYouTypeOptions.SetPopupMenuItems(AValue: TdxSpellCheckerPopupMenuItems);
begin
if AValue <> FPopupMenuItems then
begin
FPopupMenuItems := AValue;
Changed;
end;
end;
procedure TdxSpellCheckerCheckAsYouTypeOptions.SetSuggestionCount(AValue: Integer);
begin
if AValue <> FSuggestionCount then
begin
FSuggestionCount := AValue;
Changed;
end;
end;
procedure TdxSpellCheckerCheckAsYouTypeOptions.SetUnderlineColor(AValue: TColor);
begin
if FUnderlineColor <> AValue then
begin
FUnderlineColor := AValue;
Changed;
end;
end;
procedure TdxSpellCheckerCheckAsYouTypeOptions.SetUnderlineStyle(
AValue: TdxSpellCheckerUnderlineStyle);
begin
if FUnderlineStyle <> AValue then
begin
FUnderlineStyle := AValue;
Changed;
end;
end;
{ TdxCustomSpellChecker }
function IsContainer(AComponent: TComponent): Boolean;
begin
Result := (AComponent is TCustomForm) or (AComponent is TCustomFrame) or
(AComponent is TDataModule);
end;
function IsSpellCheckerAlreadyExists(AOwner: TComponent;
AInstance: TdxCustomSpellChecker): Boolean;
var
I: Integer;
begin
Result := False;
for I := 0 to AOwner.ComponentCount - 1 do
if (AOwner.Components[I] <> AInstance) and (AOwner.Components[I] is TdxCustomSpellChecker) then
begin
Result := True;
Break;
end;
end;
procedure SpellCheckerCreatingError;
begin
raise Exception.Create(cxGetResourceString(@sdxSpellCheckerMoreThanOne));
end;
constructor TdxCustomSpellChecker.Create(AOwner: TComponent);
var
I: Integer;
AComponent: TComponent;
begin
FCreating := True;
if IsContainer(AOwner) and IsSpellCheckerAlreadyExists(AOwner, Self) then
SpellCheckerCreatingError;
for I := 0 to Application.ComponentCount - 1 do
begin
AComponent := Application.Components[I];
if IsContainer(AComponent) and IsSpellCheckerAlreadyExists(AComponent, Self) then
SpellCheckerCreatingError;
end;
FCreating := False;
inherited Create(AOwner);
FAutoLoadDictionaries := False;
FSpellingFormType := sftOutlook;
FDictionaryItems := TdxSpellCheckerDictionaries.Create(Self);
FSimilarity := CreateSimilarity;
FRules := TdxSpellCheckerRules.Create;
FDialogLookAndFeel := TcxLookAndFeel.Create(nil);
FSpellingOptions := CreateSpellingOptions;
FCheckAsYouTypeOptions := TdxSpellCheckerCheckAsYouTypeOptions.Create(Self);
SpellingOptionsChanged;
FLanguages := TdxSpellCheckerLanguages.Create;
FChangeList := TdxSpellCheckerReplacementList.Create;
FDeleteList := TdxSpellCheckerWordList.Create(LANG_SYSTEM_DEFAULT, 257);
FIgnoreList := TdxSpellCheckerWordList.Create(LANG_SYSTEM_DEFAULT, 257);
end;
destructor TdxCustomSpellChecker.Destroy;
begin
if not FCreating then
begin
FreeAndNil(FChangeList);
FreeAndNil(FDeleteList);
FreeAndNil(FIgnoreList);
FCheckAsYouTypeOptions.Active := False;
UnloadDictionaries;
FreeAndNil(FLanguages);
FreeAndNil(FSpellingOptions);
FreeAndNil(FRules);
FreeAndNil(FSimilarity);
FreeAndNil(FCheckAsYouTypeOptions);
FreeAndNil(FDialogLookAndFeel);
FreeAndNil(FDictionaryItems);
end;
inherited Destroy;
end;
procedure TdxCustomSpellChecker.Check(AEdit: TCustomEdit);
var
AEditAdapter: TdxSpellCheckerEditAdapter;
begin
AEditAdapter := TdxSpellCheckerEditAdapter.Create(AEdit);
try
InternalCheck(AEditAdapter);
finally
FreeAndNil(AEditAdapter);
end;
end;
procedure TdxCustomSpellChecker.Check(AEdit: TcxCustomTextEdit);
var
AEditAdapter: TdxSpellCheckercxTextEditAdapter;
begin
if AEdit is TcxCustomRichEdit then
AEditAdapter := TdxSpellCheckercxRichEditAdapter.Create(AEdit)
else
AEditAdapter := TdxSpellCheckercxTextEditAdapter.Create(AEdit);
try
InternalCheck(AEditAdapter);
finally
FreeAndNil(AEditAdapter);
end;
end;
procedure TdxCustomSpellChecker.CheckContainer(AContainer: TWinControl; ARecursive: Boolean);
begin
if AContainer = nil then Exit;
FCheckingContainer := True;
try
FCheckGroupMode := True;
FLastDialogResult := mrOk;
try
DoCheckContainer(AContainer, ARecursive);
finally
FCheckGroupMode := False;
end;
if FLastDialogResult <> mrCancel then
SpellingComplete;
finally
FCheckingContainer := False;
end;
end;
procedure TdxCustomSpellChecker.AddToIgnoreList(const AWord: WideString);
begin
IgnoreList.Add(AWord);
if Assigned(CheckAsYouTypeManager) then
CheckAsYouTypeManager.Refresh;
end;
procedure TdxCustomSpellChecker.AddWordToUserDictionary(
const AWord: WideString);
var
AUserDictionary: TdxUserSpellCheckerDictionary;
begin
AUserDictionary := FindFirstEnabledUserDictionary;
if AUserDictionary <> nil then
begin
if not DoAddWord(AUserDictionary, AWord) then
AUserDictionary.AddWord(AWord);
end;
end;
function TdxCustomSpellChecker.FindDictionaryByWord(const AWord: WideString): TdxCustomSpellCheckerDictionary;
var
I: Integer;
ADictionary: TdxCustomSpellCheckerDictionary;
begin
Result := nil;
for I := 0 to ActiveDictionaryCount - 1 do
begin
ADictionary := ActiveDictionaries[I];
if ADictionary.HasWord(AWord) then
begin
Result := ADictionary;
Break;
end;
end;
end;
function TdxCustomSpellChecker.FindFirstEnabledUserDictionary: TdxUserSpellCheckerDictionary;
var
I: Integer;
ADictionary: TdxUserSpellCheckerDictionary;
begin
Result := nil;
for I := 0 to UserDictionaryCount - 1 do
begin
ADictionary := UserDictionaries[I];
if ADictionary.Enabled then
begin
Result := ADictionary;
Break;
end;
end;
end;
function TdxCustomSpellChecker.GetSuggestions(const AWord: WideString): TdxSpellCheckerSuggestionList;
var
I: Integer;
ADictionary: TdxCustomSpellCheckerDictionary;
begin
Result := TdxSpellCheckerSuggestionList.Create;
if not HasWordInDictionaries(AWord) then
begin
for I := 0 to ActiveDictionaryCount - 1 do
begin
ADictionary := ActiveDictionaries[I];
with ADictionary.CreateSuggestionBuilder do
try
AddSuggestions(AWord, Result);
finally
Free;
end;
end;
Result.RemoveDuplicates;
Result.FixCapitalization(AWord);
DoGetSuggestions(Result);
end;
end;
function TdxCustomSpellChecker.HasWordInDictionaries(const AWord: WideString): Boolean;
begin
Result := FindDictionaryByWord(AWord) <> nil;
end;
function TdxCustomSpellChecker.HasEnabledUserDictionary: Boolean;
begin
Result := FindFirstEnabledUserDictionary <> nil;
end;
function TdxCustomSpellChecker.IsValidWord(const AWord: WideString): Boolean;
begin
Result := False;
if not DoCheckWord(AWord, Result) then
Result := Rules.IsValid(AWord);
end;
procedure TdxCustomSpellChecker.PopulateLanguages(AList: TStrings);
var
I: Integer;
ADictionary: TdxCustomSpellCheckerDictionary;
ALanguageName: string;
ALangID: Cardinal;
begin
for I := 0 to DictionaryItems.Count - 1 do
begin
ADictionary := Dictionaries[I];
if ADictionary is TdxUserSpellCheckerDictionary then
Continue;
if ADictionary.Language <> 0 then
ALangID := ADictionary.Language
else
ALangID := Languages.GetDefaultLanguageLCID;
ALanguageName := Languages.NameFromLocaleID[ALangID];
if AList.IndexOf(ALanguageName) < 0 then
AList.AddObject(ALanguageName, Pointer(ALangID));
end;
end;
procedure TdxCustomSpellChecker.ShowSpellingCompleteMessage;
begin
ShowMessage(cxGetResourceString(@sdxSpellCheckerSpellingComplete));
end;
procedure TdxCustomSpellChecker.LoadDictionaries(AIgnoreDisabled: Boolean = True);
begin
if UseThreadedLoad then
LoadDictionariesUsingThread(AIgnoreDisabled)
else
LoadDictionariesDirect(AIgnoreDisabled);
end;
procedure TdxCustomSpellChecker.UnloadDictionaries;
var
I: Integer;
begin
ShowHourglassCursor;
try
for I := 0 to DictionaryCount - 1 do
Dictionaries[I].Unload;
finally
HideHourglassCursor;
end;
end;
function TdxCustomSpellChecker.GetTwoWordsDistance(
const AWord1, AWord2: WideString): Integer;
begin
Result := FSimilarity.GetDistance(AWord1, AWord2);
end;
procedure TdxCustomSpellChecker.CheckCallEnabledDictionariesLoaded;
begin
if Assigned(CheckAsYouTypeManager) then
CheckAsYouTypeManager.Refresh(True);
if ActiveDictionaryCount = EnabledDictionaryCount then
DoEnabledDictionariesLoaded;
end;
function TdxCustomSpellChecker.CreateSimilarity: TdxStringSimilarityCalculator;
begin
Result := TdxStringSimilarityCalculator.Create;
end;
function TdxCustomSpellChecker.CreateSpellingOptions: TdxSpellCheckerSpellingOptions;
begin
Result := TdxSpellCheckerSpellingOptions.Create(Self);
end;
procedure TdxCustomSpellChecker.BeginManualCheck;
begin
if Assigned(CheckAsYouTypeManager) then
CheckAsYouTypeManager.BeginManualCheck;
end;
procedure TdxCustomSpellChecker.EndManualCheck;
begin
if Assigned(CheckAsYouTypeManager) then
CheckAsYouTypeManager.EndManualCheck;
end;
function TdxCustomSpellChecker.DoAddWord(AUserDictionary: TdxUserSpellCheckerDictionary;
const AWord: WideString): Boolean;
begin
Result := False;
if Assigned(FOnAddWord) then
FOnAddWord(AUserDictionary, AWord, Result);
end;
procedure TdxCustomSpellChecker.DoAfterCheck;
begin
if Assigned(FOnAfterCheck) then
FOnAfterCheck(Self);
end;
procedure TdxCustomSpellChecker.DoBeforeCheck;
begin
if Assigned(FOnBeforeCheck) then
FOnBeforeCheck(Self);
end;
procedure TdxCustomSpellChecker.DoCheck(ADialogCheckMode: TdxSpellCheckerDialogCheckMode);
begin
if ActiveDictionaryCount = 0 then
raise EdxSpellCheckerException.Create(cxGetResourceString(@sdxSpellCheckerNoActiveDictionaries));
DoBeforeCheck;
try
ValidateRules(ADialogCheckMode.Parser);
if not ADialogCheckMode.GetNextMisspelledWord then
begin
SpellingComplete;
FLastDialogResult := mrOk;
end
else
begin
FLastDialogResult := ADialogCheckMode.ShowDialog;
if FLastDialogResult = mrOk then
SpellingComplete;
end;
finally
DoAfterCheck;
end;
end;
procedure TdxCustomSpellChecker.DoCheckAsYouTypeFinish(AControl: TWinControl);
begin
if Assigned(OnCheckAsYouTypeFinish) then
OnCheckAsYouTypeFinish(Self, AControl);
end;
function TdxCustomSpellChecker.DoCheckAsYouTypePopup(APopup: TComponent): Boolean;
begin
Result := False;
if Assigned(FOnCheckAsYouTypePopup) then
FOnCheckAsYouTypePopup(Self, APopup, Result);
end;
function TdxCustomSpellChecker.DoCheckAsYouTypeStart(AControl: TWinControl): Boolean;
begin
Result := Assigned(AControl);
if Result and Assigned(OnCheckAsYouTypeStart) then
OnCheckAsYouTypeStart(Self, AControl, Result);
end;
procedure TdxCustomSpellChecker.DoCheckContainer(AContainer: TWinControl;
ARecursive: Boolean);
function StopCheck(AContinue: Boolean): Boolean;
begin
Result := not AContinue or (FLastDialogResult <> mrOk);
if Result then
FLastDialogResult := mrCancel;
end;
var
I: Integer;
AControl: TWinControl;
AContinue: Boolean;
L: TList;
begin
L := TList.Create;
try
AContainer.GetTabOrderList(L);
for I := 0 to L.Count - 1 do
begin
AControl := TWinControl(L[I]);
if not AControl.CanFocus or (not ARecursive and (AControl.Parent <> AContainer)) then
Continue;
AContinue := True;
if (AControl is TcxCustomTextEdit) then
begin
if DoCheckControlInContainer(AControl, AContinue) then
Check(TcxCustomTextEdit(AControl));
if StopCheck(AContinue) then
Break;
end
else
if (AControl is TCustomEdit) then
begin
if DoCheckControlInContainer(GetInnerControlContainer(AControl), AContinue) then
Check(TCustomEdit(AControl));
if StopCheck(AContinue) then
Break;
end;
end;
finally
L.Free;
end;
end;
function TdxCustomSpellChecker.DoCheckControlInContainer(AControl: TWinControl;
var AContinue: Boolean): Boolean;
begin
Result := True;
if Assigned(FOnCheckControlInContainer) then
FOnCheckControlInContainer(Self, AControl, Result, AContinue);
end;
function TdxCustomSpellChecker.DoCheckWord(const AWord: WideString; var AValid: Boolean): Boolean;
begin
Result := False;
if Assigned(FOnCheckWord) then
FOnCheckWord(Self, AWord, AValid, Result);
end;
procedure TdxCustomSpellChecker.DoEnabledDictionariesLoaded;
begin
if Assigned(FOnEnabledDictionariesLoaded) then
FOnEnabledDictionariesLoaded(Self);
end;
procedure TdxCustomSpellChecker.DoGetSuggestions(ASuggestions: TdxSpellCheckerSuggestionList);
begin
if Assigned(FOnGetSuggestions) then
FOnGetSuggestions(Self, ASuggestions);
end;
function TdxCustomSpellChecker.DoSpellingComplete: Boolean;
begin
Result := False;
if Assigned(FOnSpellingComplete) then
FOnSpellingComplete(Self, Result);
end;
function TdxCustomSpellChecker.GetDialogCheckModeClass: TdxSpellCheckerCustomCheckModeClass;
begin
if sftWord = SpellingFormType then
Result := TdxSpellCheckerWordCheckMode
else
Result := TdxSpellCheckerOutlookCheckMode;
end;
procedure TdxCustomSpellChecker.InternalCheck(AAdapter: TdxSpellCheckerCustomEditAdapter);
begin
if ActiveDictionaryCount = 0 then
Exit;
BeginManualCheck;
try
FCheckMode := GetDialogCheckModeClass.Create(Self, AAdapter);
try
DoCheck(FCheckMode as TdxSpellCheckerDialogCheckMode);
finally
FreeAndNil(FCheckMode);
end;
finally
EndManualCheck;
end;
end;
procedure TdxCustomSpellChecker.LoadDictionariesDirect(
AIgnoreDisabled: Boolean = True);
var
I: Integer;
ADictionary: TdxCustomSpellCheckerDictionary;
begin
ShowHourglassCursor;
try
for I := 0 to DictionaryCount - 1 do
begin
ADictionary := Dictionaries[I];
if ADictionary.Enabled or not AIgnoreDisabled then
ADictionary.Load;
end;
finally
HideHourglassCursor;
end;
end;
procedure TdxCustomSpellChecker.LoadDictionariesUsingThread(
AIgnoreDisabled: Boolean = True);
var
I: Integer;
ADictionary: TdxCustomSpellCheckerDictionary;
begin
for I := 0 to DictionaryCount - 1 do
begin
ADictionary := Dictionaries[I];
if ADictionary.Enabled or not AIgnoreDisabled then
ADictionary.LoadUsingThread;
end;
end;
procedure TdxCustomSpellChecker.Loaded;
begin
inherited Loaded;
if AutoLoadDictionaries and not (csDesigning in ComponentState) then
LoadDictionaries;
end;
procedure TdxCustomSpellChecker.Notification(AComponent: TComponent; Operation: TOperation);
begin
inherited Notification(AComponent, Operation);
if CheckAsYouTypeOptions <> nil then
CheckAsYouTypeOptions.Notification(AComponent, Operation);
end;
procedure TdxCustomSpellChecker.SpellingOptionsChanged;
begin
if Assigned(CheckMode) then
ValidateRules(CheckMode.Parser);
if Assigned(CheckAsYouTypeManager) then
CheckAsYouTypeManager.SpellingOptionsChanged;
end;
procedure TdxCustomSpellChecker.ValidateRules(AParser: TdxSpellCheckerTextParser);
begin
Rules.Clear;
if Assigned(AParser) then
begin
SpellingOptions.PopulateRules(Rules, AParser);
Rules.Add(TdxSpellCheckerWordExistsRule.Create(AParser));
end;
end;
procedure TdxCustomSpellChecker.UpdateByDictionary(
ADictionary: TdxCustomSpellCheckerDictionary);
begin
if Assigned(CheckMode) then
CheckMode.UpdateByDictionary(ADictionary);
if Assigned(CheckAsYouTypeManager) then
CheckAsYouTypeManager.Reset;
end;
procedure TdxCustomSpellChecker.UpdateCheckAsYouTypeManagerState;
begin
FreeAndNil(FCheckAsYouTypeManager);
if CheckAsYouTypeOptions.Active then
begin
FCheckAsYouTypeManager := TdxSpellCheckerCheckAsYouTypeManager.Create(Self);
FCheckAsYouTypeManager.DoOptionsChanged;
end;
end;
procedure TdxCustomSpellChecker.SpellingComplete;
begin
if not FCheckGroupMode and not DoSpellingComplete then
ShowSpellingCompleteMessage;
end;
function TdxCustomSpellChecker.GetActiveDictionary(
Index: Integer): TdxCustomSpellCheckerDictionary;
var
I, J: Integer;
ADictionary: TdxCustomSpellCheckerDictionary;
begin
Result := nil;
J := 0;
for I := 0 to DictionaryItems.Count - 1 do
begin
ADictionary := DictionaryItems[I].DictionaryType;
if (ADictionary <> nil) and (ADictionary.Active) then
begin
if J = Index then
begin
Result := ADictionary;
Exit;
end;
Inc(J);
end;
end;
end;
function TdxCustomSpellChecker.GetActiveDictionaryCount: Integer;
var
I: Integer;
ADictionary: TdxCustomSpellCheckerDictionary;
begin
Result := 0;
for I := 0 to DictionaryItems.Count - 1 do
begin
ADictionary := DictionaryItems[I].DictionaryType;
if (ADictionary <> nil) and (ADictionary.Active) then
Inc(Result);
end;
end;
function TdxCustomSpellChecker.GetCheckMode: TdxSpellCheckerCustomCheckMode;
begin
Result := FCheckMode;
if (Result = nil) and Assigned(CheckAsYouTypeManager) then
Result := CheckAsYouTypeManager.GetCheckMode;
end;
function TdxCustomSpellChecker.GetDictionary(
Index: Integer): TdxCustomSpellCheckerDictionary;
var
I, J: Integer;
ADictionary: TdxCustomSpellCheckerDictionary;
begin
Result := nil;
J := 0;
for I := 0 to DictionaryItems.Count - 1 do
begin
ADictionary := DictionaryItems[I].DictionaryType;
if ADictionary <> nil then
begin
if J = Index then
begin
Result := ADictionary;
Exit;
end;
Inc(J);
end;
end;
end;
function TdxCustomSpellChecker.GetDictionaryCount: Integer;
var
I: Integer;
begin
Result := 0;
for I := 0 to DictionaryItems.Count - 1 do
if DictionaryItems[I].DictionaryType <> nil then
Inc(Result);
end;
function TdxCustomSpellChecker.GetEnabledDictionary(
Index: Integer): TdxCustomSpellCheckerDictionary;
var
I, J: Integer;
ADictionary: TdxCustomSpellCheckerDictionary;
begin
Result := nil;
J := 0;
for I := 0 to DictionaryItems.Count - 1 do
begin
ADictionary := DictionaryItems[I].DictionaryType;
if (ADictionary <> nil) and (ADictionary.Enabled) then
begin
if J = Index then
begin
Result := DictionaryItems[I].DictionaryType;
Exit;
end;
Inc(J);
end;
end;
end;
function TdxCustomSpellChecker.GetEnabledDictionaryCount: Integer;
var
I: Integer;
ADictionary: TdxCustomSpellCheckerDictionary;
begin
Result := 0;
for I := 0 to DictionaryItems.Count - 1 do
begin
ADictionary := DictionaryItems[I].DictionaryType;
if (ADictionary <> nil) and (ADictionary.Enabled) then
Inc(Result);
end;
end;
function TdxCustomSpellChecker.GetUserDictionary(
Index: Integer): TdxUserSpellCheckerDictionary;
var
I, J: Integer;
begin
Result := nil;
J := 0;
for I := 0 to DictionaryItems.Count - 1 do
begin
if DictionaryItems[I].DictionaryType is TdxUserSpellCheckerDictionary then
begin
if J = Index then
begin
Result := TdxUserSpellCheckerDictionary(DictionaryItems[I].DictionaryType);
Exit;
end;
Inc(J);
end;
end;
end;
function TdxCustomSpellChecker.GetUserDictionaryCount: Integer;
var
I: Integer;
begin
Result := 0;
for I := 0 to DictionaryItems.Count - 1 do
if DictionaryItems[I].DictionaryType is TdxUserSpellCheckerDictionary then
Inc(Result);
end;
procedure TdxCustomSpellChecker.SetCheckAsYouTypeOptions(
AValue: TdxSpellCheckerCheckAsYouTypeOptions);
begin
FCheckAsYouTypeOptions.Assign(AValue);
end;
procedure TdxCustomSpellChecker.SetDialogLookAndFeel(AValue: TcxLookAndFeel);
begin
FDialogLookAndFeel.Assign(AValue);
end;
procedure TdxCustomSpellChecker.SetDictionaryItems(
AValue: TdxSpellCheckerDictionaries);
begin
FDictionaryItems.Assign(AValue);
end;
procedure TdxCustomSpellChecker.SetSpellingOptions(
AValue: TdxSpellCheckerSpellingOptions);
begin
FSpellingOptions.Assign(AValue);
end;
initialization
GetRegisteredDictionaryTypes.Register(
TdxUserSpellCheckerDictionary, cxGetResourceString(@sdxSpellCheckerUserDictionary));
finalization
FreeRegisteredDictionaryTypes;
end.