PageRenderTime 48ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/vendor/jvcl/examples/JvSpellChecker/JvSpellCheckerForm.pas

http://my-chuanqi.googlecode.com/
Pascal | 327 lines | 237 code | 29 blank | 61 comment | 23 complexity | 43a349d9a7e7a9e5170a5cc82d4a7968 MD5 | raw file
  1. {******************************************************************
  2. JEDI-VCL Demo
  3. Copyright (C) 2002 Project JEDI
  4. Original author:
  5. Contributor(s):
  6. You may retrieve the latest version of this file at the JEDI-JVCL
  7. home page, located at http://jvcl.sourceforge.net
  8. The contents of this file are used with permission, subject to
  9. the Mozilla Public License Version 1.1 (the "License"); you may
  10. not use this file except in compliance with the License. You may
  11. obtain a copy of the License at
  12. http://www.mozilla.org/MPL/MPL-1_1Final.html
  13. Software distributed under the License is distributed on an
  14. "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  15. implied. See the License for the specific language governing
  16. rights and limitations under the License.
  17. ******************************************************************}
  18. unit JvSpellCheckerForm;
  19. interface
  20. uses
  21. Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
  22. Dialogs, StdCtrls, JvSpellChecker, ActnList;
  23. type
  24. { This is an example form with code that shows how to implement a spell check form
  25. that can be displayed to the end user. The TJvSpellChecker is created dynamically
  26. so you don't need to install it to run the demo: just make sure the JvSpellChecker and
  27. JvSpellIntf units are somewhere in your path.
  28. The main tasks of this form is to:
  29. * Scan for the next misspelled word (GetNextWord)
  30. * Display the misspelled word along with suggested replacements
  31. * Call an event handler to highlight the text in the original control
  32. * Call an event handler when the user wants to replace the word
  33. * Add a word to the user dictionary (btnAdd)
  34. * Add a word to the ignore list (btnIgnoreAll)
  35. This form doesn't implement everything needed for a professional looking form (i.e only
  36. enable buttons as needed) but it can serve as a base for a more complete implementation.
  37. }
  38. TJvReplaceTextEvent = procedure(Sender: TObject; StartIndex, ALength: integer; const NewText: string) of object;
  39. TJvSelectTextEvent = procedure(Sender: TObject; StartIndex, ALength: integer) of object;
  40. TfrmSpellChecker = class(TForm)
  41. Label1: TLabel;
  42. edNewWord: TEdit;
  43. Label2: TLabel;
  44. lbSuggestions: TListBox;
  45. btnIgnore: TButton;
  46. btnIgnoreAll: TButton;
  47. btnChange: TButton;
  48. btnClose: TButton;
  49. btnAdd: TButton;
  50. GroupBox1: TGroupBox;
  51. chkUpperCase: TCheckBox;
  52. chkNumber: TCheckBox;
  53. chkURL: TCheckBox;
  54. chkHTML: TCheckBox;
  55. lblNoSuggestions: TLabel;
  56. Label3: TLabel;
  57. edBadWord: TEdit;
  58. alSpell: TActionList;
  59. acIgnore: TAction;
  60. acIgnoreAll: TAction;
  61. acChange: TAction;
  62. acAdd: TAction;
  63. acClose: TAction;
  64. procedure FormCreate(Sender: TObject);
  65. procedure FormShow(Sender: TObject);
  66. procedure acIgnoreExecute(Sender: TObject);
  67. procedure acIgnoreAllExecute(Sender: TObject);
  68. procedure acChangeExecute(Sender: TObject);
  69. procedure acAddExecute(Sender: TObject);
  70. procedure acCloseExecute(Sender: TObject);
  71. procedure alSpellUpdate(Action: TBasicAction; var Handled: Boolean);
  72. procedure lbSuggestionsClick(Sender: TObject);
  73. private
  74. { Private declarations }
  75. FStartIndex, FLength: integer;
  76. ASpellChecker: TJvSpellChecker;
  77. FOnReplaceText: TJvReplaceTextEvent;
  78. FOnSelectText: TJvSelectTextEvent;
  79. procedure CloseAndReport(ReportSuccess: boolean);
  80. function GetNextWord: boolean;
  81. procedure DoReplaceText(Sender: TObject; StartIndex, ALength: integer; const NewText: string);
  82. procedure DoSelectText(Sender: TObject; StartIndex, ALength: integer);
  83. function GetSpellText: string;
  84. procedure SetSpellText(const Value: string);
  85. procedure DoCanIgnore(Sender: TObject; const Value: string; var CanIgnore: boolean);
  86. procedure CheckSuggestions;
  87. public
  88. { Public declarations }
  89. property SpellText: string read GetSpellText write SetSpellText;
  90. property OnReplaceText: TJvReplaceTextEvent read FOnReplaceText write FOnReplaceText;
  91. property OnSelectText: TJvSelectTextEvent read FOnSelectText write FOnSelectText;
  92. end;
  93. var
  94. frmSpellChecker: TfrmSpellChecker;
  95. implementation
  96. {$R *.dfm}
  97. procedure TfrmSpellChecker.FormCreate(Sender: TObject);
  98. var S:string;
  99. begin
  100. ASpellChecker := TJvSpellChecker.Create(self);
  101. // Dictionaries are plain text files, one word per row, preferably sorted.
  102. // If you don't load a dictionary, all words are misspelled and you won't get any suggestions
  103. S := ExtractFilePath(Application.ExeName) + 'english.dic';
  104. if not FileExists(S) then
  105. S := '..\Dict\english.dic';
  106. if FileExists(S) then
  107. ASpellChecker.Dictionary := S
  108. else
  109. ShowMessage('Dictionary file not found: make sure you have an english.dic file in the exe folder!');
  110. // ASpellChecker.UserDictionary.LoadFromFile(Application.ExeName + 'custom.dic'); // you need to create this
  111. // set up a custom ignore filter:
  112. ASpellChecker.OnCanIgnore := DoCanIgnore;
  113. end;
  114. procedure TfrmSpellChecker.DoReplaceText(Sender: TObject; StartIndex, ALength: integer; const NewText: string);
  115. begin
  116. // this events calls back to the main form where the content of the rich edit is updated
  117. if Assigned(FOnReplaceText) then
  118. FOnReplaceText(self, StartIndex, ALength, NewText);
  119. end;
  120. function TfrmSpellChecker.GetSpellText: string;
  121. begin
  122. Result := ASpellChecker.Text;
  123. end;
  124. procedure TfrmSpellChecker.SetSpellText(const Value: string);
  125. begin
  126. ASpellChecker.Text := Value;
  127. end;
  128. procedure TfrmSpellChecker.CheckSuggestions;
  129. begin
  130. if lbSuggestions.Items.Count = 0 then
  131. begin
  132. lblNoSuggestions.Parent := lbSuggestions;
  133. lblNoSuggestions.Top := 4;
  134. lblNoSuggestions.Left := (lbSuggestions.ClientWidth - lblNoSuggestions.Width) div 2;
  135. lblNoSuggestions.Visible := true;
  136. end
  137. else
  138. lblNoSuggestions.Visible := false;
  139. end;
  140. function TfrmSpellChecker.GetNextWord: boolean;
  141. begin
  142. // scan for the next misspelled word. Returns false if no more misspelled words are found
  143. Result := false;
  144. while ASpellChecker.SpellChecker.Next(FStartIndex, FLength) do
  145. begin
  146. edBadWord.Text := '';
  147. edNewWord.Text := '';
  148. Result := FLength > 0;
  149. if Result then
  150. begin
  151. edBadWord.Text := Copy(ASpellChecker.Text, FStartIndex, FLength);
  152. lbSuggestions.Items := ASpellChecker.SpellChecker.Suggestions;
  153. if lbSuggestions.Items.Count > 0 then
  154. begin
  155. edNewWord.Text := lbSuggestions.Items[0];
  156. lbSuggestions.ItemIndex := 0;
  157. end
  158. else
  159. edNewWord.Text := edBadWord.Text;
  160. edNewWord.SetFocus;
  161. end;
  162. CheckSuggestions;
  163. Exit;
  164. end;
  165. end;
  166. procedure TfrmSpellChecker.FormShow(Sender: TObject);
  167. begin
  168. if GetNextWord then
  169. DoSelectText(self, FStartIndex, FLength)
  170. else
  171. CloseAndReport(false);
  172. end;
  173. procedure TfrmSpellChecker.DoSelectText(Sender: TObject; StartIndex,
  174. ALength: integer);
  175. begin
  176. // this events calls back to the main form where the selection in the rich edit is updated
  177. if Assigned(FOnSelectText) then FOnSelectText(self, StartIndex, ALength);
  178. end;
  179. procedure TfrmSpellChecker.DoCanIgnore(Sender: TObject; const Value: string;
  180. var CanIgnore: boolean);
  181. var
  182. i: integer;
  183. begin
  184. // custom event to manage some of the options in the dialog
  185. // always ignore words shorter than four letter
  186. if Length(Value) < 4 then
  187. begin
  188. CanIgnore := true;
  189. Exit;
  190. end;
  191. // make some additional checks on the current word to determine if we need to spellcheck it
  192. if chkUpperCase.Checked and (AnsiUpperCase(Value) = Value) then // ignore all UPPERCASE words
  193. begin
  194. CanIgnore := true;
  195. Exit;
  196. end;
  197. if chkNumber.Checked then // ignore words that contains numbers
  198. for i := 1 to Length(Value) do
  199. if (Value[i] in ['0'..'9', '#', '%']) then
  200. begin
  201. CanIgnore := true;
  202. Exit;
  203. end;
  204. if chkURL.Checked then // ignore URL's and file paths (this code is in no way 100% effective...)
  205. for i := 1 to Length(Value) do
  206. if (Value[i] in [':', '/', '\']) then
  207. begin
  208. CanIgnore := true;
  209. Exit;
  210. end;
  211. if chkHTML.Checked then // ignore HTML tags (this code is in no way 100% effective...)
  212. CanIgnore := (Length(Value) < 2) or ((Value[1] = '<') or (Value[Length(Value)] = '>')) or
  213. ((Value[1] = '&') and (Value[Length(Value)] = ';'));
  214. end;
  215. procedure TfrmSpellChecker.CloseAndReport(ReportSuccess: boolean);
  216. var
  217. S: string;
  218. begin
  219. if ReportSuccess then
  220. S := 'Spell check completed!'
  221. else
  222. S := 'There is nothing to spell check';
  223. ShowMessage(S);
  224. // delay since we might have been called from the OnShow event (can't close in OnShow)
  225. PostMessage(Handle, WM_CLOSE, 0, 0);
  226. end;
  227. procedure TfrmSpellChecker.acIgnoreExecute(Sender: TObject);
  228. begin
  229. // ignore = skip to next word but don't remember the word we just saw
  230. if GetNextWord then
  231. DoSelectText(self, FStartIndex, FLength)
  232. else
  233. CloseAndReport(true)
  234. end;
  235. procedure TfrmSpellChecker.acIgnoreAllExecute(Sender: TObject);
  236. begin
  237. // ignore all = add to ignore list so it will be skipped in the future as well
  238. ASpellChecker.SpellChecker.Ignores.Add(AnsiLowerCase(edBadWord.Text));
  239. if GetNextWord then
  240. DoSelectText(self, FStartIndex, FLength)
  241. else
  242. CloseAndReport(true);
  243. end;
  244. procedure TfrmSpellChecker.acChangeExecute(Sender: TObject);
  245. begin
  246. // replace the current selection with the word in the edit
  247. DoReplaceText(self, FStartIndex, FLength, edNewWord.Text);
  248. if GetNextWord then
  249. DoSelectText(self, FStartIndex, FLength)
  250. else
  251. CloseAndReport(true)
  252. end;
  253. procedure TfrmSpellChecker.acAddExecute(Sender: TObject);
  254. begin
  255. // Add the misspelled word to the user dictionary. To persist, you must add code to call
  256. // UserDictionary.SaveToFile() at close down as well as UserDictionary.LoadFromFile() at start up.
  257. ASpellChecker.SpellChecker.UserDictionary.Add(edBadWord.Text);
  258. edNewWord.Text := edBadWord.Text;
  259. // change the word as well
  260. if not acChange.Execute then
  261. begin
  262. // move on
  263. if GetNextWord then
  264. DoSelectText(self, FStartIndex, FLength)
  265. else
  266. CloseAndReport(true);
  267. end;
  268. end;
  269. procedure TfrmSpellChecker.acCloseExecute(Sender: TObject);
  270. begin
  271. Close;
  272. end;
  273. procedure TfrmSpellChecker.alSpellUpdate(Action: TBasicAction;
  274. var Handled: Boolean);
  275. begin
  276. acIgnore.Enabled := edBadWord.Text <> '';
  277. acIgnoreAll.Enabled := acIgnore.Enabled;
  278. acChange.Enabled := not AnsiSameText(edBadWord.Text, edNewWord.Text);
  279. acAdd.Enabled := (edBadWord.Text <> '') and (ASpellChecker.UserDictionary.IndexOf(edBadWord.Text) < 0);
  280. end;
  281. procedure TfrmSpellChecker.lbSuggestionsClick(Sender: TObject);
  282. begin
  283. with lbSuggestions do
  284. if ItemIndex > -1 then
  285. edNewWord.Text := Items[ItemIndex];
  286. end;
  287. end.