- Timestamp:
- May 17, 2015, 7:29:55 AM (10 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
cprs/branches/HealthSevak-CPRS/CPRS-Lib/Hans SpellCheck/skaSpellCheck.pas
r1712 r1715 17 17 * License. 18 18 * 19 *Special Note: 20 * This work has heavily relies upon rather build upon Copyrighted work by 21 * Miha Vrhovnik (http://simail.sf.net, http://xcollect.sf.net) which is 22 * available at http://sourceforge.net/projects/hunspell/ 23 * 19 24 * Alternatively, the content of this file maybe used under the terms of either 20 25 * the GNU General Public License Version 2 or later (the "GPL"), or the GNU … … 34 39 35 40 uses 36 Windows, Classes, SysUtils, ComCtrls, StdCtrls, Graphics ;41 Windows, Classes, SysUtils, ComCtrls, StdCtrls, Graphics, Forms, Controls; 37 42 38 43 const 39 AboutThis = 'A wrapper component developed by Sunil K Arora (digitiger@gmail.com) of HealthSevak using OpenSource HanSpell engine'; 44 AboutThis = 'A wrapper component developed by Sunil K Arora ' 45 + '(digitiger@gmail.com) of HealthSevak using OpenSource HanSpell engine'; 40 46 type 41 TSpellState = (ssNotStarted, ssChecking, ssCancelled, ssCompleted); 47 TSpellState = (ssNoengine, ssInActive, ssReady, ssChecking, ssCancelled, 48 ssCompleted); 49 TStateChangeEvent = procedure (const Sender : TObject; 50 const State : TSpellState) of object; 42 51 43 52 TskaHunSpellChecker = class(TComponent) … … 61 70 PREditorWndProc:pointer; 62 71 FHighlightColor: TColor; 63 FShowCompletion: Boolean;64 FpointerSpellComplete: String;65 FStatus: TSpellState;66 72 FUndoList: TStringList; 67 73 FCustDict: TStringList; … … 69 75 FModified: Boolean; 70 76 FHighlightEdit: TEdit; 71 FbtnClose: TButton;72 77 FTxtBeforeManualEdit: String; 78 79 FStatus: TSpellState; 80 FOnStart: TNotifyEvent; 81 FOnAbort : TNotifyEvent; 82 FOnStateChange : TStateChangeEvent; 83 73 84 function AddCustomWord(aWord: String; isInternal: Boolean = False): Boolean; 74 85 overload; virtual; … … 79 90 procedure SetActive(const Value: Boolean); 80 91 procedure SetAffixFileName(const Value: string); 81 procedure SetbtnClose(const Value: TButton);82 92 procedure SetCustomDict(const Value: String); 83 93 procedure SetDictFileName(const Value: string); … … 89 99 function GetAboutThis: String; 90 100 procedure SaveForUndo(const Ignoring: Boolean=False); 91 procedure ShowBtnClose(const ShowIt: Boolean = True);101 procedure InformStatusChange; 92 102 public 93 103 constructor Create(AOwner: TComponent); overload; override; … … 111 121 procedure ManualChangeDone; 112 122 function Open:Boolean; virtual; 123 procedure ReOpen; 113 124 function ReStart: Boolean; virtual; 114 115 125 function Undo: Boolean; 116 117 118 property SpellCheckState: TSpellState read GetStatus default ssNotStarted; 126 property SpellCheckState: TSpellState read GetStatus default ssInActive; 119 127 published 120 128 property About: String read GetAboutThis; 121 129 property Active: Boolean read GetActive write SetActive; 122 130 property AffixFileName: string read FAffixFileName write SetAffixFileName; 123 property btnClose: TButton read FbtnClose write SetbtnClose;124 131 property CustDictionaryFile: String read FCustom write SetCustomDict; 125 132 property DictionaryFileName:string read FDictFileName write SetDictFileName; 126 property ColorForMisspelled: TColor read FHighlightColor write FHighlightColor default clRed; 133 property ColorForMisspelled: TColor read FHighlightColor 134 write FHighlightColor default clRed; 127 135 property MisSpeltWord: TEdit read FHighlightEdit write SetHighLightEdit; 128 136 property IsModified: Boolean read FModified; 129 property ShowCompletionMessage: Boolean read FShowCompletion write FShowCompletion default True; 137 property OnStart : TNotifyEvent read FOnStart write FOnStart; 138 property OnStateChange : TStateChangeEvent read FOnStateChange 139 write FOnStateChange; 140 property OnAbort : TNotifyEvent read FOnAbort write FOnAbort; 130 141 property SourceTextControl: TRichEdit read FSourceEdit write SetSourceEdit; 131 property SpellCheckCompletionMessage: String read FpointerSpellComplete write FpointerSpellComplete; 132 property SuggestionList: TListbox read FSuggestionList write FSuggestionList; 142 property SuggestionList:TListbox read FSuggestionList write FSuggestionList; 133 143 134 144 end; … … 140 150 CaptionForNewWord = 'New Word Suggestion'; 141 151 ConfirmAbort = 'Really abort?'; 152 ConfirmComplete = 'If you accept last change than SpellCheck is complete.' 153 + #13 + ' To review last change click on "Cancel".'; 142 154 PromptForNewWord = 'Specify the replacement for current mis-spelt word:'; 143 155 DLLNotLoaded = 'Failed to load SpellCheck Engine DLL.'; … … 145 157 +' Would you want to still use it? Click NO button ' 146 158 +'to specify better replacement word.'; 159 147 160 var 148 161 OldRichEditWndProc: {integer}pointer; 149 162 CurrentMe: TskaHunSpellChecker; 150 163 implementation 151 uses messages, Dialogs, RichEdit, SHFolder, Forms,uHunSpellLib;164 uses messages, Dialogs, RichEdit, SHFolder, uHunSpellLib; 152 165 153 166 procedure Register; … … 171 184 [mbYes, mbNo],0, mbNo) = 6); 172 185 173 if Result then 174 FStatus := ssCancelled; 175 176 ShowBtnClose; 177 end; 178 179 function TskaHunSpellChecker.AddCustomWord(aWord: String; isInternal: Boolean = False): Boolean; 186 if Result and (FUndoList.Count > 0) then 187 begin 188 SourceTextControl.Text := FUndoList[0]; 189 FUndoList.Clear; 190 FUndoList.Add(SourceTextControl.Text); 191 end; 192 FIgnore.Clear; 193 FStatus := ssCancelled; 194 SourceTextControl.Invalidate; 195 if Assigned(OnAbort) then 196 OnAbort(Self); 197 end; 198 199 function TskaHunSpellChecker.AddCustomWord(aWord: String; 200 isInternal: Boolean = False): Boolean; 180 201 begin 181 202 Result := False; 182 if (trim(aWord) = '') or (not assigned(SourceTextControl)) or (not assigned(SuggestionList)) then 183 184 185 Result := False; 186 if (not Active) then Exit; 203 if (not active) or (trim(aWord) = '') or (SpellCheckState <> ssChecking) 204 or (not assigned(SourceTextControl)) or (not assigned(SuggestionList)) then 205 begin 206 Result := False; 207 exit; 208 end; 187 209 uHunSpellLib.hunspell_put_word(FpointerHunLib, PAnsiChar(AnsiString(aWord))); 188 210 Result := True; … … 191 213 procedure TskaHunSpellChecker.ChangeAll; 192 214 begin 193 if (SpellCheckState <> ssChecking) or (not assigned(SourceTextControl)) or (not assigned(SuggestionList)) then 215 if (SpellCheckState <> ssChecking) or (not assigned(SourceTextControl)) 216 or (not assigned(SuggestionList)) then 194 217 exit; 195 218 SaveForUndo; … … 214 237 end; 215 238 239 procedure TskaHunSpellChecker.ReOpen; 240 begin 241 Close; 242 Open; 243 end; 244 216 245 procedure TskaHunSpellChecker.ReplaceCurrentWordWith(const aNewWord: String); 217 246 var … … 221 250 begin 222 251 full := SourceTextControl.Lines[CurrentLine]; 223 prefix := copy(CurrentText, 2, WordPos-2); //remember there is one extra space at the start of the line prefixed while populating this variable 252 {remember there is one extra space at the start of the line prefixed while 253 populating this variable} 254 prefix := copy(CurrentText, 2, WordPos-2); 224 255 Suffix := copy(CurrentText, WordPos+WordLength, 225 256 length(CurrentText)); 226 257 SaveForUndo; 258 FModified := True; 227 259 SourceTextControl.Lines[CurrentLine] :=prefix + aNewWord + suffix; 228 260 WaitForUser := False; … … 238 270 Initialize; 239 271 WaitForUser := False; 240 FStatus := ssChecking; 272 if FStatus <> ssChecking then 273 begin 274 FStatus := ssChecking; 275 InformStatusChange; 276 end; 241 277 SourceTextControl.Invalidate; 242 278 Result := not WaitForUser; … … 246 282 247 283 begin 248 if (SpellCheckState <> ssChecking) or (not assigned(SourceTextControl)) or (not assigned(SuggestionList)) then 284 if (SpellCheckState <> ssChecking) or (not assigned(SourceTextControl)) 285 or (not assigned(SuggestionList)) then 249 286 exit; 250 287 ReplaceCurrentWordWith(SuggestionList.Items[SuggestionList.ItemIndex]); … … 253 290 procedure TskaHunSpellChecker.CheckSpelling; 254 291 begin 255 if (SpellCheckState = ssChecking) or (not assigned(SourceTextControl)) or (not assigned(SuggestionList)) then 292 if (SpellCheckState = ssChecking) or (not assigned(SourceTextControl)) 293 or (trim(SourceTextControl.Text)= '') or (not assigned(SuggestionList)) then 256 294 exit; 257 295 258 296 Initialize; 259 297 FUndoList.Clear; 298 FUndoList.Add(SourceTextControl.Text); 299 FIgnore.Clear; 260 300 WaitForUser := False; 261 301 FStatus := ssChecking; 302 if Assigned(OnStart) then 303 OnStart(Self); 262 304 SourceTextControl.Invalidate; 263 //SourceTextControl.Invalidate;264 ShowBtnClose(False);265 305 end; 266 306 … … 268 308 begin 269 309 if not Active then Exit; 270 uHunSpellLib.hunspell_uninitialize(FpointerHunLib);310 uHunSpellLib.hunspell_uninitialize(FpointerHunLib); 271 311 FpointerHunLib := nil; 312 FStatus := ssInActive; 313 InformStatusChange; 272 314 end; 273 315 … … 278 320 GotIt: Boolean; 279 321 begin 280 if (SpellCheckState <> ssChecking) or (not assigned(SourceTextControl)) or (not assigned(SuggestionList)) then 322 if (SpellCheckState <> ssChecking) or (not assigned(SourceTextControl)) 323 or (not assigned(SuggestionList)) then 281 324 exit; 282 325 … … 304 347 305 348 constructor TskaHunSpellChecker.Create(AOwner: TComponent); 306 function GetSpecialFolderPath(folder : integer) : string;307 var308 path: array [0..MAX_PATH] of char;309 begin310 if SUCCEEDED(SHGetFolderPath(0,folder,0,0,@path[0])) then311 Result := path312 else313 Result := '';314 end;315 349 begin 316 350 inherited; 317 318 351 ColorForMisspelled := clRed; 319 ShowCompletionMessage := True;320 SpellCheckCompletionMessage := CompletionMessage;321 322 323 352 324 353 CurrentMe := Self; … … 326 355 FCustDict := TStringList.Create; 327 356 328 CustDictionaryFile := IncludeTrailingPathDelimiter(GetSpecialFolderPath(CSIDL_PERSONAL)) + 'CustomDictionary.txt'; 329 if FileExists(CustDictionaryFile) then 357 if (trim(CustDictionaryFile)<>'') and (FileExists(CustDictionaryFile)) then 330 358 try 331 359 FCustDict.LoadFromFile(CustDictionaryFile); … … 335 363 FUndoList := TStringList.Create; 336 364 337 FStatus := ss NotStarted;365 FStatus := ssInActive; 338 366 WaitForUser := False; 339 367 WordPos := 0; … … 406 434 uHunSpellLib.hunspell_suggest_auto(FpointerHunLib, pMisSpelt, suggestions); 407 435 begin 408 Count := uHunSpellLib.hunspell_suggest(FpointerHunLib, pMisSpelt,suggestions);436 Count :=uHunSpellLib.hunspell_suggest(FpointerHunLib,pMisSpelt,suggestions); 409 437 Results := suggestions; 410 438 for i := 1 to Count do … … 415 443 uHunSpellLib.hunspell_suggest_free(FpointerHunLib, suggestions, Count); 416 444 end; 417 end;418 419 procedure TskaHunSpellChecker.ShowBtnClose(const ShowIt: Boolean);420 begin421 if Assigned(btnClose) then422 begin423 btnClose.Enabled := ShowIt;424 btnClose.Visible := ShowIt;425 if ShowIt then426 begin427 btnClose.BringToFront;428 btnClose.SetFocus;429 end;430 end;431 445 end; 432 446 … … 453 467 exit; 454 468 455 SendMessage (SourceTextControl.Handle, EM_POSFROMCHAR, integer(@VisPoint), PosOfFirstCharInCurrentLine + FoundAt-1); 469 SendMessage (SourceTextControl.Handle, EM_POSFROMCHAR, integer(@VisPoint), 470 PosOfFirstCharInCurrentLine + FoundAt-1); 456 471 SetTextColor(dcForHndl, ColorForMisspelled); 457 TextOut(dcForHndl, VisPoint.x, VisPoint.y,pchar(CurrentWord), WordLength);472 TextOut(dcForHndl, VisPoint.x, VisPoint.y, pchar(CurrentWord), WordLength); 458 473 end; 459 474 begin … … 474 489 vispoint.Y := visrect.Bottom; 475 490 vispoint.X := visrect.Right; 476 CharPosion 477 LASTVISIBLELINE 491 CharPosion := SendMessage (hndl, EM_CHARFROMPOS, 0, integer(@VisPoint)); 492 LASTVISIBLELINE := SendMessage (hndl, EM_LINEFROMCHAR, CharPosion, 0); 478 493 FIRSTVISIBLELINE := SendMessage (hndl, EM_GETFIRSTVISIBLELINE, 0, 0); 479 494 … … 496 511 497 512 CurrentText := ' ' + SourceTextControl.Lines[CurrentLine]; 498 PosOfFirstCharInCurrentLine := SendMessage (SourceTextControl.Handle, EM_LINEINDEX, CurrentLine, 0); 513 PosOfFirstCharInCurrentLine := SendMessage (SourceTextControl.Handle, 514 EM_LINEINDEX, CurrentLine, 0); 499 515 i := 0; 500 516 … … 522 538 ShowMisSpelletWord; 523 539 if CurrentLine > LastVisibleLine then 524 SendMessage(SourceTextControl.Handle, EM_LINESCROLL, 0, (CurrentLine - lastvisibleLine)+5); 540 SendMessage(SourceTextControl.Handle, EM_LINESCROLL, 0, 541 (CurrentLine - lastvisibleLine)+5); 525 542 WaitForUser := True; 526 543 exit; … … 531 548 end; 532 549 end; 533 if (CurrentLine >= SourceTextControl.Lines.Count-1) and (i >= length(CurrentText) +1) then 550 if (CurrentLine >= SourceTextControl.Lines.Count-1) 551 and (i >= length(CurrentText) +1) then 534 552 begin 535 FStatus := ssCompleted; 536 if ShowCompletionMessage then 537 ShowMessage(CompletionMessage); 538 ShowBtnClose; 553 if (not FModified) 554 or (MessageDlg(ConfirmComplete,mtConfirmation,[mbOK, mbCancel],0)=mrOk) 555 then 556 begin 557 FStatus := ssCompleted; 558 InformStatusChange; 559 end 560 else 561 Undo; 539 562 end; 540 563 {$R+} … … 548 571 tmpStr: String; 549 572 tmpCount: Integer; 550 begin 551 if FUndoList.Count > 0 then 573 SrcText: String; 574 begin 575 if FUndoList.Count > 1 then 552 576 try 553 577 tmpStr := FUndoList.Strings[FUndoList.Count-1]; 554 { showmessage(inttostr(AnsiPos('$$',tmpStr)) + #13 + inttostr(length(tmpstr)) + #13 +555 copy(tmpStr,length(tmpStr)-2,2)); }556 578 if (AnsiPos('$$',tmpStr)=1) and (copy(tmpStr,length(tmpStr)-1,2) = '$$')then 579 //if last action was ignoring word then just remove it from ignore list 557 580 begin 558 581 tmpCount := strtoInt(StringReplace(tmpStr,'$$','',[rfReplaceAll])); … … 573 596 procedure TskaHunSpellChecker.IgnoreAll; 574 597 begin 575 if (SpellCheckState <> ssChecking) or (not assigned(SourceTextControl)) or (not assigned(SuggestionList)) then 598 if (SpellCheckState <> ssChecking) or (not assigned(SourceTextControl)) 599 or (not assigned(SuggestionList)) then 576 600 exit; 601 577 602 SaveForUndo(True); 578 603 FIgnore.Add(CurrentWordDetail(False)) ; … … 583 608 procedure TskaHunSpellChecker.IgnoreOnce; 584 609 begin 585 if (SpellCheckState <> ssChecking) or (not assigned(SourceTextControl)) or (not assigned(SuggestionList)) then 610 if (SpellCheckState <> ssChecking) or (not assigned(SourceTextControl)) 611 or (not assigned(SuggestionList)) then 586 612 exit; 613 587 614 if trim(CurrentWord) <> '' then 588 615 begin … … 592 619 WaitForUser := False; 593 620 SourceTextControl.Invalidate; 621 end; 622 623 procedure TskaHunSpellChecker.InformStatusChange; 624 begin 625 if Assigned(OnStateChange) then 626 OnStateChange(Self, FStatus); 594 627 end; 595 628 … … 609 642 Result := True 610 643 else 611 Result := not uHunSpellLib.hunspell_spell(FpointerHunLib, PAnsiChar(AnsiString(AWord))); 644 Result := not uHunSpellLib.hunspell_spell(FpointerHunLib, 645 PAnsiChar(AnsiString(AWord))); 612 646 end; 613 647 … … 634 668 var 635 669 CurrentLine: integer; 670 function GetSpecialFolderPath(folder : integer) : string; 671 var 672 path: array [0..MAX_PATH] of char; 673 begin 674 if SUCCEEDED(SHGetFolderPath(0,folder,0,0,@path[0])) then 675 Result := path 676 else 677 Result := ''; 678 end; 636 679 begin 637 680 Result := True; … … 644 687 Exit; 645 688 end; 646 FpointerHunLib := uHunSpellLib.hunspell_initialize(PAnsiChar(AnsiString(FAffixFileName)), PAnsiChar(AnsiString(FDictFileName))); 689 FpointerHunLib := uHunSpellLib.hunspell_initialize( 690 PAnsiChar(AnsiString(FAffixFileName)), 691 PAnsiChar(AnsiString(FDictFileName))); 647 692 Result := Assigned(FpointerHunLib); 648 693 694 if Result then 695 begin 696 FStatus := ssReady; 697 InformStatusChange; 698 end; 699 if trim(CustDictionaryFile) = '' then 700 CustDictionaryFile := IncludeTrailingPathDelimiter( 701 GetSpecialFolderPath(CSIDL_PERSONAL)) + 'CustomDictionary.txt'; 649 702 if (Result) and (assigned(FCustDict)) then 650 703 for CurrentLine := 0 to FCustDict.Count - 1 do … … 675 728 Close; 676 729 FAffixFileName := Value; 677 end; 678 679 procedure TskaHunSpellChecker.SetbtnClose(const Value: TButton); 680 begin 681 if btnClose = Value then 682 exit; 683 FbtnClose := Value; 684 FbtnClose.ModalResult := 1; //mrOK 730 if (trim(DictionaryFileName) = '') and (trim(value)<>'') then 731 DictionaryFileName := ChangeFileExt(value, '.dic'); 685 732 end; 686 733 … … 688 735 begin 689 736 FCustom := Value; 690 if not (csDesigning in componentState) then 691 if Active and (FileExists(Value)) then 692 FCustDict.LoadFromFile(Value); 737 if (not (csDesigning in componentState)) 738 and (FileExists(Value)) and assigned(FCustDict) then 739 begin 740 FCustDict.Clear; 741 FCustDict.LoadFromFile(Value); 742 end; 693 743 end; 694 744 … … 697 747 Close; 698 748 FDictFileName := Value; 749 if (trim(AffixFileName) = '') and (trim(value)<>'') then 750 AffixFileName := ChangeFileExt(value, '.aff'); 699 751 end; 700 752 … … 712 764 end; 713 765 714 Function RichEditWndProc (handle:HWnd;uMsg,wParam,lParam:longint): longint stdcall; 715 begin 716 Result := CallWindowProc(OldRichEditWndProc, handle, uMsg, wParam, lParam); 717 if (uMsg=WM_PAINT) and assigned(CurrentMe) then CurrentMe.ShowMisSpelledWord; 766 Function RichEditWndProc(handle:HWnd;uMsg,wParam,lParam:longint):longint stdcall; 767 begin 768 Result := CallWindowProc(OldRichEditWndProc, handle, uMsg, wParam, lParam); 769 if (uMsg=WM_PAINT) and assigned(CurrentMe) then 770 CurrentMe.ShowMisSpelledWord; 718 771 End; 719 772 … … 729 782 730 783 PREditorWndProc:=@RichEditWndProc; 731 Value.perform(EM_EXLIMITTEXT, 0, 65535*32); //raise the limit of text which could be inserted into this Richedit 732 OldRichEditWndProc := pointer(SetWindowLong(Value.handle, GWL_WNDPROC, longint(@RichEditWndProc))); 733 784 //raise the limit of text which could be inserted into this Richedit 785 Value.perform(EM_EXLIMITTEXT, 0, 65535*32); 786 OldRichEditWndProc := pointer(SetWindowLong(Value.handle, GWL_WNDPROC, 787 longint(@RichEditWndProc))); 734 788 end; 735 789
Note:
See TracChangeset
for help on using the changeset viewer.