source: trunk/NewView/GlobalSearchForm.pas@ 25

Last change on this file since 25 was 18, checked in by RBRi, 19 years ago

+ newview source

  • Property svn:eol-style set to native
File size: 19.7 KB
Line 
1Unit GlobalSearchForm;
2
3// NewView - a new OS/2 Help Viewer
4// Copyright 2003 Aaron Lawrence (aaronl at consultant dot com)
5// This software is released under the Gnu Public License - see readme.txt
6
7Interface
8
9// Global search uses a thread to load helpfiles, search them, and
10// send the results to be displayed.
11
12Uses
13 PmWin,
14 Classes, Forms, Graphics, Buttons, StdCtrls, ComCtrls,
15 MultiColumnListBox, Outline2, GenericThread, ACLLanguageUnit,
16 TextSearchQuery, HelpFile, TabCtrls, ExtCtrls, LED;
17
18const
19 // Custom window messages for this form
20 // NOTE! Sibyl uses WM_USER+1 and +2!
21 WM_OPENED = WM_USER + 10;
22
23Type
24 TViewTopicCallback = procedure( Filename: string;
25 TopicIndex: longint ) of object;
26
27 TSearchParameters = class
28 Query: TTextSearchQuery;
29 Directories: TStringList;
30 end;
31
32 // Returned by thread. (Note - helpfiles and topics are destroyed dynamically.)
33 TSearchResult = class
34 Filename: string;
35 FileTitle: string;
36 MatchingTopics: TList;
37 constructor Create;
38 destructor Destroy; override;
39 end;
40
41 TGlobalSearchForm = Class (TForm)
42 SearchTextEdit: TEdit;
43 SearchTextLabel: TLabel;
44 SelectDrivesButton: TButton;
45 SearchTextLabel1: TLabel;
46 ResultsLabel: TLabel;
47 Led: TLed;
48 LEDTimer: TTimer;
49 SearchLocationComboBox: TComboBox;
50 Bevel: TBevel;
51 HelpButton: TButton;
52 ResultsOutline: TOutline2;
53 SearchButton: TButton;
54 ViewTopicButton: TButton;
55 CancelButton: TButton;
56 ProgressBar: TProgressBar;
57 ProgressLabel: TLabel;
58 Procedure SearchLocationComboBoxOnItemSelect (Sender: TObject;
59 Index: LongInt);
60 Procedure LEDTimerOnTimer (Sender: TObject);
61 Procedure SearchInComboBoxOnChange (Sender: TObject);
62 Procedure ResultsOutlineOnEnter (Sender: TObject);
63 Procedure SearchTextEditOnEnter (Sender: TObject);
64 Procedure ViewHelpPathsButtonOnClick (Sender: TObject);
65 Procedure SelectDrivesButtonOnClick (Sender: TObject);
66 Procedure GlobalSearchFormOnSetupShow (Sender: TObject);
67 Procedure CancelButtonOnClick (Sender: TObject);
68 Procedure GlobalSearchFormOnClose (Sender: TObject;
69 Var Action: TCloseAction);
70 Procedure ResultsOutlineOnItemDblClick (Node: TNode);
71 Procedure ViewTopicButtonOnClick (Sender: TObject);
72 Procedure GlobalSearchFormOnCreate (Sender: TObject);
73 Procedure GlobalSearchFormOnCloseQuery (Sender: TObject;
74 Var CanClose: Boolean);
75 Procedure SearchButtonOnClick (Sender: TObject);
76 Procedure GlobalSearchFormOnShow (Sender: TObject);
77 Protected
78 Procedure OnSearchProgress ( n, outof: integer;
79 S: String );
80 Procedure OnMatchFound( SearchResult: TSearchResult );
81 Procedure OnThreadData( S: string; Data: TObject );
82 Procedure OnSearchFinished( Result: TObject );
83 Procedure SetProgressLabel( const S: String );
84
85 // Handle our own WM_OPENED message
86 Procedure WMOpened( Var Msg: TMessage ); Message WM_OPENED;
87 Procedure ClearResults;
88 Procedure ViewTopic;
89
90 ThreadManager: TGenericThreadManager;
91
92 Procedure UpdateButtons;
93
94
95 Procedure GetSelectedDirectories( List: TStringList );
96
97 // search thread context
98
99 Function Search( Parameters: TObject ): TObject;
100
101 protected
102 Procedure OnLanguageEvent( Language: TLanguageFile;
103 const Apply: boolean );
104
105 SearchCaption: string;
106 StopCaption: string;
107 NoResultsMsg: string;
108 ScanDirectoriesMsg: string;
109 SearchingFileMsg: string;
110 OfMsg: string;
111 DoneMsg: string;
112 SearchErrorTitle: string;
113 SearchError: string;
114
115 StandardHelpPathsLocation: string;
116 FixedDrivesLocation: string;
117 SelectedHelpPathsLocation: string;
118 CustomPathsLocation: string;
119
120 public
121 // set by caller
122 ViewTopicCallback: TViewTopicCallback;
123 Procedure DoSearch;
124 End;
125
126Var
127 GlobalSearchForm: TGlobalSearchForm;
128
129procedure EnsureGlobalSearchFormLoaded;
130
131Implementation
132
133uses
134 PMWin,
135 SysUtils, BseDos,
136 Dialogs,
137 ACLFileUtility, ACLProfile, ACLDialogs, ControlsUtility, DriveInfoUnit, ACLStringUtility,
138 IPFFileFormatUnit, HelpTopic, SearchUnit, SearchDirectoriesFormUnit,
139 SettingsUnit, InformationFormUnit;
140
141type
142 // Used to store filenames in outline
143 THelpFileInfo = class
144 FileName: string;
145 end;
146
147constructor TSearchResult.Create;
148begin
149 inherited Create;
150 MatchingTopics := TList.Create;
151end;
152
153destructor TSearchResult.Destroy;
154begin
155 MatchingTopics.Destroy;
156 inherited Destroy;
157end;
158
159Procedure TGlobalSearchForm.SearchLocationComboBoxOnItemSelect (Sender: TObject; Index: LongInt);
160Begin
161 Settings.GlobalSearchLocation := TGlobalSearchLocation( SearchLocationComboBox.ItemIndex );
162End;
163
164Procedure TGlobalSearchForm.LEDTimerOnTimer (Sender: TObject);
165Begin
166 LED.LedCondition := not LED.LedCondition;
167End;
168
169Procedure TGlobalSearchForm.SearchInComboBoxOnChange (Sender: TObject);
170Begin
171End;
172
173Procedure TGlobalSearchForm.ResultsOutlineOnEnter (Sender: TObject);
174Begin
175 ViewTopicButton.Default := true;
176End;
177
178Procedure TGlobalSearchForm.SearchTextEditOnEnter (Sender: TObject);
179Begin
180 SearchButton.Default := true;
181End;
182
183Procedure TGlobalSearchForm.ViewHelpPathsButtonOnClick (Sender: TObject);
184var
185 Dirs: TStringList;
186Begin
187 Dirs := TStringList.Create;
188
189 with InformationForm.InformationMemo do
190 begin
191 Lines.Clear;
192
193 Lines.Add( 'HELP:' );
194 GetDirsInPath( 'HELP', Dirs );
195 Lines.AddStrings( Dirs );
196
197 Lines.Add( '' );
198 Lines.Add( 'BOOKSHELF:' );
199 GetDirsInPath( 'BOOKSHELF', Dirs );
200 Lines.AddStrings( Dirs );
201 end;
202 InformationForm.ShowModal;
203
204 Dirs.Destroy;
205End;
206
207Procedure TGlobalSearchForm.GetSelectedDirectories( List: TStringList );
208Var
209 DriveNumber: longint;
210 DriveType: TDriveType;
211 DriveLetter: char;
212 Dirs: TStringList;
213 i: longint;
214 Dir: string;
215 FoundIndex: longint;
216begin
217 List.Clear;
218 case SearchLocationComboBox.ItemIndex of
219 -1:
220 begin
221 // one custom dir...
222 List.Add( SearchLocationComboBox.Text );
223 end;
224
225 Ord( gsHelpPaths ),
226 Ord( gsSelectedHelpPaths ): // standard or selected help paths
227 Begin
228 Dirs := TStringList.Create;
229 List.Sorted := true;
230 List.Duplicates := dupIgnore;
231
232 GetDirsInPath( 'HELP', Dirs );
233 List.AddStrings( Dirs );
234
235 GetDirsInPath( 'BOOKSHELF', Dirs );
236 List.AddStrings( Dirs );
237
238 Dirs.Destroy;
239
240 if SearchLocationComboBox.ItemIndex = Ord( gsSelectedHelpPaths ) then
241 begin
242 // now mark some as non-selected...
243 for i := 0 to List.Count - 1 do
244 begin
245 Dir := List[ i ];
246 if not Settings.SearchDirectories.Find( Dir, FoundIndex ) then
247 List.Objects[ i ] := pointer( 1 );
248 end;
249 end;
250 end;
251
252 Ord( gsFixedDrives ):
253 begin
254 // drives
255 For DriveNumber := MinDriveNumber To MaxDriveNumber Do
256 Begin
257 DriveType := GetDriveType( DriveNumber );
258 DriveLetter := Chr( DriveNumber + Ord( 'A' ) - 1 );
259
260 if DriveType = dtHard then
261 begin
262 List.Add( DriveLetter + ':\...' );
263 end;
264 end;
265 end;
266
267 Ord( gsCustom ):
268 begin
269 // already custom...
270 List.Assign( Settings.SearchDirectories );
271 end;
272 end;
273end;
274
275Procedure TGlobalSearchForm.SelectDrivesButtonOnClick (Sender: TObject);
276Begin
277 GetSelectedDirectories( SearchDirectoriesForm.SelectedFolders );
278
279 SearchDirectoriesForm.ShowModal;
280 if SearchDirectoriesForm.ModalResult <> mrOK then
281 exit;
282
283 if SearchLocationComboBox.ItemIndex = Ord( gsHelpPaths ) then
284 SearchLocationComboBox.ItemIndex := Ord( gsSelectedHelpPaths );
285
286 if SearchLocationComboBox.ItemIndex = Ord( gsFixedDrives ) then
287 SearchLocationComboBox.ItemIndex := Ord( gsCustom );
288
289 if SearchDirectoriesForm.CustomDirAdded then
290 SearchLocationComboBox.ItemIndex := Ord( gsCustom );
291
292 Settings.SearchDirectories.Assign( SearchDirectoriesForm.SelectedFolders );
293
294 SaveSettings;
295End;
296
297Procedure TGlobalSearchForm.UpdateButtons;
298Begin
299 // HelpPathsRadioButton.Checked := SearchType = stHelpPaths;
300 // EverywhereRadioButton.Checked := SearchType = stDrives;
301// FolderRadioButton.Checked := SearchType = stFolder;
302
303End;
304
305Procedure TGlobalSearchForm.GlobalSearchFormOnSetupShow (Sender: TObject);
306Begin
307 ScaleForm( self, 11, 16 );
308 SearchButton.Align := alFixedRightTop;
309
310 if SearchLocationComboBox.Items.Count = 0 then
311 begin
312 // must match teh global search location enum...
313 SearchLocationComboBox.Items.Add( StandardHelpPathsLocation );
314 SearchLocationComboBox.Items.Add( FixedDrivesLocation );
315 SearchLocationComboBox.Items.Add( SelectedHelpPathsLocation );
316 SearchLocationComboBox.Items.Add( CustomPathsLocation );
317
318 SearchLocationComboBox.ItemIndex := Ord( Settings.GlobalSearchLocation );
319 end;
320
321End;
322
323Procedure TGlobalSearchForm.OnLanguageEvent( Language: TLanguageFile;
324 const Apply: boolean );
325begin
326 Language.LoadComponentLanguage( self, Apply );
327
328 Language.LL( Apply, SearchCaption, 'SearchCaption', '~Search' );
329 Language.LL( Apply, StopCaption, 'StopCaption', '~Stop' );
330 Language.LL( Apply, NoResultsMsg, 'NoResultsMsg', '(No results found)' );
331 Language.LL( Apply, ScanDirectoriesMsg, 'ScanDirectoriesMsg', 'Finding help files...' );
332 Language.LL( Apply, SearchingFileMsg, 'SearchingFileMsg', 'Searching ' );
333 Language.LL( Apply, OfMsg, 'OfMsg', ' of ' );
334 Language.LL( Apply, DoneMsg, 'DoneMsg', 'Done' );
335 Language.LL( Apply, SearchErrorTitle, 'SearchErrorTitle', 'Search' );
336 Language.LL( Apply, SearchError, 'SearchError', 'Error in search syntax: ' );
337
338 Language.LL( Apply, StandardHelpPathsLocation, 'StandardHelpPathsLocation', 'Standard Help Paths' );
339 Language.LL( Apply, FixedDrivesLocation, 'FixedDrivesLocation', 'All Hard Drives' );
340 Language.LL( Apply, SelectedHelpPathsLocation, 'SelectedHelpPathsLocation', 'Selected Help Paths' );
341 Language.LL( Apply, CustomPathsLocation, 'CustomPathsLocation', 'Directory List' );
342
343end;
344
345Procedure TGlobalSearchForm.CancelButtonOnClick (Sender: TObject);
346Begin
347 Close;
348End;
349
350Procedure TGlobalSearchForm.GlobalSearchFormOnClose (Sender: TObject;
351 Var Action: TCloseAction);
352Begin
353 ClearResults;
354
355 if SearchLocationComboBox.ItemIndex = -1 then
356 begin
357 Settings.GlobalSearchLocation := gsCustom;
358 Settings.SearchDirectories.Clear;
359 Settings.SearchDirectories.Add( SearchLocationComboBox.Text );
360 end;
361
362 Action := caFreeHandle; // DON'T release the form! (Default action for non-modal forms)
363End;
364
365Procedure TGlobalSearchForm.ResultsOutlineOnItemDblClick (Node: TNode);
366Begin
367 ViewTopic;
368End;
369
370Procedure TGlobalSearchForm.ViewTopicButtonOnClick (Sender: TObject);
371begin
372 ViewTopic;
373end;
374
375Procedure TGlobalSearchForm.ViewTopic;
376var
377 Node: TNode;
378 HelpFileInfo: THelpFileInfo;
379 TopicIndex: longint;
380Begin
381 Node := ResultsOutline.SelectedNode;
382 if Node = nil then
383 exit;
384 case Node.Level of
385 0:
386 begin
387 // file node
388 HelpFileInfo := Node.Data as THelpFileInfo;
389 TopicIndex := -1;
390 end;
391
392 1:
393 begin
394 // topic node
395 HelpFileInfo := Node.Parent.Data as THelpFileInfo;
396 TopicIndex := longint( Node.Data );
397 end;
398
399 else
400 assert( false, 'Invalid node level in ViewTopic!: ' + IntToStr( Node.Level ) );
401 end;
402
403 ViewTopicCallback( HelpFileInfo.FileName, TopicIndex );
404End;
405
406Procedure TGlobalSearchForm.GlobalSearchFormOnCreate (Sender: TObject);
407Begin
408 RegisterForLanguages( OnLanguageEvent );
409
410 UpdateButtons;
411
412 ThreadManager := TGenericThreadManager.Create( self );
413 ThreadManager.OnProgressUpdate := OnSearchProgress;
414 ThreadManager.OnDataFromThread := OnThreadData;
415 ThreadManager.OnJobComplete := OnSearchFinished;
416End;
417
418Procedure TGlobalSearchForm.OnSearchFinished( Result: TObject );
419Begin
420 SearchButton.Caption := SearchCaption;
421 ProgressBar.Hide;
422 LED.LedCondition := false;
423 LEDTimer.Stop;
424
425 if ResultsOutline.ChildCount > 0 then
426 begin
427 ResultsOutline.SelectedNode:= ResultsOutline.Children[ 0 ];
428 ResultsOutline.Focus;
429 SetProgressLabel( '' );
430 end
431 else
432 begin
433 SetProgressLabel( NoResultsMsg );
434 end;
435
436End;
437
438Procedure TGlobalSearchForm.GlobalSearchFormOnCloseQuery (Sender: TObject;
439 Var CanClose: Boolean);
440Begin
441 if ThreadManager.IsRunning then
442 begin
443 ThreadManager.Stop;
444 end;
445End;
446
447Procedure TGlobalSearchForm.SetProgressLabel( const S: String );
448begin
449 ProgressLabel.Text := S;
450 ProgressLabel.Refresh;
451end;
452
453Procedure TGlobalSearchForm.OnSearchProgress ( n, outof: integer;
454 S: String );
455Begin
456 ProgressBar.Position := n * 100 div outof;
457 SetProgressLabel( S );
458End;
459
460Function TGlobalSearchForm.Search( Parameters: TObject ): TObject;
461var
462 Files: TStringList;
463 FileIndex: longint;
464 Filename: string;
465 HelpFile: THelpFile;
466 SearchResult: TSearchResult;
467 MatchingTopics: TList;
468
469 SearchParameters: TSearchParameters;
470 Query: TTextSearchQuery;
471 i: longint;
472 Dir: string;
473
474Begin
475// StartProfile( GetLogFilesDir + 'NewViewSearch.prf' );
476
477 SearchParameters := Parameters as TSearchParameters;
478
479 Query := SearchParameters.Query;
480 Files := TStringList.Create;
481
482 // MatchingTopics.Add( nil ); // artificial crash
483 MatchingTopics := TList.Create;
484
485 ProfileEvent( 'Getting files' );
486
487 // make sure we ignore duplicate files...
488 Files.Sorted := true;
489 Files.CaseSensitive := false;
490 Files.Duplicates := dupIgnore;
491
492 for i := 0 to SearchParameters.Directories.Count - 1 do
493 begin
494 if ThreadManager.StopRequested then
495 break;
496 ThreadManager.UpdateProgress( i * 10 div SearchParameters.Directories.Count,
497 100,
498 ScanDirectoriesMsg );
499 Dir := SearchParameters.Directories[ i ];
500 if StrEnds( '...', Dir ) then
501 begin
502 Dir := StrLeftWithout( Dir, 3 );
503 ListDirectoryRecursiveAdditive2( Dir,
504 '*.inf;*.hlp',
505 Dir, // want full paths
506 Files,
507 nil, // don't care to know subdirs
508 ThreadManager.StopRequested,
509 true ); // check termination
510 end
511 else
512 begin
513 ListDirectoryAdditive( Dir,
514 '*.inf;*.hlp',
515 Dir, // want full paths
516 Files,
517 nil ); // don't care to know subdirs
518 end;
519 end;
520
521 ProfileEvent( ' Searching ' + IntToStr( Files.Count ) + ' files' );
522 for FileIndex := 0 to Files.Count - 1 do
523 begin
524 if ThreadManager.StopRequested then
525 break;
526 Filename := Files[ FileIndex ];
527 ProfileEvent( Filename );
528 ThreadManager.UpdateProgress( 10 + FileIndex * 95 div Files.Count,
529 100,
530 SearchingFileMsg
531 + Filename
532 + ' ('
533 + IntToStr( FileIndex + 1 )
534 + OfMsg
535 + IntToStr( Files.Count )
536 + ')...' );
537
538 try
539 ProfileEvent( ' Create THelpFile' );
540 HelpFile := THelpFile.Create( FileName );
541
542 ProfileEvent( ' Helpfile created' );
543 MatchingTopics.Clear;
544
545 ProfileEvent( ' Search file' );
546 SearchHelpFile( HelpFile,
547 Query,
548 MatchingTopics,
549 nil // don't care about words matched
550 );
551
552 if MatchingTopics.Count > 0 then
553 begin
554 ProfileEvent( ' Sort results' );
555 // Create a searchresult object to send back to main thread.
556 SearchResult := TSearchResult.Create;
557 SearchResult.Filename := HelpFile.Filename;
558 SearchResult.FileTitle := HelpFile.Title;
559
560 SearchResult.MatchingTopics.Assign( MatchingTopics );
561
562 SearchResult.MatchingTopics.Sort( TopicRelevanceCompare );
563 ProfileEvent( ' Display results' );
564
565 ThreadManager.SendData( '', SearchResult );
566 end;
567
568 ProfileEvent( 'Unload helpfile' );
569 HelpFile.Destroy;
570
571 except
572 on E: EHelpFileException do
573 begin
574 ; // ignore exceptions
575 end;
576
577 on E: EWindowsHelpFormatException do
578 begin
579 ; // ignore Windows help files
580 end;
581 end;
582
583 end;
584 ProfileEvent( 'search completed' );
585 ThreadManager.UpdateProgress( 100, 100, DoneMsg );
586 Files.Destroy;
587
588 Query.Destroy;
589
590 SearchParameters.Directories.Destroy;
591 SearchParameters.Destroy;
592
593 Result := nil;
594 ProfileEvent( 'done' );
595End;
596
597Procedure TGlobalSearchForm.ClearResults;
598var
599 FileIndex: longint;
600begin
601 for FileIndex := 0 to ResultsOutline.ChildCount - 1 do
602 ResultsOutline.Children[ FileIndex ].Data.Free;
603 ResultsOutline.Clear;
604 ViewTopicButton.Enabled := false;
605end;
606
607Procedure TGlobalSearchForm.SearchButtonOnClick (Sender: TObject);
608begin
609 DoSearch;
610end;
611
612Procedure TGlobalSearchForm.DoSearch;
613var
614 SearchText: string;
615 Query: TTextSearchQuery;
616 SearchParameters: TSearchParameters;
617Begin
618 if ThreadManager.IsRunning then
619 begin
620 ThreadManager.Stop;
621 exit;
622 end;
623
624 SearchText := trim( SearchTextEdit.Text );
625 if SearchText = '' then
626 exit;
627
628 try
629 Query := TTextSearchQuery.Create( SearchText );
630 except
631 on e: ESearchSyntaxError do
632 begin
633 DoErrorDlg( SearchErrorTitle,
634 SearchError
635 + e.Message );
636 exit;
637 end;
638 end;
639
640 ClearResults;
641
642 SearchParameters := TSearchParameters.Create;
643 SearchParameters.Directories := TStringList.Create;
644
645 SearchParameters.Query := Query;
646
647 GetSelectedDirectories( SearchParameters.Directories );
648
649 ThreadManager.StartJob( Search, SearchParameters );
650 SearchButton.Caption := StopCaption;
651 ProgressBar.Show;
652
653 LED.LedCondition := true;
654 LEDTimer.Start;
655End;
656
657Procedure TGlobalSearchForm.GlobalSearchFormOnShow (Sender: TObject);
658Begin
659 // make search button default
660 SearchButton.Focus;
661 SearchTextEdit.Focus;
662 SetProgressLabel( '' );
663 PostMsg( Handle, WM_OPENED, 0, 0 );
664 SearchButton.Caption := SearchCaption;
665 ProgressBar.Hide;
666 ViewTopicButton.Enabled := false;
667End;
668
669Procedure TGlobalSearchForm.OnThreadData( S: string; Data: TObject );
670var
671 SearchResult: TSearchResult;
672begin
673 SearchResult := Data as TSearchResult;
674 OnMatchFound( SearchResult );
675 SearchResult.Destroy;
676end;
677
678Procedure TGlobalSearchForm.OnMatchFound( SearchResult: TSearchResult );
679var
680 Topic: TTopic;
681 HelpFileInfo: THelpFileInfo;
682 FileNode: TNode;
683 TopicIndex: longint;
684begin
685 ViewTopicButton.Enabled := true;
686
687 HelpFileInfo := THelpFileInfo.Create;
688 HelpFileInfo.FileName := SearchResult.FileName;
689 FileNode := ResultsOutline.AddChild( SearchResult.FileTitle
690 + ' ('
691 + SearchResult.FileName
692 + ')',
693 HelpFileInfo );
694 for TopicIndex := 0 to SearchResult.MatchingTopics.Count - 1 do
695 begin
696 Topic := SearchResult.MatchingTopics[ TopicIndex ];
697 FileNode.AddChild( Topic.Title,
698 TObject( Topic.Index ) );
699 end;
700end;
701
702Procedure TGlobalSearchForm.WMOpened( Var Msg: TMessage );
703begin
704 Bevel.XStretch := xsFrame;
705 Bevel.YAlign := yaTop;
706
707 LED.XAlign := xaRight;
708 LED.YAlign := yaTop;
709
710 SearchTextEdit.XStretch := xsFrame;
711 ProgressLabel.XStretch := xsFrame;
712 ResultsOutline.XStretch := xsFrame;
713 ResultsOutline.YStretch := ysFrame;
714 ProgressLabel.YAlign := yaTop;
715 ProgressBar.XStretch := xsFrame;
716 ProgressBar.YAlign := yaBottom;
717 SearchTextEdit.YAlign := yaTop;
718 SearchTextEdit.Focus;
719end;
720
721procedure EnsureGlobalSearchFormLoaded;
722begin
723 if GlobalSearchForm = nil then
724 GlobalSearchForm := TGlobalSearchForm.Create( nil );
725end;
726
727Initialization
728 RegisterClasses ([TGlobalSearchForm, TEdit, TLabel,
729 TProgressBar, TButton, TOutline2, TComboBox, TBevel, TLed, TTimer]);
730 RegisterUpdateProcForLanguages( EnsureGlobalSearchFormLoaded );
731End.
Note: See TracBrowser for help on using the repository browser.