source: trunk/NewView/MainForm.pas@ 65

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

more fixes for the link handling

  • Property svn:eol-style set to native
File size: 182.4 KB
Line 
1Unit MainForm;
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
9Uses
10// system is a good unit to be able to open ;)
11// the above line is here so you can use right-mouse open file on "system"
12 OS2Def,
13 SysUtils,
14 Classes,
15 Forms,
16 Graphics,
17 Messages,
18 Buttons,
19 ComCtrls,
20 StdCtrls,
21 ExtCtrls,
22 TabCtrls,
23 Dialogs,
24
25// library
26 ACLString,
27 SharedMemoryUnit,
28 ACLLanguageUnit,
29 GenericThread,
30 CmdLineParameterUnit,
31
32// custom components
33 SplitBar,
34 Outline2,
35 RichTextView,
36 Coolbar2,
37 CustomListBox,
38
39// local
40 HelpFile,
41 HelpTopic,
42 HelpWindowUnit,
43 HelpWindowDimensions,
44 NavigatePointUnit,
45 MiscUnit,
46 HelpManagerUnit,
47 TextSearchQuery,
48 IPFFileFormatUnit,
49 Tabset2Unit;
50
51const
52 // Custom window messages for this form
53 // NOTE! Sibyl uses WM_USER+1 and +2!
54 WM_OPENED = WM_USER + 10;
55 WM_FOLLOWLINK = WM_USER + 11;
56 WM_FOLLOWEXTERNALLINK = WM_USER + 12;
57
58 MAIN_WINDOW_CLASS_NAME = 'NewViewMainForm';
59
60Type
61
62 TMainForm = Class (TForm)
63 VSplitBar: TSplitBar;
64 Notebook: TNoteBook;
65 IndexSearchEdit: TEdit;
66 SearchTextEdit: TEdit;
67 SearchResultsListBox: TListBox;
68 NotesListBox: TListBox;
69 CoolBar: TCoolBar2;
70 MenuItem21: TMenuItem;
71 SaveAsIPFMI: TMenuItem;
72 MenuItem20: TMenuItem;
73 DebugFindBinaryMI: TMenuItem;
74 TopicByNameMI: TMenuItem;
75 DebugTopicByResourceIDMI: TMenuItem;
76 ToolsDebugSep: TMenuItem;
77 DebugSaveLanguageFileMI: TMenuItem;
78 DebugLoadLanguageMI: TMenuItem;
79 TabSet: TTabSet2;
80 NavigateNextMI: TMenuItem;
81 ShowLeftPanelMI: TMenuItem;
82 MenuItem18: TMenuItem;
83 AddNoteButton: TButton;
84 EditNoteButton: TButton;
85 DeleteNoteButton: TButton;
86 GotoNoteButton: TButton;
87 MenuItem23: TMenuItem;
88 MenuItem24: TMenuItem;
89 MenuItem25: TMenuItem;
90 DebugHelpManagerVersionMI: TMenuItem;
91 MenuItem19: TMenuItem;
92 ViewHighlightSearchWordsMI: TMenuItem;
93 MenuItem17: TMenuItem;
94 MenuItem16: TMenuItem;
95 MenuItem15: TMenuItem;
96 FileNewWindowMI: TMenuItem;
97 OpenSpecialMI: TMenuItem;
98 MenuItem14: TMenuItem;
99 SearchPMI: TMenuItem;
100 ViewSourceMI: TMenuItem;
101 FileCloseMI: TMenuItem;
102 MenuItem10: TMenuItem;
103 MenuItem12: TMenuItem;
104 MenuItem13: TMenuItem;
105 StatusPanel: TPanel;
106 ProgressPanel: TPanel;
107 ProgressBar: TProgressBar;
108 DebugShowWordSeparatorsMI: TMenuItem;
109 DebugStressTestMI: TMenuItem;
110 TopicPropertiesPMI: TMenuItem;
111 MenuItem3: TMenuItem;
112 MenuItem2: TMenuItem;
113 MenuItem8: TMenuItem;
114 ToolsOptionsMI: TMenuItem;
115 MenuItem9: TMenuItem;
116 ToolsDebugMenu: TMenuItem;
117 DebugShowParamsMI: TMenuItem;
118 DebugShowCodesMI: TMenuItem;
119 EditGlobalSearchMI: TMenuItem;
120 ViewExpandAllMI: TMenuItem;
121 EditBookmarksMI: TMenuItem;
122 AddBookmarkMI: TMenuItem;
123 ViewPopupMenu: TPopupMenu;
124 SelectAllPMI: TMenuItem;
125 CopyPMI: TMenuItem;
126 ContentsOutline: TOutline2;
127 IndexListBox: TCustomListBox;
128 ViewCollapseAllMI: TMenuItem;
129 MenuItem7: TMenuItem;
130 SystemOpenDialog: TSystemOpenDialog;
131 SearchButton: TButton;
132 MenuItem1: TMenuItem;
133 ViewIndexMI: TMenuItem;
134 ViewContentsMI: TMenuItem;
135 ViewSearchMI: TMenuItem;
136 ViewNotesMI: TMenuItem;
137 ViewRefreshMI: TMenuItem;
138 MenuItem11: TMenuItem;
139 DisplayPanel: TPanel;
140 ButtonImages: TImageList;
141 BookmarksMenu: TMenuItem;
142 MainMenu: TMainMenu;
143 FileMenu: TMenuItem;
144 OpenMI: TMenuItem;
145 FileSaveAsMI: TMenuItem;
146 PrintMI: TMenuItem;
147 FileInformationMI: TMenuItem;
148 MenuItem4: TMenuItem;
149 ExitMI: TMenuItem;
150 EditMenu: TMenuItem;
151 SelectAllMI: TMenuItem;
152 CopyMI: TMenuItem;
153 MenuItem5: TMenuItem;
154 FindMI: TMenuItem;
155 FindNextMI: TMenuItem;
156 NavigateMenu: TMenuItem;
157 NavigateBackMI: TMenuItem;
158 NavigateForwardMI: TMenuItem;
159 MenuItem6: TMenuItem;
160 NavigatePreviousMI: TMenuItem;
161 ToolsMenu: TMenuItem;
162 GlobalSearchMI: TMenuItem;
163 HelpMenu: TMenuItem;
164 HelpMI: TMenuItem;
165 HelpProductInformationMI: TMenuItem;
166 AddNoteMI: TMenuItem;
167
168 Procedure SaveAsIPFMIOnClick (Sender: TObject);
169 Procedure DebugFindBinaryMIOnClick (Sender: TObject);
170 Procedure TopicByNameMIOnClick (Sender: TObject);
171 Procedure CopyLinkLocationPMIOnClick (Sender: TObject);
172 Procedure HelpKeysMIOnClick (Sender: TObject);
173 Procedure MainFormOnCommand (Sender: TObject; Var Command: TCommand);
174 Procedure MainFormOnScan (Sender: TObject; Var KeyCode: TKeyCode);
175 Procedure ShowLeftPanelMIOnClick (Sender: TObject);
176 Procedure CoolBarOnFontChange (Sender: TObject);
177 Procedure NotebookOnFontChange (Sender: TObject);
178 Procedure TabSetOnFontChange (Sender: TObject);
179 Procedure IndexListBoxOnFontChange (Sender: TObject);
180 Procedure NotesListBoxOnFontChange (Sender: TObject);
181 Procedure DisplayPanelOnFontChange (Sender: TObject);
182 Procedure ContentsOutlineOnFontChange (Sender: TObject);
183 Procedure SearchResultsListBoxOnFontChange (Sender: TObject);
184 Procedure DisplayPanelOnDragOver (Sender: TObject; Source: TObject;
185 X: LongInt; Y: LongInt; State: TDragState; Var Accept: Boolean);
186 Procedure NotesListBoxOnDragOver (Sender: TObject; Source: TObject;
187 X: LongInt; Y: LongInt; State: TDragState; Var Accept: Boolean);
188 Procedure DisplayPanelOnDragDrop (Sender: TObject; Source: TObject;
189 X: LongInt; Y: LongInt);
190 Procedure NotesListBoxOnDragDrop (Sender: TObject; Source: TObject;
191 X: LongInt; Y: LongInt);
192 Procedure SearchResultsListBoxOnDragDrop (Sender: TObject; Source: TObject;
193 X: LongInt; Y: LongInt);
194 Procedure SearchResultsListBoxOnDragOver (Sender: TObject; Source: TObject;
195 X: LongInt; Y: LongInt; State: TDragState; Var Accept: Boolean);
196 Procedure IndexListBoxOnDragDrop (Sender: TObject; Source: TObject;
197 X: LongInt; Y: LongInt);
198 Procedure IndexListBoxOnDragOver (Sender: TObject; Source: TObject;
199 X: LongInt; Y: LongInt; State: TDragState; Var Accept: Boolean);
200 Procedure ContentsOutlineOnDragOver (Sender: TObject; Source: TObject;
201 X: LongInt; Y: LongInt; State: TDragState; Var Accept: Boolean);
202 Procedure ContentsOutlineOnDragDrop (Sender: TObject; Source: TObject;
203 X: LongInt; Y: LongInt);
204 Procedure MainFormOnDragOver (Sender: TObject; Source: TObject; X: LongInt;
205 Y: LongInt; State: TDragState; Var Accept: Boolean);
206 Procedure MainFormOnDragDrop (Sender: TObject; Source: TObject; X: LongInt;
207 Y: LongInt);
208 Procedure ContentsOutlineOnItemClick (Node: TNode);
209 Procedure DebugLoadLanguageMIOnClick (Sender: TObject);
210 Procedure DebugSaveLanguageFileMIOnClick (Sender: TObject);
211 Procedure SearchResultsListBoxOnClick (Sender: TObject);
212 Procedure VSplitBarOnDblClick (Sender: TObject);
213 Procedure DebugHelpManagerVersionMIOnClick (Sender: TObject);
214 Procedure DebugTopicByResourceIDMIOnClick (Sender: TObject);
215 Procedure ViewHighlightSearchWordsMIOnClick (Sender: TObject);
216 Procedure FileNewWindowMIOnClick (Sender: TObject);
217 Procedure OpenSpecialMIOnClick (Sender: TObject);
218 Procedure NotesListBoxOnScan (Sender: TObject; Var KeyCode: TKeyCode);
219 Procedure ViewPopupMenuOnPopup (Sender: TObject);
220 Procedure SearchPMIOnClick (Sender: TObject);
221 Procedure ViewSourceMIOnClick (Sender: TObject);
222 Procedure PrintMIOnClick (Sender: TObject);
223 Procedure DebugShowWordSeparatorsMIOnClick (Sender: TObject);
224 Procedure DebugStressTestMIOnClick (Sender: TObject);
225 Procedure TopicPropertiesPMIOnClick (Sender: TObject);
226 Procedure NavigateForwardMIOnClick (Sender: TObject);
227 Procedure IndexListBoxOnScan (Sender: TObject; Var KeyCode: TKeyCode);
228 Procedure SearchResultsListBoxOnScan (Sender: TObject;
229 Var KeyCode: TKeyCode);
230 Procedure ContentsOutlineOnScan (Sender: TObject; Var KeyCode: TKeyCode);
231 Procedure ToolsOptionsMIOnClick (Sender: TObject);
232 Procedure EditGlobalSearchMIOnClick (Sender: TObject);
233 Procedure DebugShowParamsMIOnClick (Sender: TObject);
234 Procedure ViewExpandAllMIOnClick (Sender: TObject);
235 Procedure EditBookmarksMIOnClick (Sender: TObject);
236 Procedure CopyPMIOnClick (Sender: TObject);
237 Procedure SelectAllPMIOnClick (Sender: TObject);
238 Procedure AddNoteButtonOnClick (Sender: TObject);
239 Procedure SearchTextEditOnChange (Sender: TObject);
240 Procedure IndexListBoxOnClick (Sender: TObject);
241 Procedure ViewCollapseAllMIOnClick (Sender: TObject);
242 Procedure NotesListBoxOnDblClick (Sender: TObject);
243 Procedure HelpMIOnClick (Sender: TObject);
244 Procedure NotebookOnPageChanged (Sender: TObject);
245 Procedure ViewRefreshMIOnClick (Sender: TObject);
246 Procedure ViewNotesMIOnClick (Sender: TObject);
247 Procedure ViewSearchMIOnClick (Sender: TObject);
248 Procedure ViewIndexMIOnClick (Sender: TObject);
249 Procedure ViewContentsMIOnClick (Sender: TObject);
250 Procedure MainFormOnCloseQuery (Sender: TObject; Var CanClose: Boolean);
251 Procedure GlobalSearchMIOnClick (Sender: TObject);
252 Procedure GotoNoteButtonOnClick (Sender: TObject);
253 Procedure EditNoteButtonOnClick (Sender: TObject);
254 Procedure NotesListBoxOnItemFocus (Sender: TObject; Index: LongInt);
255 Procedure DeleteNoteButtonOnClick (Sender: TObject);
256 Procedure AddBookmarkMIOnClick (Sender: TObject);
257 Procedure AddNoteMIOnClick (Sender: TObject);
258 Procedure FileCloseMIOnClick (Sender: TObject);
259 Procedure CoolBarOnSectionResize (HeaderControl: THeaderControl;
260 section: THeaderSection);
261 Procedure CoolBarOnSectionClick (HeaderControl: THeaderControl;
262 section: THeaderSection);
263 Procedure MainFormOnDestroy (Sender: TObject);
264 Procedure MainFormOnSetupShow (Sender: TObject);
265 Procedure MainFormOnCreate (Sender: TObject);
266 Procedure MainFormOnShow (Sender: TObject);
267 Procedure FindNextMIOnClick (Sender: TObject);
268 Procedure FindMIOnClick (Sender: TObject);
269 Procedure IndexSearchEditOnScan (Sender: TObject; Var KeyCode: TKeyCode);
270 Procedure IndexSearchEditOnChange (Sender: TObject);
271 Procedure FileInformationMIOnClick (Sender: TObject);
272 Procedure SearchTextEditOnScan (Sender: TObject; Var KeyCode: TKeyCode);
273 Procedure SearchButtonOnClick (Sender: TObject);
274 Procedure FileSaveAsMIOnClick (Sender: TObject);
275 Procedure OptionsMIOnClick (Sender: TObject);
276 Procedure TabSetOnChange (Sender: TObject; NewTab: LongInt;
277 Var AllowChange: Boolean);
278 Procedure NotebookOnSetupShow (Sender: TObject);
279 Procedure NavigateBackMIOnClick (Sender: TObject);
280 Procedure NavigatePreviousMIOnClick (Sender: TObject);
281 Procedure NavigateNextMIOnClick (Sender: TObject);
282 Procedure CopyMIOnClick (Sender: TObject);
283 Procedure SelectAllMIOnClick (Sender: TObject);
284 Procedure DebugShowCodesMIOnClick (Sender: TObject);
285 Procedure HelpProductInformationMIOnClick (Sender: TObject);
286 Procedure OnOverLink ( Sender: TRichTextView; LinkString: String);
287 Procedure OnNotOverLink ( Sender: TRichTextView; LinkString: String);
288 Procedure OnClickLink ( Sender: TRichTextView; LinkString: String);
289 Procedure BackButtonOnClick (Sender: TObject);
290 Procedure RTViewOnSetupShow (Sender: TObject);
291 Procedure OpenMIOnClick (Sender: TObject);
292 Procedure ExitMIOnClick (Sender: TObject);
293
294 Procedure MainFormOnResize (Sender: TObject);
295 Procedure VSplitBarOnChange (NewSplit: LongInt);
296 Protected
297 // Custom window messages ----------------------------------
298
299 // Handle our own WM_OPENED message
300 Procedure WMOpened( Var Msg: TMessage ); Message WM_OPENED;
301 Procedure WMFollowLink( Var Msg: TMessage ); Message WM_FOLLOWLINK;
302 Procedure WMFollowExternalLink( Var Msg: TMessage ); Message WM_FOLLOWEXTERNALLINK;
303
304 // Messages from new help manager OR other instances
305 Procedure NHMDisplayIndex( Var Msg: TMessage ); Message NHM_HELP_INDEX;
306 Procedure NHMDisplayContents( Var Msg: TMessage ); Message NHM_HELP_CONTENTS;
307 Procedure NHMTopicByResourceID( Var Msg: TMessage ); Message NHM_TOPIC_BY_RESOURCE_ID;
308 Procedure NHMTopicByPanelName( Var Msg: TMessage ); Message NHM_TOPIC_BY_PANEL_NAME;
309
310 Procedure NHMTest( Var Msg: TMessage ); Message NHM_TEST;
311
312 Procedure NHMSearch( Var Msg: TMessage ); Message NHM_SEARCH;
313 Procedure NHMGlobalSearch( Var Msg: TMessage ); Message NHM_GLOBAL_SEARCH;
314 Procedure NHMShowUsage( Var Msg: TMessage ); Message NHM_SHOW_USAGE;
315
316 Procedure NHMSetFiles( Var Msg: TMessage ); Message NHM_SET_FILES;
317 Procedure NHMSetTitle( Var Msg: TMessage ); Message NHM_SET_TITLE;
318
319 Protected
320 // GUI events set by code ----------------------------------
321
322 Procedure OnHint( Sender: TObject );
323 Procedure OnWindowClose( Window: THelpWindow );
324 Procedure OnWindowAboutToClose( Window: THelpWindow;
325 var CanClose: boolean );
326 Procedure OnNavigateToMenuItemClick( Sender: TObject );
327 Procedure OnDragOverWindow( Sender: TObject;
328 Source: TObject;
329 X: LongInt;
330 Y: LongInt;
331 State: TDragState;
332 Var Accept: Boolean );
333 Procedure OnDragDropToWindow( Sender: TObject;
334 Source: TObject;
335 X: LongInt;
336 Y: LongInt );
337 Procedure OnWindowFontChange( Sender: TObject );
338 Procedure OnWindowTab( Sender: TObject );
339 Procedure OnWindowBackTab( Sender: TObject );
340
341 Procedure OnException( Sender: TObject;
342 E: Exception );
343 Procedure OnHelp( context: THelpContext;
344 var Result: Boolean );
345
346
347 FShowLeftPanel: boolean;
348
349 Function GetShowLeftPanel: boolean;
350 Procedure SetShowLeftPanel( Value: boolean );
351 Property ShowLeftPanel: boolean read GetShowLeftPanel write SetShowLeftPanel;
352
353 Procedure ShowTab( TabIndex: longint );
354
355 procedure GetClassData(var ClassData: TClassData); override;
356 Public
357
358 // Open the file or list of files in FileNames
359 // Set the window title if given, otherwise get it from first file
360 Function OpenFiles( const FileNames: TStrings;
361 const WindowTitle: string;
362 const DisplayFirstTopic: boolean ): boolean;
363
364 // Open a single file
365 Function OpenFile( const FileName: string;
366 const WindowTitle: string;
367 const DisplayFirstTopic: boolean ): boolean;
368
369 Function OpenAdditionalFiles( const FileNames: TStrings;
370 const DisplayFirstTopic: boolean ): boolean;
371
372 Function OpenAdditionalFile( const FileName: string;
373 const DisplayFirstTopic: boolean ): boolean;
374
375 // open from original helpmgr style file1+file2+file3. ..
376 Function OpenFilesFromTextList( const TextList: string;
377 const DisplayFirstTopic: boolean ): boolean;
378
379 Procedure CloseFile;
380 Function OKToCloseFile: boolean;
381
382 Procedure AddCurrentToMRUFiles;
383
384 Function LoadFiles( const FileNames: TStrings;
385 HelpFiles: TList ): boolean;
386 Procedure DisplayFiles( NewFiles: TList;
387 Var FirstContentsNode: TNode );
388
389 Procedure OpenDroppedFile( Source: TObject );
390
391 Function OpenWindowsHelp( const Filename: string ): boolean;
392
393 function DisplayTopicByResourceID( ID: uint16 ): boolean;
394 function DisplayTopicByName( const TopicName: string ): boolean;
395 function DisplayTopicByGlobalName( const TopicName: string ): boolean;
396
397 Procedure DisplayIndex;
398 Procedure DisplayContents;
399 Procedure DisplaySearch;
400
401 Protected
402 // Startup functions ----------------------------------
403
404 Function pSharedStruct: TPNewHelpMgrSharedStruct;
405 Procedure PositionWindow;
406 Procedure RestoreWindow;
407
408 Procedure CheckEnvironmentVars;
409 Procedure ShowUsage;
410
411 // Loading functions ----------------------------------
412
413 // Most recently used files list
414 Procedure CreateMRUMenuItems;
415 Procedure OnMRUMenuItemClick( Sender: TObject );
416
417 Procedure OnHelpFileLoadProgress( n, outof: integer;
418 message: string );
419
420 // Returns nil if file is not open
421 Function FindOpenHelpFile( FileName: string ): THelpFile;
422
423 // Navigation -------------------------------------------------
424
425 Procedure SaveNavigatePoint;
426 Procedure SaveWindows( SourceList: TList;
427 DestList: TList;
428 Parent: TSavedHelpWindow );
429
430 Procedure UpdateCurrentNavigatePoint;
431 Procedure ClearPageHistory;
432
433 Procedure NavigateToPoint( NavPoint: TNavigatePoint );
434 Procedure NavigateToHistoryIndex( Index: longint );
435
436 Procedure DisplayWindows( WindowList: TList;
437 Parent: THelpWindow );
438 Procedure ShowWindows;
439 Procedure ShowWindowList( WindowList: TList );
440 Procedure CloseWindows;
441
442 Procedure FocusFirstHelpWindow;
443
444 Procedure NavigateBack;
445 Procedure NavigateForward;
446 Procedure NavigatePreviousInContents;
447 Procedure NavigateNextInContents;
448
449 Procedure CreateNavigateToMenuItems;
450
451 // GUI status updates ---------------------------------
452
453 Procedure EnableControls;
454 Procedure EnableSearchButton;
455 Procedure SetStatus( Text: String );
456 Procedure SetProgress( n, outof: integer;
457 message: string );
458 Procedure ResetProgress;
459 Procedure RefreshWindows( WindowList: TList );
460
461 // language stuff
462 // called by callback
463 Procedure OnLanguageEvent( Language: TLanguageFile;
464 const Apply: boolean );
465
466 function ShowCodes: boolean;
467 function ShowWordIndices: boolean;
468
469 // Loading views --------------------------------------
470
471 // Used in loading contents
472 Procedure AddChildNodes( HelpFile: THelpFile;
473 ParentNode: TNode;
474 Level: longint;
475 Var TopicIndex: longint );
476 Procedure LoadContents( Files: TList;
477 Var FirstNode: TNode );
478 Procedure LoadIndex;
479
480 // Note manipulations --------------------------------
481
482 procedure AddNote;
483 Procedure EditNote( NoteIndex: longint );
484 procedure DeleteNote( NoteIndex: longint );
485 Procedure SaveNotes;
486 Procedure SaveNotesForFile( HelpFile: THelpFile );
487 Procedure LoadNotes( HelpFile: THelpFile );
488 Procedure GotoCurrentNote;
489
490 // make sure that note insert positions are not in
491 // the middle of tags due to help file or newview updates.
492 Procedure CorrectNotesPositions( Topic: TTopic;
493 Text: pchar );
494
495 Procedure InsertNotesIntoTopicText( Topic: TTopic;
496 Text: TAString );
497 function FindOriginalNoteCharIndex( NoteCharIndex: longword;
498 Topic: TTopic ): longword;
499 function FindActualNoteCharIndex( NoteCharIndex: longword;
500 MaxNoteIndex: longword;
501 Topic: TTopic ): longword;
502 procedure RefreshNoteInsertInfo( NoteIndex: longword );
503 procedure ClearNotes;
504
505 Procedure EnableNotesControls;
506 Procedure UpdateNotesDisplay;
507
508 Procedure RefreshFontSubstitutions;
509
510 // GUI actions ------------------------------------------
511
512 procedure FileOpen;
513
514 Procedure PrintTopics;
515 function DoPrinting( Parameters: TObject ): TObject;
516 Procedure StopPrinting;
517
518 Procedure DoFind( FindOrigin: TFindOrigin );
519
520 // Bookmarks ------------------------------------------
521
522 Procedure NavigateToBookmark( Bookmark: TBookmark );
523 Procedure BuildBookmarksMenu;
524 Procedure UpdateBookmarksForm;
525 Procedure BookmarksMenuItemClick( Sender: TObject );
526 procedure AddBookmark;
527 procedure ClearBookmarks;
528 procedure SaveBookmarks;
529 procedure SaveBookmarksForFile( HelpFile: THelpFile );
530 procedure LoadBookmarks( HelpFile: THelpFile );
531 procedure OnBookmarksChanged( Sender: TObject );
532
533 // Global search -------------------------------------
534
535 procedure DoGlobalSearch( const SearchText: string );
536 // Called when viewing topics from global search
537 Procedure OnViewGlobalSearchTopic( FileName: string;
538 TopicIndex: longint );
539
540 // Options and appearance -----------------------------
541
542 procedure DoOptions;
543
544 procedure ApplySettings;
545
546 // changes normal or fixed font depending on shift state
547 Procedure SetTopicFont( NewFont: TFont );
548
549 Procedure SetApplicationFont( NewFont: TFont );
550
551 // Retrieve control colours (in case drag'n'drop used to change)
552 Procedure GetColors;
553 // Set the layout of the main form
554 Procedure SetLayout;
555 // Lay out the specified list of help windows
556 Procedure LayoutWindowList( WindowList: TList );
557 // Setup the rich text views in the specified windows (e.g for changing global settings)
558 Procedure SetupViews( WindowList: TList );
559
560 // Topic display -------------------------------------
561
562 // Major display topic function.
563 procedure DisplayTopic( Topic: TTopic );
564
565 Procedure DisplaySelectedIndexTopic;
566 Procedure DisplaySelectedSearchResultTopic;
567 Procedure DisplaySelectedContentsTopic;
568
569 Procedure DisplayTopicInWindow( Window: THelpWindow;
570 FollowAutoLinks: boolean;
571 KeepPosition: boolean );
572
573 function OpenWindow( Topic: TTopic;
574 Group: longint;
575 Parent: THelpWindow;
576 Rect: THelpWindowRect;
577 FollowAutoLinks: boolean ): THelpWindow;
578
579 Procedure RemoveHelpWindowFromParent( Window: THelpWindow );
580
581 Procedure FollowLink( Link: THelpLink;
582 SourceWindow: THelpWindow );
583
584 Function FindTopicByResourceID( ID: uint16 ): TTopic;
585 Function FindTopicByName( const Name: string ): TTopic;
586 Function FindTopicByGlobalName( const Name: string ): TTopic;
587
588 Function FindTopicForLink( Link: THelpLink ): TTopic;
589
590 Function FindWindowFromView( View: TRichTextView; WindowList: TList ): THelpWindow;
591 Function FindWindowFromGroup( Group: longint; WindowList: TList ): THelpWindow;
592 Function FindWindowFromTopic( Topic: TTopic; WindowList: TList ): THelpWindow;
593 Function GetActiveWindow: THelpWindow;
594
595 Procedure DoSearch;
596 Procedure SearchFor( const SearchText: string );
597 Procedure StartupTopicSearch( const SearchText: string );
598
599 // clear search match sequences
600 Procedure ClearAllWordSequences;
601
602 Procedure SetMainCaption;
603
604 // cancel help manager mode
605 Procedure ClearHelpManager;
606 Procedure PostHelpManagerMessage( MessageType: ULONG;
607 Param1: long;
608 Param2: long );
609
610 HelpManagerWindows: TList; // of HWND
611
612 function OwnHelpMode: boolean;
613 CurrentOpenFiles: TList; // current open help files.
614 MRUMenuItems: TList; // most recently used file list
615 NavigateToMenuItems: TList;
616 MainTitle: string;
617
618 // Current topic has the vague meaning that it was the last
619 // topic selected by the user... (?)
620 CurrentTopic: TTopic;
621
622 AllFilesWordSequences: TList; // of lists; one per open file; of possible word sequences
623
624 // use during decode...
625 TopicText: TAString;
626
627 Windows: TList; // top level help windows
628
629 PageHistory: TStringList; // history
630 CurrentHistoryIndex: longint; // where we are in history
631
632 Navigating: boolean; // true while going to a particular history point
633
634 DisplayedIndex: TStringList; // duplicate of index listbox,
635 // for fast case insensitive searching
636 InIndexSearch: boolean; // true while searching index
637 IndexLoaded: boolean;
638
639 ContentsLoaded: boolean;
640
641 StartingUp: boolean; // true while starting
642 SettingFont: boolean;
643 DisplayingTopicWindow: boolean;
644
645 FindText: string; // last text found (Ctrl-F)
646
647 Notes: TList; // Notes in current files.
648
649 Bookmarks: TList;
650 BookmarksMenuItems: TList;
651
652 // while loading... so owe can display progress
653 LoadingFilenameList: TStringList;
654 LoadingFileIndex: integer;
655
656 PrintThread: TGenericThreadManager;
657 procedure OnPrintProgress( n, outof: integer;
658 Message: string );
659 procedure OnPrintComplete( Dummy: TObject );
660 protected
661 // language stuff
662 FileOpenTitle: string;
663 LoadingFileMsg: string;
664 HelpFileError: string;
665 LoadingStatusDisplaying: string;
666 LoadingStatusNotesAndBookmarks: string;
667 LoadingStatusContents: string;
668 LoadingStatusIndex: string;
669 LoadingStatusDone: string;
670
671 AllFilesDesc: string;
672 HelpFilesDesc: string;
673 LanguageFilesDesc: string;
674
675 SaveLanguageTitle: string;
676 OpenLanguageTitle: string;
677 SaveLanguageError: string;
678
679 HelpManagerVersionTitle: string;
680
681 FindResourceIDTitle: string;
682 FindResourceIDPrompt: string;
683 InvalidResourceIDError: string;
684 ResourceIDNotFoundError: string;
685
686 OpenSpecialTitle: string;
687 OpenSpecialPrompt: string;
688
689 PrintTopicTitle: string;
690 NoPrinterError: string;
691 SelectWindowToPrintError: string;
692 PrintingError: string;
693 StoppingPrintMsg: string;
694 PrintStoppedMsg: string;
695 CheckStopPrintTitle: string;
696 CheckStopPrintMsg: string;
697
698 TopicInfoTitle: string;
699 TopicInfoTopicTitle: string;
700 TopicInfoIndex: string;
701 TopicInfoFile: string;
702 TopicInfoResourceIDs: string;
703 TopicInfoNoResourceIDs: string;
704
705 ParameterCountLabel: string;
706
707 NewViewHelpTitle: string;
708 AlreadyNewviewHelp: string;
709 NewViewHelpNotFound: string;
710
711 InvalidLinkErrorTitle: string;
712 InvalidLinkError: string;
713 InvalidResourceIDLinkErrorA: string;
714 InvalidResourceIDLinkErrorB: string;
715
716 OpenedTopicMsg: string;
717
718 AddNoteTitle: string;
719 AddNoteCursorError: string;
720 NoteWithinNoteError: string;
721 LoadNotesTitle: string;
722 LoadNotesError: string;
723 SaveNotesTitle: string;
724 SaveNotesError: string;
725
726 UntitledBookmarkName: string;
727 LoadBookmarksTitle: string;
728 LoadBookmarksError: string;
729 SaveBookmarksTitle: string;
730 SaveBookmarksError: string;
731
732 ApplicationErrorTitle: string;
733 ApplicationErrorA: string;
734 ApplicationErrorB: string;
735 ApplicationErrorC: string;
736
737 EnvironmentVarErrorTitle: string;
738 EnvironmentVarError: string;
739 EnvironmentVarUndefined: string;
740
741 FindTitle: string;
742 FindSelectWindowError: string;
743 FindPrompt: string;
744 TextNotFoundMsg: string;
745
746 FilesInfoTitle: string;
747 FilesInfoOverallTitle: string;
748 FilesInfoFilename: string;
749 FilesInfoFileTitle: string;
750 FilesInfoTopicCount: string;
751 FilesInfoIndexCount: string;
752 FilesInfoDictionaryCount: string;
753 FilesInfoFileSize: string;
754 FilesInfoTotalTopicCount: string;
755 FilesInfoTotalIndexCount: string;
756 FilesInfoTotalFileSize: string;
757
758 SearchTitle: string;
759 SearchSyntaxError: string;
760 SearchingMsg: string;
761 NoSearchMatchesMsg: string;
762 SearchFoundMsgA: string;
763 SearchFoundMsgB: string;
764
765 FileSaveTitle: string;
766 FileSaveSelectWindowError: string;
767 DefaultSaveTopicFilename: string;
768 ReplaceFilePromptA: string;
769 ReplaceFilePromptB: string;
770 UnableToSaveError: string;
771
772 UsageTitle: string;
773 UsageText1: string;
774 UsageText2: string;
775 UsageText3: string;
776 UsageText4: string;
777 UsageText5: string;
778 UsageText6: string;
779 UsageText7: string;
780 UsageText8: string;
781
782 GoBackHint: string;
783
784 SelectAllTitle: string;
785 SelectAllWindowError: string;
786
787 EditNoteMsg: string;
788 ExternalLinkMsg: string;
789 LinkMsg: string;
790 UnknownLinkMsg: string;
791 FootnoteMsg: string;
792
793 ExternalLinkTitle: string;
794 ExternalLinkError: string;
795
796 MRUMultipleFilesHint: string;
797
798 HelpProgramTitle: string;
799 WindowsHelpTitle: string;
800 WindowsHelpPrompt: string;
801
802 ErrorTitle: string;
803
804 FindTopicNameTitle: string;
805 FindTopicNamePrompt: string;
806 TopicNameNotFoundError: string;
807
808 SplitBarDblClickToShow: string;
809 SplitBarDblClickToHide: string;
810
811 End;
812
813Var
814 MainForm: TMainForm;
815 CmdLineParameters : TCmdLineParameters;
816
817Implementation
818
819uses
820 BseDos,
821 BseErr,
822 PMWin,
823 PmShl,
824 Dos,
825 Printers,
826
827 // Library
828 ACLStringUtility,
829 AStringUtilityUnit,
830 ACLFileUtility,
831 ACLFileIOUtility,
832 ACLUtility,
833 ACLDialogs,
834 ACLString,
835 RunProgramUnit,
836 StringUtilsUnit,
837 DebugUnit,
838
839 // Components
840 RichTextPrintUnit,
841 RichTextStyleUnit,
842 RichTextDocumentUnit,
843 ControlsUtility,
844
845 // local: forms
846 InformationFormUnit,
847 OptionsForm,
848 ProductInformationFormUnit,
849 NoteForm,
850 GlobalSearchForm,
851 FileDialogForm,
852 BookmarksFormUnit,
853 PrintDialogUnit,
854
855 // local: others
856 SettingsUnit,
857 VersionUnit,
858 SearchUnit,
859 StartupUnit,
860 GlobalFilelistUnit,
861 WebBrowserUnit,
862 HelpBitmap;
863
864{$R Images}
865
866const
867 // Coolbar button indexes
868 ciOpen = 0;
869 ciBack = 1;
870 ciForward = 2;
871 ciPrint = 3;
872 ciAddNote = 4;
873 ciAddBookmark = 5;
874 ciPrevious = 6;
875 ciNext = 7;
876 ciGlobalSearch = 8;
877
878 // Page indexes.
879 piContents = 0;
880 piIndex = 1;
881 piSearch = 2;
882 piNotes = 3;
883
884 CrashLogFileName = 'NewView.log';
885
886 _MAX_PATH = 260;
887
888var
889 hNewViewDLL: HMODULE;
890
891 StartMem: longword;
892 LastMem: longword;
893
894 g_ExternalLinkFilename: string;
895 g_ExternalLinkTopic: string;
896 g_ExternalLinkSourceFilename: string;
897 g_ExternalLinkKeepCurrent: boolean; // whether to keep current files open
898
899//
900// ----------------------------------------------------------------------------------------
901// TMainForm implementation
902// ----------------------------------------------------------------------------------------
903//
904
905Procedure TMainForm.SaveAsIPFMIOnClick (Sender: TObject);
906var
907 FileName: string;
908 F: TextFile;
909 H: THelpFile;
910 i: longint;
911 T: TTopic;
912 ResourceIDs: TList;
913 ImageOffsets: TList;
914 ImageOffset: longint;
915 Image: THelpBitmap;
916Begin
917 H := CurrentOpenFiles[ 0 ];
918
919 FileName := ChangeFileExt( ExtractFileName( H.Filename ), '.ipf' );
920 if not DoSaveFileDialog( FileSaveTitle,
921 'IPF' + '|*.ipf',
922 Filename,
923 Settings.LastSaveDirectory,
924 Filename ) then
925 exit;
926 if FileExists( Filename ) then
927 if not DoConfirmDlg( FileSaveTitle,
928 ReplaceFilePromptA
929 + Filename
930 + ReplaceFilePromptB ) then
931 exit;
932
933 ImageOffsets := TList.Create;
934
935 AssignFile( F, FileName );
936 Rewrite( F );
937 WriteLn( F, ':userdoc.' );
938
939 // We can't tell if some levels of the contents were
940 // merged into the text of topics. So we just assume all are visible
941 WriteLn( F, ':docprof toc=123456.' );
942
943 ResourceIDs := TList.Create;
944
945 WriteLn( F, ':title.' + H.Title );
946
947 for i := 0 to H.TopicCount - 1 do
948 begin
949 T := H.Topics[ i ];
950
951 SetProgress( i div 2, H.TopicCount , 'Saving text...' );
952
953 WriteLn( F, '' );
954
955
956 if T.ContentsLevel = 0 then
957 begin
958 // perhaps it means footnote?
959 // Level := 1;
960 Write( F, ':fn id=fn' + IntToStr( i ) + '.' ); // use index as id
961
962 T.SaveToIPF( F, ImageOffsets );
963
964 WriteLn( F, '' );
965 WriteLn( F, ':efn.' );
966 end
967 else
968 begin
969 Write( F, ':h' + IntToStr( T.ContentsLevel ) );
970 Write( F, ' id=' + IntToStr( i ) ); // use index as id
971
972 H.FindResourceIDsForTopic( T, ResourceIDs );
973 if ResourceIDs.Count > 0 then
974 begin
975 Write( F, ' res=' + IntToStr( longint( ResourceIDs[ 0 ] ) ) );
976 end;
977
978 if not T.ShowInContents then
979 Write( F, ' hide' );
980
981 if T.ContentsGroupIndex > 0 then
982 Write( F, ' group=' + IntToStr( T.ContentsGroupIndex ) );
983
984 Write( F, '.' ); // end of header
985 WriteLn( F, T.Title );
986
987 T.SaveToIPF( F, ImageOffsets );
988 end;
989
990
991
992 end;
993
994 ResourceIDs.Destroy;
995
996 WriteLn( F, ':euserdoc.' );
997 System.Close( F );
998
999 // Now write images
1000
1001 for i := 0 to ImageOffsets.Count - 1 do
1002 begin
1003 ImageOffset := longint( ImageOffsets[ i ] );
1004
1005 SetProgress( i div 2 + ImageOffsets.Count div 2,
1006 ImageOffsets.Count ,
1007 'Saving images...' );
1008
1009 Image := H.GetImage( ImageOffset );
1010
1011 if Image <> nil then
1012 begin
1013 Image.SaveToFile( ExtractFilePath( Filename )
1014 + 'img'
1015 + IntToStr( i )
1016 + '.bmp' );
1017 Image.Destroy;
1018 end;
1019
1020 end;
1021
1022 ResetProgress;
1023 SetStatus( 'Save complete' );
1024 ImageOffsets.Destroy;
1025End;
1026
1027Procedure TMainForm.DebugFindBinaryMIOnClick (Sender: TObject);
1028Var
1029 DataStr: string;
1030 data: array[ 0.. 255 ] of byte;
1031 DataLen: longint;
1032 FileIndex: longint;
1033 HelpFile: THelpFile;
1034 i: longint;
1035 Topic: TTopic;
1036
1037Begin
1038 if not DoInputQuery( 'Binary Find',
1039 'Enter data to find (decimal, separate with spaces)',
1040 DataStr ) then
1041 exit;
1042
1043 DataLen := 0;
1044 while Length( DataStr ) > 0 do
1045 begin
1046 Data[ DataLen ] := StrToInt( ExtractNextValue( DataStr, ' ' ) );
1047 inc( DataLen );
1048 end;
1049
1050 ShowTab( piSearch );
1051 SearchResultsListBox.Clear;
1052
1053 for FileIndex := 0 to CurrentOpenFiles.Count - 1 do
1054 begin
1055 HelpFile := CurrentOpenFiles[ FileIndex ];
1056 for i := 0 to HelpFile.TopicCount -1 do
1057 begin
1058 Topic := HelpFile.Topics[ i ];
1059 if Topic.SearchForData( Addr( Data ), DataLen ) then
1060 begin
1061 SearchResultsListBox.Items.AddObject( Topic.Title, Topic );
1062 end;
1063
1064 end;
1065
1066 end;
1067
1068End;
1069
1070Procedure TMainForm.TopicByNameMIOnClick (Sender: TObject);
1071var
1072 TopicNameString: string;
1073Begin
1074 if not DoInputQuery( FindTopicNameTitle,
1075 FindTopicNamePrompt,
1076 TopicNameString ) then
1077 exit;
1078
1079 if not DisplayTopicByName( TopicNameString ) then
1080 if not DisplayTopicByGlobalName( TopicNameString ) then
1081 DoErrorDlg( FindTopicNameTitle,
1082 TopicNameNotFoundError );
1083End;
1084
1085Function TMainForm.pSharedStruct: TPNewHelpMgrSharedStruct;
1086begin
1087 Result := TPNewHelpMgrSharedStruct( SharedMemory.Data );
1088end;
1089
1090Procedure TMainForm.CopyLinkLocationPMIOnClick (Sender: TObject);
1091Begin
1092
1093End;
1094
1095Procedure TMainForm.HelpKeysMIOnClick (Sender: TObject);
1096Begin
1097// Application.Help( 10 );
1098End;
1099
1100Procedure TMainForm.MainFormOnCommand (Sender: TObject; Var Command: TCommand);
1101Begin
1102 case Command of
1103 kbF11:
1104 NavigatePreviousInContents;
1105
1106 kbF12:
1107 NavigateNextInContents;
1108
1109 kbF7,
1110 kbCtrlCLeft:
1111 NavigateBack;
1112
1113 kbF8:
1114 NavigateForward;
1115 end;
1116End;
1117
1118Procedure TMainForm.MainFormOnScan (Sender: TObject; Var KeyCode: TKeyCode);
1119Begin
1120End;
1121
1122Procedure TMainForm.ShowLeftPanelMIOnClick (Sender: TObject);
1123Begin
1124 ShowLeftPanel := not ShowLeftPanel;
1125End;
1126
1127Procedure TMainForm.CoolBarOnFontChange (Sender: TObject);
1128Begin
1129 SetApplicationFont( Coolbar.Font );
1130End;
1131
1132Procedure TMainForm.NotebookOnFontChange (Sender: TObject);
1133Begin
1134 SetApplicationFont( Notebook.Font );
1135End;
1136
1137Procedure TMainForm.TabSetOnFontChange (Sender: TObject);
1138Begin
1139 SetApplicationFont( TabSet.Font );
1140End;
1141
1142Procedure TMainForm.IndexListBoxOnFontChange (Sender: TObject);
1143Begin
1144 SetApplicationFont( IndexListBox.Font );
1145End;
1146
1147Procedure TMainForm.NotesListBoxOnFontChange (Sender: TObject);
1148Begin
1149 SetApplicationFont( NotesListBox.Font );
1150End;
1151
1152Procedure TMainForm.DisplayPanelOnFontChange (Sender: TObject);
1153Begin
1154 SetTopicFont( DisplayPanel.Font );
1155End;
1156
1157Procedure TMainForm.SetTopicFont( NewFont: TFont );
1158var
1159 ShiftPressed: boolean;
1160Begin
1161 if SettingFont or StartingUp then
1162 exit;
1163 LogEvent(LogSettings, 'SetTopicFont');
1164
1165 SettingFont := true;
1166
1167 ShiftPressed := ( WinGetKeyState( HWND_DESKTOP,
1168 VK_SHIFT ) and $8000 ) > 0;
1169 if ShiftPressed then
1170 Settings.FixedFont := NewFont
1171 else
1172 Settings.NormalFont := NewFont;
1173
1174 LogEvent(LogSettings, 'Saving settings');
1175
1176 SaveSettings;
1177 LogEvent(LogSettings, 'Applying settings');
1178 ApplySettings;
1179
1180 SettingFont := false;
1181 LogEvent(LogSettings, 'SetTopicFont done');
1182End;
1183
1184Procedure TMainForm.ContentsOutlineOnFontChange (Sender: TObject);
1185Begin
1186 SetApplicationFont( ContentsOutline.Font );
1187End;
1188
1189Procedure TMainForm.SetApplicationFont( NewFont: TFont );
1190Begin
1191 if ( not SettingFont ) and ( not StartingUp ) then
1192 begin
1193 Settings.Fonts[ ApplicationFontIndex ] := NewFont;
1194 SaveSettings;
1195 ApplySettings;
1196 SetLayout;
1197 end;
1198End;
1199
1200Procedure TMainForm.SearchResultsListBoxOnFontChange (Sender: TObject);
1201Begin
1202 SetApplicationFont( SearchResultsListBox.Font );
1203End;
1204
1205Procedure TMainForm.OnDragOverWindow(Sender: TObject; Source: TObject;
1206 X: LongInt; Y: LongInt; State: TDragState; Var Accept: Boolean);
1207Begin
1208 if Source is TExternalDragDropObject then
1209 Accept := true;
1210
1211End;
1212
1213Procedure TMainForm.OnDragDropToWindow(Sender: TObject; Source: TObject;
1214 X: LongInt; Y: LongInt);
1215Begin
1216 OpenDroppedFile( Source );
1217End;
1218
1219Procedure TMainForm.OnWindowTab( Sender: TObject );
1220Begin
1221 OnWindowBackTab( Sender ); // for now
1222End;
1223
1224Procedure TMainForm.OnWindowBackTab( Sender: TObject );
1225Begin
1226 case NoteBook.PageIndex of
1227 piContents:
1228 ContentsOutline.Focus;
1229 piIndex:
1230 IndexListBox.Focus;
1231 piSearch:
1232 SearchResultsListBox.Focus;
1233 piNotes:
1234 NotesListBox.Focus;
1235 end;
1236End;
1237
1238Procedure TMainForm.OnWindowFontChange( Sender: TObject );
1239begin
1240 if not DisplayingTopicWindow then
1241 SetTopicFont( TControl(Sender).Font );
1242end;
1243
1244Procedure TMainForm.DisplayPanelOnDragOver (Sender: TObject; Source: TObject;
1245 X: LongInt; Y: LongInt; State: TDragState; Var Accept: Boolean);
1246Begin
1247 if Source is TExternalDragDropObject then
1248 Accept := true;
1249End;
1250
1251Procedure TMainForm.NotesListBoxOnDragOver (Sender: TObject; Source: TObject;
1252 X: LongInt; Y: LongInt; State: TDragState; Var Accept: Boolean);
1253Begin
1254 if Source is TExternalDragDropObject then
1255 Accept := true;
1256End;
1257
1258Procedure TMainForm.DisplayPanelOnDragDrop (Sender: TObject; Source: TObject;
1259 X: LongInt; Y: LongInt);
1260Begin
1261 OpenDroppedFile( Source );
1262End;
1263
1264Procedure TMainForm.NotesListBoxOnDragDrop (Sender: TObject; Source: TObject;
1265 X: LongInt; Y: LongInt);
1266Begin
1267 OpenDroppedFile( Source );
1268End;
1269
1270Procedure TMainForm.SearchResultsListBoxOnDragDrop (Sender: TObject;
1271 Source: TObject; X: LongInt; Y: LongInt);
1272Begin
1273 OpenDroppedFile( Source );
1274End;
1275
1276Procedure TMainForm.SearchResultsListBoxOnDragOver (Sender: TObject;
1277 Source: TObject; X: LongInt; Y: LongInt; State: TDragState;
1278 Var Accept: Boolean);
1279Begin
1280 if Source is TExternalDragDropObject then
1281 Accept := true;
1282End;
1283
1284Procedure TMainForm.IndexListBoxOnDragDrop (Sender: TObject; Source: TObject;
1285 X: LongInt; Y: LongInt);
1286Begin
1287 OpenDroppedFile( Source );
1288End;
1289
1290Procedure TMainForm.IndexListBoxOnDragOver (Sender: TObject; Source: TObject;
1291 X: LongInt; Y: LongInt; State: TDragState; Var Accept: Boolean);
1292Begin
1293 if Source is TExternalDragDropObject then
1294 Accept := true;
1295End;
1296
1297Procedure TMainForm.ContentsOutlineOnDragOver (Sender: TObject;
1298 Source: TObject; X: LongInt; Y: LongInt; State: TDragState;
1299 Var Accept: Boolean);
1300Begin
1301 if Source is TExternalDragDropObject then
1302 Accept := true;
1303End;
1304
1305Procedure TMainForm.ContentsOutlineOnDragDrop (Sender: TObject;
1306 Source: TObject; X: LongInt; Y: LongInt);
1307Begin
1308 OpenDroppedFile( Source );
1309End;
1310
1311Procedure TMainForm.OpenDroppedFile( Source: TObject );
1312var
1313 DropObject: TExternalDragDropObject;
1314Begin
1315 if not ( Source is TExternalDragDropObject ) then
1316 // probably not needed, but crashes during drag drop completely
1317 // screw PM, so best to be sure!
1318 exit;
1319
1320 DropObject := Source as TExternalDragDropObject;
1321
1322 g_ExternalLinkFileName := AddSlash( DropObject.ContainerName )
1323 + DropObject.SourceFilename;
1324 g_ExternalLinkTopic := '';
1325 g_ExternalLinkSourceFilename := ''; // don't care
1326
1327 g_ExternalLinkKeepCurrent := ( WinGetKeyState( HWND_DESKTOP,
1328 VK_SHIFT ) and $8000 ) > 0;
1329 PostMsg( Self.Handle,
1330 WM_FOLLOWEXTERNALLINK,
1331 0,
1332 0 );
1333
1334End;
1335
1336Procedure TMainForm.MainFormOnDragOver (Sender: TObject; Source: TObject;
1337 X: LongInt; Y: LongInt; State: TDragState; Var Accept: Boolean);
1338Begin
1339 Accept := true;
1340End;
1341
1342Procedure TMainForm.MainFormOnDragDrop (Sender: TObject; Source: TObject;
1343 X: LongInt; Y: LongInt);
1344Begin
1345End;
1346
1347Procedure TMainForm.ContentsOutlineOnItemClick (Node: TNode);
1348Begin
1349 DisplaySelectedContentsTopic;
1350End;
1351
1352Procedure TMainForm.SetMainCaption;
1353begin
1354 if ( Trim( MainTitle ) = '' )
1355 or ( StringsSame( Trim( MainTitle ), HelpProgramTitle ) ) then
1356 // supress "Help - " or "Help - Help"
1357 Caption := HelpProgramTitle
1358 else
1359 Caption := HelpProgramTitle + ' - ' + MainTitle
1360end;
1361
1362Procedure TMainForm.OnLanguageEvent( Language: TLanguageFile;
1363 const Apply: boolean );
1364Begin
1365 // get rid of mru menu items
1366 DestroyListObjects( MRUMenuItems );
1367 MRUMenuItems.Clear;
1368
1369 Language.LoadComponentLanguage( self, Apply );
1370
1371 if Apply then
1372 begin
1373 // copy menu hints to toolbar hints
1374 Coolbar.Sections[ ciOpen ].Hint := OpenMI.Hint;
1375 Coolbar.Sections[ ciBack ].Hint := NavigateBackMI.Hint;
1376 Coolbar.Sections[ ciForward ].Hint := NavigateForwardMI.Hint;
1377 Coolbar.Sections[ ciPrint ].Hint := PrintMI.Hint;
1378 Coolbar.Sections[ ciAddNote ].Hint := AddNoteMI.Hint;
1379 Coolbar.Sections[ ciAddBookmark ].Hint := AddBookmarkMI.Hint;
1380 Coolbar.Sections[ ciPrevious ].Hint := NavigatePreviousMI.Hint;
1381 Coolbar.Sections[ ciNext ].Hint := NavigateNextMI.Hint;
1382 Coolbar.Sections[ ciGlobalSearch ].Hint := GlobalSearchMI.Hint;
1383 end;
1384
1385 // Load strings referred to by code...
1386 // ----------------------------------------------------------
1387
1388 Language.LL( Apply, FileOpenTitle, 'FileOpenTitle', 'Open Help Files' );
1389 Language.LL( Apply, LoadingFileMsg, 'LoadingFileMsg', 'Loading file ' );
1390 Language.LL( Apply, HelpFileError, 'HelpFileError', 'Could not open ' );
1391 Language.LL( Apply, LoadingStatusDisplaying, 'LoadingStatusDisplaying', 'Displaying...' );
1392 Language.LL( Apply, LoadingStatusNotesAndBookmarks, 'LoadingStatusNotesAndBookmarks', 'Loading notes/bookmarks...' );
1393 Language.LL( Apply, LoadingStatusContents, 'LoadingStatusContents', 'Display contents... ' );
1394 Language.LL( Apply, LoadingStatusIndex, 'LoadingStatusIndex', 'Display index... ' );
1395 Language.LL( Apply, LoadingStatusDone, 'LoadingStatusDone', 'Done' );
1396
1397 Language.LL( Apply, HelpFilesDesc, 'HelpFilesDesc', 'Help Files (*.inf,*.hlp)' );
1398 Language.LL( Apply, AllFilesDesc, 'AllFilesDesc', 'All Files (*)' );
1399 Language.LL( Apply, LanguageFilesDesc, 'LanguageFilesDesc', 'NewView Language Files (*.lng)' );
1400
1401 Language.LL( Apply, SaveLanguageTitle, 'SaveLanguageTitle', 'Save/Update Language File' );
1402 Language.LL( Apply, OpenLanguageTitle, 'OpenLanguageTitle', 'Open Language File' );
1403 Language.LL( Apply, SaveLanguageError, 'SaveLanguageError', 'Error saving language file: ' );
1404
1405 Language.LL( Apply, HelpManagerVersionTitle, 'HelpManagerVersionTitle', 'Help Manager Version' );
1406
1407 Language.LL( Apply, FindResourceIDTitle, 'FindResourceIDTitle', 'Find Resource ID' );
1408 Language.LL( Apply, FindResourceIDPrompt, 'FindResourceIDPrompt', 'Enter the resource ID to find' );
1409 Language.LL( Apply, InvalidResourceIDError, 'InvalidResourceIDError', 'Invalid resource ID entered' );
1410 Language.LL( Apply, ResourceIDNotFoundError, 'ResourceIDNotFoundError', 'Resource ID not found' );
1411
1412 Language.LL( Apply, OpenSpecialTitle, 'OpenSpecialTitle', 'Open Special' );
1413 Language.LL( Apply, OpenSpecialPrompt, 'OpenSpecialPrompt', 'Enter help file name/environment variable name' );
1414
1415 Language.LL( Apply, PrintTopicTitle, 'PrintTopicTitle', 'Print Topic' );
1416 Language.LL( Apply, NoPrinterError, 'NoPrinterError', 'You don''t have a printer configured.' );
1417 Language.LL( Apply, SelectWindowToPrintError, 'SelectWindowToPrintError', 'You must select the window you want to print.' );
1418 Language.LL( Apply, PrintingError, 'PrintingError', 'Error while printing: ' );
1419 Language.LL( Apply, StoppingPrintMsg, 'StoppingPrintMsg', 'Stopping print...' );
1420 Language.LL( Apply, PrintStoppedMsg, 'PrintStoppedMsg', 'Printing stopped' );
1421 Language.LL( Apply, CheckStopPrintTitle, 'CheckStopPrintTitle', 'Stop Print?' );
1422 Language.LL( Apply, CheckStopPrintMsg, 'CheckStopPrintMsg', 'Printing is still in progress. It will be stopped if you close.' );
1423
1424 Language.LL( Apply, TopicInfoTitle, 'TopicInfo.Title', 'Topic Information' );
1425 Language.LL( Apply, TopicInfoTopicTitle, 'TopicInfo.TopicTitle', 'Title: ' );
1426 Language.LL( Apply, TopicInfoIndex, 'TopicInfo.Index', 'Index: ' );
1427 Language.LL( Apply, TopicInfoFile, 'TopicInfo.File', 'File: ' );
1428 Language.LL( Apply, TopicInfoResourceIDs, 'TopicInfo.ResourceIDs', 'Resource IDs:' );
1429 Language.LL( Apply, TopicInfoNoResourceIDs, 'TopicInfo.NoResourceIDs', ' (None)' );
1430
1431 Language.LL( Apply, ParameterCountLabel, 'ParameterCountLabel', 'Parameter Count: ' );
1432
1433 Language.LL( Apply, NewViewHelpTitle, 'NewViewHelpTitle', 'NewView Help' );
1434 Language.LL( Apply, AlreadyNewviewHelp, 'AlreadyNewviewHelp', 'You are already viewing the NewView help file' );
1435 Language.LL( Apply, NewViewHelpNotFound, 'NewViewHelpNotFound', 'Couldn''t find the NewView helpfile: ' );
1436
1437 Language.LL( Apply, InvalidLinkErrorTitle, 'InvalidLinkErrorTitle', 'Invalid Link' );
1438 Language.LL( Apply, InvalidLinkError, 'InvalidLinkError', 'Cannot follow link to nonexistent topic' );
1439 Language.LL( Apply, InvalidResourceIDLinkErrorA, 'InvalidResourceIDLinkErrorA', 'Could not find linked topic (Resource #' );
1440 Language.LL( Apply, InvalidResourceIDLinkErrorB, 'InvalidResourceIDLinkErrorB', '). This may be from another file.' );
1441
1442 Language.LL( Apply, OpenedTopicMsg, 'OpenedTopicMsg', 'Opened topic #' );
1443
1444 Language.LL( Apply, AddNoteTitle, 'AddNoteTitle', 'Add Note' );
1445 Language.LL( Apply, AddNoteCursorError, 'AddNoteCursorError', 'Before adding a note, position the cursor where you want the note to be placed.' );
1446 Language.LL( Apply, NoteWithinNoteError, 'NoteWithinNoteError', 'You can''t add a note within a link or another note' );
1447 Language.LL( Apply, LoadNotesTitle, 'LoadNotesTitle', 'Load Notes' );
1448 Language.LL( Apply, LoadNotesError, 'LoadNotesError', 'Error loading notes from ' );
1449 Language.LL( Apply, SaveNotesTitle, 'SaveNotesTitle', 'Save Notes' );
1450 Language.LL( Apply, SaveNotesError, 'SaveNotesError', 'Error saving notes to ' );
1451
1452 Language.LL( Apply, UntitledBookmarkName, 'UntitledBookmarkName', '(Untitled)' );
1453 Language.LL( Apply, LoadBookmarksTitle, 'LoadBookmarksTitle', 'Load Bookmarks' );
1454 Language.LL( Apply, LoadBookmarksError, 'LoadBookmarksError', 'Could not load bookmarks: ' );
1455 Language.LL( Apply, SaveBookmarksTitle, 'SaveBookmarksTitle', 'Save Bookmarks' );
1456 Language.LL( Apply, SaveBookmarksError, 'SaveBookmarksError', 'Could not save bookmarks: ' );
1457
1458 Language.LL( Apply, ApplicationErrorTitle, 'ApplicationErrorTitle', 'Application Error - Close?' );
1459 Language.LL( Apply, ApplicationErrorA, 'ApplicationErrorA', 'This application has crashed. ' );
1460 Language.LL( Apply, ApplicationErrorB, 'ApplicationErrorB', '(Details logged to ' );
1461 Language.LL( Apply, ApplicationErrorC, 'ApplicationErrorC', 'Close application? ' );
1462
1463 Language.LL( Apply, EnvironmentVarErrorTitle, 'EnvironmentVarErrorTitle', 'Environment Variable Warning' );
1464 Language.LL( Apply, EnvironmentVarError,
1465 'EnvironmentVarError',
1466 'NewView found a problem with environment variables. '
1467 + 'These are used when finding help files. '
1468 + 'You may have problems launching help.' );
1469 Language.LL( Apply, EnvironmentVarUndefined, 'EnvironmentVarUndefined', 'Undefined: ' );
1470
1471 Language.LL( Apply, FindTitle, 'FindTitle', 'Find' );
1472 Language.LL( Apply, FindSelectWindowError, 'FindSelectWindowError', 'Click in a window first' );
1473 Language.LL( Apply, FindPrompt, 'FindPrompt', 'Enter the text to find' );
1474 Language.LL( Apply, TextNotFoundMsg, 'TextNotFoundMsg', 'Text not found' );
1475
1476 Language.LL( Apply, FilesInfoTitle, 'FilesInfoTitle', 'Open Files Information' );
1477 Language.LL( Apply, FilesInfoOverallTitle, 'FilesInfoOverallTitle', 'Title: ' );
1478 Language.LL( Apply, FilesInfoFilename, 'FilesInfoFilename', 'Filename: ' );
1479 Language.LL( Apply, FilesInfoFileTitle, 'FilesInfoFileTitle', ' Title: ' );
1480 Language.LL( Apply, FilesInfoTopicCount, 'FilesInfoTopicCount', ' Topic Count: ' );
1481 Language.LL( Apply, FilesInfoIndexCount, 'FilesInfoIndexCount', ' Index Count: ' );
1482 Language.LL( Apply, FilesInfoDictionaryCount, 'FilesInfoDictionaryCount', ' Dictionary Count: ' );
1483 Language.LL( Apply, FilesInfoFileSize, 'FilesInfoFileSize', ' Size: ' );
1484 Language.LL( Apply, FilesInfoTotalTopicCount, 'FilesInfoTotalTopicCount', 'Total Topic Count: ' );
1485 Language.LL( Apply, FilesInfoTotalIndexCount, 'FilesInfoTotalIndexCount', 'Total Index Count: ' );
1486 Language.LL( Apply, FilesInfoTotalFileSize, 'FilesInfoTotalFileSize', 'Total File Size: ' );
1487
1488 Language.LL( Apply, SearchTitle, 'SearchTitle', 'Search' );
1489 Language.LL( Apply, SearchSyntaxError, 'SearchSyntaxError', 'Error in search syntax: ' );
1490 Language.LL( Apply, SearchingMsg, 'SearchingMsg', 'Searching...' );
1491 Language.LL( Apply, NoSearchMatchesMsg, 'NoSearchMatchesMsg', 'No matches found for ' );
1492 Language.LL( Apply, SearchFoundMsgA, 'SearchFoundMsgA', 'Found ' );
1493 Language.LL( Apply, SearchFoundMsgB, 'SearchFoundMsgB', ' matches for ' );
1494
1495 Language.LL( Apply, FileSaveTitle, 'FileSaveTitle', 'Save Topic' );
1496 Language.LL( Apply, FileSaveSelectWindowError, 'FileSaveSelectWindowError', 'Before saving, click in the window you want to save.' );
1497 Language.LL( Apply, DefaultSaveTopicFilename, 'DefaultSaveTopicFilename', 'topic.txt' );
1498
1499 Language.LL( Apply, ReplaceFilePromptA, 'ReplaceFilePromptA', 'Replace existing file ' );
1500 Language.LL( Apply, ReplaceFilePromptB, 'ReplaceFilePromptB', '?' );
1501 Language.LL( Apply, UnableToSaveError, 'UnableToSaveError', 'Unable to save file: ' );
1502
1503 Language.LL( Apply, UsageTitle, 'UsageTitle', 'NewView Command Line' );
1504 Language.LL( Apply, UsageText1, 'UsageText1', 'Usage: ' );
1505 Language.LL( Apply, UsageText2, 'UsageText2', 'NewView <filename> [<topic>]' );
1506 Language.LL( Apply, UsageText3, 'UsageText3', ' /s:<text> Do search for <text>' );
1507 Language.LL( Apply, UsageText4, 'UsageText4', ' /g:<text> Do global search for <text>' );
1508 Language.LL( Apply, UsageText5, 'UsageText5', ' /pos:l,b,w,h Set window position' );
1509 Language.LL( Apply, UsageText6, 'UsageText6', ' /lang:<lang> Load UI language' );
1510 Language.LL( Apply, UsageText7, 'UsageText7', ' /title:<title> Set window title' );
1511 Language.LL( Apply, UsageText8, 'UsageText8', 'See help for details' );
1512
1513 Language.LL( Apply, GoBackHint, 'GoBackHint', 'Go back to ' );
1514
1515 Language.LL( Apply, SelectAllTitle, 'SelectAllTitle', 'Select All' );
1516 Language.LL( Apply, SelectAllWindowError, 'SelectAllWindowError', 'Click in a text window first' );
1517
1518 Language.LL( Apply, EditNoteMsg, 'EditNoteMsg', 'Click to edit note' );
1519 Language.LL( Apply, ExternalLinkMsg, 'ExternalLinkMsg', 'Link to another file' );
1520 Language.LL( Apply, LinkMsg, 'LinkMsg', 'Link to ' );
1521 Language.LL( Apply, UnknownLinkMsg, 'UnknownLinkMsg', 'Unknown link' );
1522 Language.LL( Apply, FootnoteMsg, 'FootnoteMsg', 'Footnote' );
1523
1524 Language.LL( Apply, ExternalLinkTitle, 'ExternalLinkTitle', 'File Link' );
1525 Language.LL( Apply, ExternalLinkError, 'ExternalLinkError', 'Sorry, this is a link to another file, which is not currently implemented in NewView' );
1526
1527 Language.LL( Apply, MRUMultipleFilesHint, 'MRUMultipleFilesHint', 'files' );
1528 Language.LL( Apply, HelpProgramTitle, 'HelpProgramTitle', 'Help' );
1529
1530 Language.LL( Apply, WindowsHelpTitle, 'WindowsHelpTitle', 'Windows Help' );
1531 Language.LL( Apply,
1532 WindowsHelpPrompt,
1533 'WindowsHelpPrompt',
1534 'This file is a Windows help file. '
1535 + 'Would you like to start Windows Help viewer?' );
1536
1537 Language.LL( Apply, ErrorTitle, 'ErrorTitle', 'Error' );
1538
1539 Language.LL( Apply, FindTopicNameTitle, 'FindTopicNameTitle', 'Find Topic By Name' );
1540 Language.LL( Apply, FindTopicNamePrompt, 'FindTopicNamePrompt', 'Enter the topic name to search for' );
1541 Language.LL( Apply, TopicNameNotFoundError, 'TopicNameNotFoundError', 'Topic name not found' );
1542 Language.LL( Apply, SplitBarDblClickToShow, 'SplitBarDblClickToShow', 'Double-click to show left panel' );
1543 Language.LL( Apply, SplitBarDblClickToHide, 'SplitBarDblClickToHide', 'Double-click to hide left panel' );
1544
1545 SetMainCaption;
1546 CreateMRUMenuItems;
1547
1548 // ----------------------------------------------------------
1549end;
1550
1551Procedure TMainForm.DebugLoadLanguageMIOnClick (Sender: TObject);
1552Var
1553 Dir: string;
1554 Filename: string;
1555Begin
1556 Dir := GetApplicationDir;
1557 if not DoOpenFileDialog( OpenLanguageTitle,
1558 LanguageFilesDesc
1559 + '|*.lng|'
1560 + AllFilesDesc
1561 + '|*',
1562 '*.lng',
1563 Dir,
1564 Filename ) then
1565 exit;
1566
1567 LoadLanguage( Filename );
1568End;
1569
1570Procedure TMainForm.DebugSaveLanguageFileMIOnClick (Sender: TObject);
1571Var
1572 LanguageFile: TLanguageFile;
1573 Dir: string;
1574 Filename: string;
1575Begin
1576 Dir := GetApplicationDir;
1577 if not DoSaveFileDialog( SaveLanguageTitle,
1578 LanguageFilesDesc
1579 + '|*.lng|'
1580 + AllFilesDesc
1581 + '|*',
1582 '*.lng',
1583 Dir,
1584 Filename ) then
1585 exit;
1586
1587 // get rid of mru menu items so they don't clutter the language file
1588 DestroyListObjects( MRUMenuItems );
1589 MRUMenuItems.Clear;
1590
1591 try
1592 LanguageFile := TLanguageFile.Create( Filename );
1593
1594 UpdateLanguage( LanguageFile );
1595 except
1596 on E: Exception do
1597 begin
1598 DoErrorDlg( SaveLanguageTitle,
1599 SaveLanguageError + E.Message );
1600 exit;
1601 end;
1602 end;
1603
1604 LanguageFile.Destroy;
1605
1606 CreateMRUMenuItems;
1607End;
1608
1609Procedure TMainForm.SearchResultsListBoxOnClick (Sender: TObject);
1610Begin
1611 DisplaySelectedSearchResultTopic;
1612End;
1613
1614Procedure TMainForm.VSplitBarOnDblClick (Sender: TObject);
1615Begin
1616 ShowLeftPanel := not ShowLeftPanel;
1617End;
1618
1619Procedure TMainForm.DebugHelpManagerVersionMIOnClick (Sender: TObject);
1620Begin
1621 DoMessageDlg( HelpManagerVersionTitle,
1622 HelpManagerVersion );
1623End;
1624
1625Procedure TMainForm.DebugTopicByResourceIDMIOnClick (Sender: TObject);
1626var
1627 ResourceIDString: string;
1628 ResourceID: USHORT;
1629Begin
1630 if not DoInputQuery( FindResourceIDTitle,
1631 FindResourceIDPrompt,
1632 ResourceIDString ) then
1633 exit;
1634 try
1635 ResourceID := StrToInt( ResourceIDString );
1636 except
1637 DoErrorDlg( FindResourceIDTitle,
1638 InvalidResourceIDError );
1639 exit;
1640 end;
1641
1642 if not DisplayTopicByResourceID( ResourceID ) then
1643 DoErrorDlg( FindResourceIDTitle,
1644 ResourceIDNotFoundError );
1645End;
1646
1647Procedure TMainForm.ViewHighlightSearchWordsMIOnClick (Sender: TObject);
1648Begin
1649 ViewHighlightSearchWordsMI.Checked := not ViewHighlightSearchWordsMI.Checked;
1650 RefreshWindows( Windows );
1651End;
1652
1653Procedure TMainForm.FileNewWindowMIOnClick (Sender: TObject);
1654Begin
1655 Exec( GetApplicationFilename, '' );
1656End;
1657
1658Function TMainForm.OpenFilesFromTextList( const TextList: string;
1659 const DisplayFirstTopic: boolean ): boolean;
1660var
1661 Filenames: TStringList;
1662begin
1663 Filenames := TStringList.Create;
1664 StringToList( TextList, Filenames, '+' );
1665 if Filenames.Count > 0 then
1666 begin
1667 result := OpenFiles( Filenames, '', DisplayFirstTopic );
1668 end
1669 else
1670 begin
1671 CloseFile;
1672 end;
1673 Filenames.Destroy;
1674end;
1675
1676Procedure TMainForm.OpenSpecialMIOnClick (Sender: TObject);
1677var
1678 Parameter: string;
1679Begin
1680 if not OKToCloseFile then
1681 exit;
1682
1683 if DoInputQuery( OpenSpecialTitle,
1684 OpenSpecialPrompt,
1685 Parameter ) then
1686 begin
1687 if OpenFilesFromTextList( Parameter, true ) then
1688 begin
1689 ClearHelpManager;
1690 end;
1691 end;
1692End;
1693
1694Procedure TMainForm.NotesListBoxOnScan (Sender: TObject;
1695 Var KeyCode: TKeyCode);
1696Begin
1697 if KeyCode in [ kbDel, kbBkSp ] then
1698 if NotesListBox.ItemIndex <> -1 then
1699 DeleteNote( NotesListBox.ItemIndex );
1700End;
1701
1702Procedure TMainForm.ViewPopupMenuOnPopup (Sender: TObject);
1703var
1704 Window: THelpWindow;
1705Begin
1706 Window := GetActiveWindow;
1707 if Window = nil then
1708 begin
1709 SearchPMI.Enabled := false;
1710 exit;
1711 end;
1712 SearchPMI.Enabled := Window.View.SelectionLength > 0;
1713End;
1714
1715Procedure TMainForm.SearchPMIOnClick (Sender: TObject);
1716var
1717 Window: THelpWindow;
1718Begin
1719 Window := GetActiveWindow;
1720 if Window = nil then
1721 exit;
1722
1723 SearchFor( Window.View.GetSelectionAsString );
1724end;
1725
1726function TMainForm.DisplayTopicByGlobalName( const TopicName: string ): boolean;
1727var
1728 Topic: TTopic;
1729begin
1730 Topic := FindTopicByGlobalName( TopicName );
1731 if Topic = nil then
1732 begin
1733 Result := false;
1734 exit;
1735 end;
1736
1737 result := true;
1738
1739 DisplayTopic( Topic );
1740end;
1741
1742function TMainForm.DisplayTopicByName( const TopicName: string ): boolean;
1743var
1744 Topic: TTopic;
1745begin
1746 Topic := FindTopicByName( TopicName );
1747 if Topic = nil then
1748 begin
1749 Result := false;
1750 exit;
1751 end;
1752
1753 result := true;
1754
1755 DisplayTopic( Topic );
1756end;
1757
1758function TMainForm.DisplayTopicByResourceID( ID: uint16 ): boolean;
1759var
1760 Topic: TTopic;
1761begin
1762 Topic := FindTopicByResourceID( ID );
1763 if Topic = nil then
1764 begin
1765 Result := false;
1766 exit;
1767 end;
1768
1769 result := true;
1770
1771 DisplayTopic( Topic );
1772end;
1773
1774Procedure TMainForm.ViewSourceMIOnClick (Sender: TObject);
1775var
1776 Window: THelpWindow;
1777Begin
1778 Window := GetActiveWindow;
1779 if Window = nil then
1780 exit;
1781 InformationForm.FText := Window.View.Text;
1782 InformationForm.ShowModal;
1783End;
1784
1785Procedure TMainForm.PrintMIOnClick (Sender: TObject);
1786Begin
1787 PrintTopics;
1788End;
1789
1790type
1791 TPrintSingle = class
1792 Topic: TTopic;
1793 end;
1794
1795 TPrintList = class
1796 Topics: TList;
1797 constructor Create;
1798 destructor Destroy; override;
1799 end;
1800
1801 TPrintAll = class
1802 end;
1803
1804constructor TPrintList.Create;
1805begin
1806 Topics := TList.Create;
1807end;
1808
1809destructor TPrintList.Destroy;
1810begin
1811 Topics.Destroy;
1812end;
1813
1814// Recursive
1815Procedure GetTopicsInWindows( Windows: TList;
1816 Topics: TList );
1817var
1818 Window: THelpWindow;
1819 i: longint;
1820begin
1821 for i := 0 to Windows.Count - 1 do
1822 begin
1823 Window := Windows[ i ];
1824 Topics.Add( Window.Topic );
1825 GetTopicsInWindows( Window.ChildWindows, Topics );
1826 end;
1827end;
1828
1829Procedure TMainForm.PrintTopics;
1830var
1831 Window: THelpWindow;
1832 PrintParameters: TObject;
1833Begin
1834 if Printer.Printers.Count = 0 then
1835 begin
1836 DoErrorDlg( PrintTopicTitle,
1837 NoPrinterError );
1838 exit;
1839 end;
1840
1841 if NewViewPrintDialog.ShowModal <> mrOK then
1842 exit;
1843
1844 if PrintThread = nil then
1845 begin
1846 PrintThread := TGenericThreadManager.Create( self );
1847 PrintThread.OnProgressUpdate := OnPrintProgress;
1848 PrintThread.OnJobComplete := OnPrintComplete;
1849
1850 end;
1851
1852 case NewViewPrintDialog.WhatToPrintRadioGroup.ItemIndex of
1853 0:
1854 begin
1855 PrintParameters := TPrintSingle.Create;
1856 Window := GetActiveWindow;
1857 TPrintSingle( PrintParameters ).Topic := Window.Topic;
1858 end;
1859
1860 1:
1861 begin
1862 PrintParameters := TPrintList.Create;
1863 GetTopicsInWindows( Windows,
1864 TPrintList( PrintParameters ).Topics );
1865 end;
1866
1867 2:
1868 begin
1869 PrintParameters := TPrintAll.Create;
1870 end;
1871 end;
1872
1873 PrintThread.StartJob( DoPrinting, PrintParameters );
1874
1875 SetStatus( 'Printing...' );
1876end;
1877
1878procedure PrintTopic( Topic: TTopic;
1879 RichTextSettings: TRichTextSettings;
1880 Var PageY: longint );
1881var
1882 TopicText: TAstring;
1883 TitleText: TAString;
1884 ImageOffsets: TList;
1885 Images: TImageList;
1886begin
1887 TopicText := TAstring.Create;
1888 Images := TImageList.Create( nil );
1889 TitleText := TAString.Create;
1890 ImageOffsets := TList.Create;
1891
1892 TitleText.AddString( '<leftmargin 1><h1>'
1893 + Topic.Title
1894 + '</h>'
1895 + #10
1896 + #10 );
1897 PrintRichText( TitleText.AsPChar,
1898 Images,
1899 RichTextSettings,
1900 PageY );
1901
1902 Topic.GetText( nil, // no highlights
1903 false, // no codes
1904 false, // no word separators
1905 TopicText, // text to print
1906 ImageOffsets, // image offsets
1907 nil ); // no highlight matches required
1908
1909 THelpFile( Topic.HelpFile ).GetImages( ImageOffsets,
1910 Images );
1911
1912 PrintRichText( TopicText.AsPChar,
1913 Images,
1914 RichTextSettings,
1915 PageY );
1916
1917 TitleText.Clear;
1918 TitleText.AddString( #10
1919 + '<leftmargin 1><align center>'
1920 + '--------------------------------------------'
1921 + #10
1922 + #10 );
1923 PrintRichText( TitleText.AsPChar,
1924 Images,
1925 RichTextSettings,
1926 PageY );
1927
1928 ImageOffsets.Destroy;
1929 TitleText.Destroy;
1930 Images.Destroy;
1931 TopicText.Destroy;
1932end;
1933
1934function TMainForm.DoPrinting( Parameters: TObject ): TObject;
1935var
1936 PrintSingle: TPrintSingle;
1937 PrintList: TPrintList;
1938 PageY: longint;
1939 RichTextSettings: TRichTextSettings;
1940 PrinterResolution: longint;
1941 MarginSize: longint;
1942
1943 HelpFile: THelpFile;
1944
1945 FileIndex: longint;
1946 TopicIndex: longint;
1947
1948 TotalTopics: longint;
1949 TotalTopicIndex: longint;
1950begin
1951 PrintSingle := nil;
1952 PrintList := nil;
1953
1954 if Parameters is TPrintSingle then
1955 PrintSingle := Parameters as TPrintSingle
1956 else if Parameters is TPrintList then
1957 PrintList := Parameters as TPrintList;
1958
1959 if Parameters is TPrintSingle then
1960 Printer.Title := PrintSingle.Topic.Title
1961 else
1962 Printer.Title := MainTitle;
1963
1964 Printer.BeginDoc;
1965
1966 PageY := Printer.PageHeight - 1;
1967
1968 RichTextSettings := TRichTextSettings.Create( nil );
1969 RichTextSettings.NormalFont := Settings.NormalFont;
1970 RichTextSettings.FixedFont := Settings.FixedFont;
1971
1972 // set half inch margins
1973 PrinterResolution := Printer.Canvas.HorizontalResolution; // pixels per meter!
1974 MarginSize := Round( PrinterResolution * 0.0125 ); // 12.5 mm = 0.5 inch
1975 RichTextSettings.Margins := Rect( MarginSize,
1976 MarginSize,
1977 MarginSize,
1978 MarginSize );
1979
1980 try
1981 if Parameters is TPrintSingle then
1982 begin
1983 PrintTopic( PrintSingle.Topic, RichTextSettings, PageY );
1984 end
1985
1986 else if Parameters is TPrintList then
1987 begin
1988 for TopicIndex := 0 to PrintList.Topics.Count -1 do
1989 begin
1990 PrintThread.UpdateProgress( TopicIndex, PrintList.Topics.Count, 'Printing' );
1991
1992 PrintTopic( PrintList.Topics[ TopicIndex ] , RichTextSettings, PageY );
1993
1994 if PrintThread.StopRequested then
1995 break;
1996 end
1997 end
1998
1999 else if Parameters is TPrintAll then
2000 begin
2001 // first count up total number of topics.
2002 TotalTopics := 0;
2003 for FileIndex := 0 to CurrentOpenFiles.Count - 1 do
2004 begin
2005 HelpFile := CurrentOpenFiles[ FileIndex ];
2006 inc( TotalTopics, HelpFile.TopicCount );
2007 end;
2008
2009 TotalTopicIndex := 0;
2010 for FileIndex := 0 to CurrentOpenFiles.Count - 1 do
2011 begin
2012 HelpFile := CurrentOpenFiles[ FileIndex ];
2013 for TopicIndex := 0 to HelpFile.TopicCount - 1 do
2014 begin
2015 PrintThread.UpdateProgress( TotalTopicIndex, TotalTopics, 'Printing' );
2016 PrintTopic( HelpFile.Topics[ TopicIndex ], RichTextSettings, PageY );
2017 if PrintThread.StopRequested then
2018 break;
2019 inc( TotalTopicIndex );
2020 end;
2021 end;
2022 end;
2023 except
2024 on E: EPrinter do
2025 begin
2026 DoErrorDlg( PrintTopicTitle,
2027 PrintingError + E.Message );
2028 end;
2029 end;
2030
2031 Printer.EndDoc;
2032 result := nil;
2033End;
2034
2035procedure TMainForm.OnPrintProgress( n, outof: integer;
2036 Message: string );
2037begin
2038 SetProgress( n, outof, message );
2039end;
2040
2041procedure TMainForm.OnPrintComplete( Dummy: TObject );
2042begin
2043 SetStatus( 'Printing complete' );
2044 ResetProgress;
2045end;
2046
2047// --------------------------------------------------
2048
2049Procedure TMainForm.DebugShowWordSeparatorsMIOnClick (Sender: TObject);
2050Begin
2051 DebugShowWordSeparatorsMI.Checked := not DebugShowWordSeparatorsMI.Checked;
2052 RefreshWindows( Windows );
2053End;
2054
2055Procedure TMainForm.DebugStressTestMIOnClick (Sender: TObject);
2056var
2057 i: longint;
2058 NString: string;
2059 N: longint;
2060Begin
2061 if not DoInputQuery( 'Stress Test',
2062 'Repititions?',
2063 NString ) then
2064 exit;
2065 N := StrToIntDef( NString, 1 );
2066 for i := 0 to N - 1 do
2067 begin
2068 ContentsOutline.GotoFirstNode;
2069 repeat
2070 DisplaySelectedContentsTopic;
2071 Application.ProcessMessages;
2072 until not ContentsOutline.GotoNextNodeDown;
2073 end;
2074End;
2075
2076// Find topic specified by global name, in all open files
2077Function TMainForm.FindTopicByGlobalName( const Name: string ): TTopic;
2078var
2079 FileIndex: longint;
2080 HelpFile: THelpFile;
2081begin
2082 Result := nil;
2083
2084 for FileIndex := 0 to CurrentOpenFiles.Count - 1 do
2085 begin
2086 HelpFile := CurrentOpenFiles[ FileIndex ];
2087 Result := HelpFile.FindTopicByGlobalName( Name );
2088 if Result <> nil then
2089 // found
2090 exit;
2091 end;
2092
2093 // not found.
2094 Result := nil;
2095end;
2096
2097// Find topic specified by numeric resource ID, in all open files
2098Function TMainForm.FindTopicByResourceID( ID: uint16 ): TTopic;
2099var
2100 FileIndex: longint;
2101 HelpFile: THelpFile;
2102begin
2103 for FileIndex := 0 to CurrentOpenFiles.Count - 1 do
2104 begin
2105 HelpFile := CurrentOpenFiles[ FileIndex ];
2106
2107 Result := HelpFile.FindTopicByResourceID( ID );
2108 if Result <> nil then
2109 // found
2110 exit;
2111 end;
2112
2113 // not found.
2114 Result := nil;
2115end;
2116
2117// Find topic specified by text name, in all open files
2118Function TMainForm.FindTopicByName( const Name: string ): TTopic;
2119var
2120 FileIndex: longint;
2121 HelpFile: THelpFile;
2122begin
2123 Result := nil;
2124
2125 for FileIndex := 0 to CurrentOpenFiles.Count - 1 do
2126 begin
2127 HelpFile := CurrentOpenFiles[ FileIndex ];
2128 Result := HelpFile.FindTopicByLocalName( Name );
2129 if Result <> nil then
2130 // found
2131 exit;
2132 end;
2133
2134 // not found.
2135 Result := nil;
2136end;
2137
2138// Find the target topic for the given link
2139Function TMainForm.FindTopicForLink( Link: THelpLink ): TTopic;
2140var
2141 HelpFile: THelpFile;
2142begin
2143 HelpFile := Link.HelpFile as THelpFile;
2144 if Link is TFootnoteHelpLink then
2145 begin
2146 Result := HelpFile.Topics[ TFootnoteHelpLink( Link ).TopicIndex ];
2147 end
2148 else if Link is TInternalHelpLink then
2149 begin
2150 Result := HelpFile.Topics[ TInternalHelpLink( Link ).TopicIndex ];
2151 end
2152 else if Link is THelpLinkByResourceID then
2153 begin
2154 Result := FindTopicByResourceID( THelpLinkByResourceID( Link ).ResourceID );
2155 end
2156end;
2157
2158Procedure TMainForm.TopicPropertiesPMIOnClick (Sender: TObject);
2159var
2160 Window: THelpWindow;
2161 Topic: TTopic;
2162 HelpFile: THelpFile;
2163 ResourceIDs: TList;
2164 i: longint;
2165Begin
2166 Window := GetActiveWindow;
2167 if Window = nil then
2168 exit;
2169 Topic := Window.Topic;
2170 HelpFile := Topic.HelpFile as THelpFile;
2171
2172 ResourceIDs := TList.Create;
2173 HelpFile.FindResourceIDsForTopic( Topic,
2174 ResourceIDs );
2175
2176 with InformationForm.InformationMemo do
2177 begin
2178 Lines.Clear;
2179 Lines.Add( TopicInfoTitle );
2180 Lines.Add( TopicInfoTopicTitle + Topic.Title );
2181 Lines.Add( TopicInfoIndex + IntToStr( Topic.Index ) );
2182 Lines.Add( TopicInfoFile + HelpFile.Filename );
2183 Lines.Add( TopicInfoResourceIDs );
2184 for i := 0 to ResourceIDs.Count - 1 do
2185 Lines.Add( ' ' + IntToStr( longint( ResourceIDs[ i ] ) ) );
2186 if ResourceIDs.Count = 0 then
2187 Lines.Add( TopicInfoNoResourceIDs );
2188 end;
2189 ResourceIDs.Destroy;
2190
2191 InformationForm.ShowModal;
2192End;
2193Procedure TMainForm.NavigateForwardMIOnClick (Sender: TObject);
2194Begin
2195 NavigateForward;
2196End;
2197
2198Procedure TMainForm.FocusFirstHelpWindow;
2199begin
2200 if Windows.Count > 0 then
2201 THelpWindow( Windows[ 0 ] ).View.Focus;
2202end;
2203
2204Procedure TMainForm.IndexListBoxOnScan (Sender: TObject;
2205 Var KeyCode: TKeyCode);
2206Begin
2207 case KeyCode of
2208 kbTab:
2209 begin
2210 FocusFirstHelpWindow;
2211 KeyCode := kbNull;
2212 end;
2213 kb_VK + VK_NEWLINE:
2214 DisplaySelectedIndexTopic;
2215 end;
2216End;
2217
2218Procedure TMainForm.SearchResultsListBoxOnScan (Sender: TObject;
2219 Var KeyCode: TKeyCode);
2220Begin
2221 case KeyCode of
2222 kbTab:
2223 begin
2224 FocusFirstHelpWindow;
2225 KeyCode := kbNull;
2226 end;
2227
2228 kb_VK + VK_NEWLINE:
2229 DisplaySelectedSearchResultTopic;
2230 end;
2231End;
2232
2233Procedure TMainForm.ContentsOutlineOnScan (Sender: TObject;
2234 Var KeyCode: TKeyCode);
2235Begin
2236 case KeyCode of
2237 kbTab:
2238 begin
2239 FocusFirstHelpWindow;
2240 KeyCode := kbNull;
2241 end;
2242 kb_VK + VK_NEWLINE:
2243 DisplaySelectedContentsTopic;
2244 end;
2245End;
2246
2247Procedure TMainForm.ToolsOptionsMIOnClick (Sender: TObject);
2248Begin
2249 DoOptions;
2250End;
2251
2252Procedure TMainForm.EditGlobalSearchMIOnClick (Sender: TObject);
2253Begin
2254 DoGlobalSearch( '' );
2255End;
2256
2257Procedure TMainForm.ViewExpandAllMIOnClick (Sender: TObject);
2258Begin
2259 DisplayContents;
2260 ContentsOutline.ExpandAll;
2261End;
2262
2263Procedure TMainForm.DebugShowParamsMIOnClick (Sender: TObject);
2264var
2265 tmpWindowPosition : TWindowPosition;
2266Begin
2267 with InformationForm.InformationMemo do
2268 begin
2269 Lines.Clear;
2270 Lines.Add('');
2271
2272 CmdLineParameters.writeDetailsTo(Lines);
2273 end;
2274
2275 InformationForm.ShowModal;
2276End;
2277
2278Procedure TMainForm.EditBookmarksMIOnClick (Sender: TObject);
2279Begin
2280 BookmarksForm.BookmarkList := Bookmarks;
2281 BookmarksForm.OpenBookmarkCallback := NavigateToBookmark;
2282 BookmarksForm.BookmarksChangedCallback := OnBookmarksChanged;
2283 BookmarksForm.Show;
2284
2285 // Since we are showing a nonmodal dialog, set the PM owner window
2286 // so that the bookmarks form remains on top.
2287 WinSetOwner( BookmarksForm.Frame.Handle,
2288 Frame.Handle );
2289End;
2290
2291Procedure TMainForm.CopyPMIOnClick (Sender: TObject);
2292var
2293 Window: THelpWindow;
2294Begin
2295 Window := GetActiveWindow;
2296 if Window = nil then
2297 exit;
2298 Window.View.CopySelectionToClipboard;
2299End;
2300
2301Procedure TMainForm.SelectAllPMIOnClick (Sender: TObject);
2302var
2303 Window: THelpWindow;
2304Begin
2305 Window := GetActiveWindow;
2306 if Window = nil then
2307 exit;
2308 Window.View.SelectAll;
2309End;
2310
2311Procedure TMainForm.AddNoteButtonOnClick (Sender: TObject);
2312Begin
2313 AddNote;
2314End;
2315
2316Procedure TMainForm.EnableSearchButton;
2317var
2318 CanSearch: boolean;
2319begin
2320 CanSearch := false;
2321 if CurrentOpenFiles.Count > 0 then
2322 if trim( SearchTextEdit.Text ) > '' then
2323 CanSearch := true;
2324 SearchButton.Enabled := CanSearch;
2325end;
2326
2327Procedure TMainForm.SearchTextEditOnChange (Sender: TObject);
2328Begin
2329 EnableSearchButton;
2330End;
2331
2332Procedure TMainForm.OnHint( Sender: TObject );
2333begin
2334 SetStatus( Application.Hint );
2335end;
2336
2337Procedure TMainForm.DisplaySelectedIndexTopic;
2338var
2339 Topic: TTopic;
2340Begin
2341 if IndexListBox.ItemIndex = -1 then
2342 exit;
2343 Topic := DisplayedIndex.Objects[ IndexListBox.ItemIndex ] as TTopic;
2344 DisplayTopic( Topic );
2345End;
2346
2347Procedure TMainForm.IndexListBoxOnClick (Sender: TObject);
2348Begin
2349 DisplaySelectedIndexTopic;
2350End;
2351
2352Procedure TMainForm.ViewCollapseAllMIOnClick (Sender: TObject);
2353Begin
2354 DisplayContents;
2355 ContentsOutline.CollapseAll;
2356 DisplaySelectedContentsTopic;
2357End;
2358
2359Procedure TMainForm.NotesListBoxOnDblClick (Sender: TObject);
2360Begin
2361 GotoCurrentNote;
2362End;
2363
2364function TMainForm.OwnHelpMode: boolean;
2365var
2366 Filename: string;
2367 NamePart: string;
2368begin
2369 result := false;
2370 if CurrentOpenFiles.Count <> 1 then
2371 exit;
2372
2373 Filename := THelpFile( CurrentOpenFiles[ 0 ] ).Filename;
2374 NamePart := ExtractFileName( Filename );
2375 Result := StrStarts( 'newview', NamePart );
2376end;
2377
2378Procedure TMainForm.HelpMIOnClick (Sender: TObject);
2379Begin
2380 if OwnHelpMode then
2381 begin
2382 DoErrorDlg( NewViewHelpTitle,
2383 AlreadyNewviewHelp );
2384 exit;
2385 end;
2386 Application.HelpContents;
2387End;
2388
2389Procedure TMainForm.NotebookOnPageChanged (Sender: TObject);
2390var
2391 FileIndex: longint;
2392 HelpFile: THelpFile;
2393Begin
2394 EnableControls;
2395 case Notebook.PageIndex of
2396 piContents:
2397 begin
2398 // not really feasible to load contents here, as we rely
2399 // on it for many things
2400 ContentsOutline.Focus;
2401 end;
2402
2403 piIndex:
2404 begin
2405 if not IndexLoaded then
2406 begin
2407 LoadIndex;
2408 end;
2409 IndexSearchEdit.Focus;
2410 end;
2411
2412 piSearch:
2413 begin
2414 SearchButton.Focus;
2415 SearchTextEdit.Focus;
2416 end;
2417
2418 piNotes:
2419 begin
2420 for FileIndex := 0 to CurrentOpenFiles.Count - 1 do
2421 begin
2422 HelpFile := CurrentOpenFiles[ FileIndex ];
2423 if not HelpFile.NotesLoaded then
2424 LoadNotes( HelpFile );
2425 end;
2426 NotesListBox.Focus;
2427 UpdateNotesDisplay;
2428 end;
2429 end;
2430
2431End;
2432
2433Procedure TMainForm.ViewRefreshMIOnClick (Sender: TObject);
2434Begin
2435 RefreshWindows( Windows );
2436End;
2437
2438Procedure TMainForm.ViewNotesMIOnClick (Sender: TObject);
2439Begin
2440 ShowLeftPanel := true;
2441 TabSet.TabIndex := piNotes;
2442End;
2443
2444Procedure TMainForm.ViewSearchMIOnClick (Sender: TObject);
2445Begin
2446 DisplaySearch;
2447End;
2448
2449Procedure TMainForm.ShowTab( TabIndex: longint );
2450Begin
2451 ShowLeftPanel := true;
2452 TabSet.TabIndex := TabIndex;
2453 NotebookOnPageChanged( self );// focus control etc
2454End;
2455
2456Procedure TMainForm.DisplaySearch;
2457Begin
2458 ShowTab( piSearch );
2459End;
2460
2461Procedure TMainForm.ViewIndexMIOnClick (Sender: TObject);
2462Begin
2463 DisplayIndex;
2464End;
2465
2466Procedure TMainForm.DisplayIndex;
2467Begin
2468 ShowTab( piIndex );
2469End;
2470
2471Procedure TMainForm.ViewContentsMIOnClick (Sender: TObject);
2472Begin
2473 DisplayContents;
2474End;
2475
2476Procedure TMainForm.DisplayContents;
2477Begin
2478 ShowTab( piContents );
2479End;
2480
2481function TMainForm.OpenWindow( Topic: TTopic;
2482 Group: longint;
2483 Parent: THelpWindow;
2484 Rect: THelpWindowRect;
2485 FollowAutoLinks: boolean ): THelpWindow;
2486var
2487 Window: THelpWindow;
2488 DisplayTopicRequired: boolean;
2489begin
2490 Window := nil;
2491
2492 if ( Group <> DefaultGroupIndex ) and ( Parent = nil ) then
2493 begin
2494 // Normal window (not a split window) and a specific group is desired.
2495 // So see if we can find one with that group number
2496 Window := FindWindowFromGroup( Group, Windows );
2497
2498 end
2499 else
2500 begin
2501 // only reuse window if it has the same topic.
2502 Window := FindWindowFromTopic( Topic, Windows );
2503 end;
2504
2505 if Window = nil then
2506 begin
2507 DisplayingTopicWindow := true;
2508
2509 // not found, or want a new one
2510 Window := THelpWindow.Create( Parent = nil );
2511
2512 // add to parent
2513 if Parent = nil then
2514 begin
2515 Window.Parent := DisplayPanel;
2516 Windows.Add( Window );
2517 end
2518 else
2519 begin
2520 Window.Parent := Parent.View;
2521 Parent.ChildWindows.Add( Window );
2522 end;
2523
2524 Window.ParentHelpWindow := Parent;
2525
2526 DisplayingTopicWindow := false;
2527
2528 end
2529 else
2530 begin
2531 // reusing an existing window. Don't change parent
2532 end;
2533
2534 Window.Group := Group;
2535
2536 Window.View.PopupMenu := ViewPopupMenu;
2537
2538 Window.View.Images := Window.Images;
2539
2540 Window.View.OnClickLink := OnClickLink;
2541 Window.View.OnOverLink := OnOverLink;
2542 Window.View.OnNotOverLink := OnNotOverLink;
2543
2544 Window.OnClose := OnWindowClose;
2545 Window.OnCloseQuery := OnWindowAboutToClose;
2546 Window.OnDragOver := OnDragOverWindow;
2547 Window.OnDragDrop := OnDragDropToWindow;
2548 Window.OnFontChange := OnWindowFontChange;
2549 Window.OnTab := OnWindowTab;
2550 Window.OnBackTab := OnWindowBackTab;
2551
2552 // Use the contents rect by default...
2553 Topic.GetContentsWindowRect( Window.Rect );
2554 if Rect <> nil then
2555 begin
2556 // the rect is being overridden, so use it instead
2557 if Rect.Left <> -1 then
2558 Window.Rect.Left := Rect.Left;
2559 if Rect.Bottom <> -1 then
2560 Window.Rect.Bottom := Rect.Bottom;
2561 if Rect.Width <> -1 then
2562 Window.Rect.Width := Rect.Width;
2563 if Rect.Height <> -1 then
2564 Window.Rect.Height := Rect.Height;
2565 end;
2566
2567 if Window.ChildWindows.Count > 0 then
2568 begin
2569 // close existing child windows
2570 DestroyListObjects( Window.ChildWindows );
2571 Window.ChildWindows.Clear;
2572 Window.View.Show; // show the view again
2573 end;
2574
2575 DisplayTopicRequired := Window.Topic <> Topic;
2576 Window.Topic := Topic; // set this now so that SetLayout can log meaninful stuff
2577
2578 // Adjust the window size to it's specified Rect
2579 // Must do this before displaying child windows (DisplayTopicInWindow,
2580 // split window autolinks),
2581 // otherwise they will not size themselves correctly
2582 Window.SetLayout;
2583
2584 if DisplayTopicRequired then
2585 begin
2586 DisplayTopicInWindow( Window, FollowAutoLinks, false );
2587 end;
2588
2589 // Bring this window to the front
2590 Window.BringToFront;
2591
2592 Result := Window;
2593end;
2594
2595// Find an existing help window containing the given richtext view control
2596Function TMainForm.FindWindowFromView( View: TRichTextView;
2597 WindowList: TList ): THelpWindow;
2598var
2599 WindowIndex: longint;
2600begin
2601 for WindowIndex:= 0 to WindowList.Count - 1 do
2602 begin
2603 Result:= WindowList[ WindowIndex ];
2604 if Result.View = View then
2605 exit;
2606 Result:= FindWindowFromView( View, Result.ChildWindows );
2607 if Result <> nil then
2608 exit;
2609 end;
2610 Result:= nil;
2611end;
2612
2613// Find an existing help window with the given group number (if any)
2614Function TMainForm.FindWindowFromGroup( Group: longint; WindowList: TList ): THelpWindow;
2615var
2616 WindowIndex: longint;
2617begin
2618 for WindowIndex:= 0 to WindowList.Count - 1 do
2619 begin
2620 Result:= WindowList[ WindowIndex ];
2621 if Result.Group = Group then
2622 exit;
2623 Result:= FindWindowFromGroup( Group, Result.ChildWindows );
2624 if Result <> nil then
2625 exit;
2626 end;
2627 Result:= nil;
2628end;
2629
2630// Find an existing help window alreadying displaying the given topic
2631Function TMainForm.FindWindowFromTopic( Topic: TTopic; WindowList: TList ): THelpWindow;
2632var
2633 WindowIndex: longint;
2634begin
2635 for WindowIndex:= 0 to WindowList.Count - 1 do
2636 begin
2637 Result:= WindowList[ WindowIndex ];
2638 if Result.Topic = Topic then
2639 exit;
2640 Result:= FindWindowFromTopic( Topic, Result.ChildWindows );
2641 if Result <> nil then
2642 exit;
2643 end;
2644 Result:= nil;
2645end;
2646
2647Procedure TMainForm.RefreshFontSubstitutions;
2648var
2649 FileIndex: longint;
2650 HelpFile: THelpFile;
2651begin
2652 for FileIndex := 0 to CurrentOpenFiles.Count - 1 do
2653 begin
2654 HelpFile := CurrentOpenFiles[ FileIndex ];
2655
2656 if Settings.FixedFontSubstitution then
2657 HelpFile.SetupFontSubstitutes( Settings.FixedFontSubstitutes )
2658 else
2659 HelpFile.SetupFontSubstitutes( '' );
2660 end;
2661end;
2662
2663// Redisplay topics in all windows
2664Procedure TMainForm.RefreshWindows( WindowList: TList );
2665var
2666 WindowIndex: longint;
2667 Window: THelpWindow;
2668begin
2669 for WindowIndex:= 0 to WindowList.Count - 1 do
2670 begin
2671 Window:= WindowList[ WindowIndex ];
2672 DisplayTopicInWindow( Window,
2673 false, // don't follow links!
2674 true ); // keep position
2675 RefreshWindows( Window.ChildWindows );
2676 end;
2677end;
2678
2679Procedure TMainForm.WMFollowExternalLink( Var Msg: TMessage );
2680var
2681 FilePath: string;
2682 Topic: TTopic;
2683begin
2684 // try in same dir as source file
2685 FilePath := AddSlash( ExtractFilePath( g_ExternalLinkSourceFilename ) )
2686 + g_ExternalLinkFilename;
2687
2688 if not StringsSame( FilePath, g_ExternalLinkSourceFilename ) then
2689 begin
2690 // different file - try and open it
2691 if not FileExists( FilePath ) then
2692 // not in same directory, find in help paths
2693 FilePath := FindHelpFile( g_ExternalLinkFilename );
2694
2695 if not FileExists( FilePath ) then
2696 begin
2697 DoErrorDlg( 'Link Error',
2698 'Cannot find linked file '
2699 + g_ExternalLinkFilename );
2700 exit;
2701 end;
2702
2703 if g_ExternalLinkKeepCurrent then
2704 begin
2705 if not OpenAdditionalFile( FilePath, false ) then
2706 exit;
2707 end
2708 else
2709 begin
2710 if not OpenFile( FilePath, '', false ) then
2711 exit;
2712 end;
2713
2714 end;
2715
2716 if g_ExternalLinkTopic = '' then
2717 begin
2718 // specific topic not required.
2719 DisplaySelectedContentsTopic;
2720 exit;
2721 end;
2722
2723 Topic := FindTopicByGlobalName( g_ExternalLinkTopic );
2724 if Topic = nil then
2725 begin
2726 DoErrorDlg( 'Link Error',
2727 'Unable to find topic with global name '
2728 + g_ExternalLinkTopic );
2729 exit;
2730 end;
2731
2732 DisplayTopic( Topic );
2733end;
2734
2735// We are following a link, specified as param1 in msg
2736Procedure TMainForm.WMFollowLink( Var Msg: TMessage );
2737var
2738 NewTopic: TTopic;
2739 Link: THelpLink;
2740 SourceWindow: THelpWindow;
2741begin
2742 Link:= THelpLink( Msg.Param1 );
2743 SourceWindow:= THelpWindow( Msg.Param2 );
2744 NewTopic:= FindTopicForLink( Link );
2745
2746 // remove the link target info from status
2747 SetStatus( '' );
2748
2749 if NewTopic = nil then
2750 begin
2751 // Linked topic not found, this is an error... which kind?
2752
2753 if Link is THelpLinkByResourceID then
2754 begin
2755 // may happen if e.g. PM4.INF is loaded by itself,
2756 // and a link references a resource ID from e.g PM2.INF
2757 DoErrorDlg( InvalidLinkErrorTitle,
2758 InvalidResourceIDLinkErrorA
2759 + IntToStr( THelpLinkByResourceID( Link ).ResourceID )
2760 + InvalidResourceIDLinkErrorB );
2761 end
2762 else
2763 begin
2764 // should never happen, given valid help files
2765 DoErrorDlg( InvalidLinkErrorTitle,
2766 InvalidLinkError );
2767 end;
2768
2769 exit;
2770 end;
2771
2772 UpdateCurrentNavigatePoint;
2773
2774 FollowLink( Link, SourceWindow );
2775
2776 if NewTopic.ShowInContents then
2777 begin
2778 Navigating:= true;
2779 if ContentsOutline.SelectedNode = nil then
2780 ContentsOutline.SetSelectedObject( NewTopic )
2781 else if ContentsOutline.SelectedNode.Data <> NewTopic then
2782 ContentsOutline.SetSelectedObject( NewTopic );
2783 Navigating:= false;
2784 end;
2785 SaveNavigatePoint;
2786 EnableControls;
2787 ShowWindows;
2788
2789end;
2790
2791// Follow the given link from the given window.
2792// ie. open the topic or footnote it points to
2793Procedure TMainForm.FollowLink( Link: THelpLink;
2794 SourceWindow: THelpWindow );
2795var
2796 LinkedTopic: TTopic;
2797 ParentWindow: THelpWindow;
2798 WindowedLink: TWindowedHelpLink;
2799 NewWindow: THelpWIndow;
2800begin
2801 LinkedTopic := FindTopicForLink( Link );
2802
2803 if LinkedTopic = nil then
2804 begin
2805 exit;
2806 end;
2807
2808 if Link is TFootnoteHelpLink then
2809 begin
2810 NewWindow := OpenWindow( LinkedTopic,
2811 DefaultGroupIndex,
2812 nil, // no parent
2813 FootnoteRect,
2814 true );
2815 NewWindow.Caption := TFootnoteHelpLink( Link ).Title;
2816 exit;
2817 end;
2818
2819 WindowedLink := Link as TWindowedHelpLink;
2820
2821 ParentWindow:= nil;
2822 if WindowedLink.Split then
2823 ParentWindow:= SourceWindow;
2824
2825 if WindowedLink.ViewPort then
2826 // link always wants a new window
2827 OpenWindow( LinkedTopic,
2828 DefaultGroupIndex,
2829 ParentWindow,
2830 WindowedLink.Rect,
2831 true )
2832
2833 else if WindowedLink.GroupIndex <> DefaultGroupIndex then
2834 // link overrides group index
2835 OpenWindow( LinkedTopic,
2836 WindowedLink.GroupIndex,
2837 ParentWindow,
2838 WindowedLink.Rect,
2839 true )
2840 else
2841 // no special case
2842 OpenWindow( LinkedTopic,
2843 LinkedTopic.ContentsGroupIndex,
2844 ParentWindow,
2845 WindowedLink.Rect,
2846 true );
2847end;
2848
2849function TMainForm.ShowCodes: boolean;
2850begin
2851 if DebugShowCodesMI = nil then
2852 result := false
2853 else
2854 result := DebugShowCodesMI.Checked;
2855end;
2856
2857function TMainForm.ShowWordIndices: boolean;
2858begin
2859 if DebugShowWordSeparatorsMI = nil then
2860 result := false
2861 else
2862 result := DebugShowWordSeparatorsMI.Checked;
2863end;
2864
2865// Decode and display the topic for the given window.
2866Procedure TMainForm.DisplayTopicInWindow( Window: THelpWindow;
2867 FollowAutoLinks: boolean;
2868 KeepPosition: boolean );
2869var
2870 ImageIndices: TList;
2871 LinkIndex: longint;
2872 Link: THelpLink;
2873 WindowedHelpLink: TWindowedHelpLink;
2874 InternalHelpLink: TInternalHelpLink;
2875 HelpFile: THelpFile;
2876 LinkedTopic: TTopic;
2877 SourceTopic: TTopic;
2878 TopCharIndex: longint;
2879 i: longint;
2880 HighlightWordSequences: TList;
2881 FileIndex: longint;
2882Begin
2883 LogEvent(LogDisplay, 'DisplayTopicInWindow');
2884
2885 SetWaitCursor;
2886
2887 TopCharIndex := Window.View.TopCharIndex;
2888
2889 Window.View.Hide;
2890 Window.View.Clear;
2891 ImageIndices := TList.Create;
2892
2893 HelpFile := TopicFile( Window.Topic );
2894
2895 if ( AllFilesWordSequences.Count > 0 ) // ie we have done a search...
2896 and ViewHighlightSearchWordsMI.Checked then
2897 begin
2898 FileIndex := CurrentOpenFiles.IndexOf( HelpFile );
2899 HighlightWordSequences := AllFilesWordSequences[ FileIndex ];
2900 end
2901 else
2902 begin
2903 HighlightWordSequences := nil;
2904 end;
2905 TopicText.Clear;
2906 Window.Topic.GetText( HighlightWordSequences,
2907 ShowCodes,
2908 ShowWordIndices,
2909 TopicText,
2910 ImageIndices,
2911 Window.Highlights );
2912
2913 HelpFile.GetImages( ImageIndices, Window.Images );
2914
2915 if not HelpFile.NotesLoaded then
2916 LoadNotes( HelpFile );
2917 InsertNotesIntoTopicText( Window.Topic, TopicText );
2918
2919 Window.View.AddText( TopicText.AsPChar );
2920
2921 if KeepPosition then
2922 Window.View.TopCharIndex := TopCharIndex;
2923
2924 Window.View.Show;
2925
2926 if not KeepPosition then
2927 if Window.Highlights.Count > 0 then
2928 // ensure first search match is visible
2929 Window.View.MakeCharVisible( longint( Window.Highlights[ 0 ] ) );
2930
2931 Window.Caption := Window.Topic.Title;
2932 Window.BringToFront;
2933 Window.View.Focus;
2934
2935 // Take a copy of the topic, because the window in question could be changing
2936 // due to recursion!
2937 SourceTopic := Window.Topic;
2938
2939 if FollowAutoLinks then
2940 begin
2941 i := 0;
2942 for LinkIndex:= 0 to SourceTopic.Links.Count - 1 do
2943 begin
2944 Link:= SourceTopic.Links[ LinkIndex ];
2945 if Link is TWindowedHelpLink then
2946 begin
2947 WindowedHelpLink := Link as TWindowedHelpLink;
2948 if WindowedHelpLink.Automatic then
2949 begin
2950 if Link is TInternalHelpLink then
2951 begin
2952 InternalHelpLink := TInternalHelpLink( Link );
2953 LinkedTopic :=
2954 THelpFile( InternalHelpLink.HelpFile ).
2955 Topics[ InternalHelpLink.TopicIndex ];
2956 if LinkedTopic.Index = SourceTopic.Index then
2957 // what the - ? The link wants to open the same topic again
2958 continue;
2959 end;
2960
2961 FollowLink( Link, Window );
2962 Window := Window;
2963
2964 inc( i );
2965 // Note 1: it is possible to crash here if
2966 // e.g. window1 auto-opens window2 which auto-opens window1 with a different topic..
2967 // I can't think of a nice, easy way to detect this
2968 //
2969 // Note 2: If there is no group number specified
2970 // (ie. group = default = 0 ) then behaves as if viewport is set:
2971 // always opens another window.
2972 end;
2973 end;
2974 end;
2975 end;
2976
2977 ClearWaitCursor;
2978
2979 ImageIndices.Destroy;
2980End;
2981
2982Procedure TMainForm.MainFormOnCloseQuery (Sender: TObject;
2983 Var CanClose: Boolean);
2984Begin
2985 LogEvent(LogShutdown, '-------- Shutdown ----------');
2986
2987
2988 if OKToCloseFile then
2989 CloseFile
2990 else
2991 CanClose := false;
2992End;
2993
2994procedure TMainForm.DisplayTopic( Topic: TTopic );
2995begin
2996 if Navigating then
2997 exit;
2998
2999 UpdateCurrentNavigatePoint;
3000
3001 CloseWindows;
3002
3003 CurrentTopic:= Topic;
3004
3005 OpenWindow( CurrentTopic,
3006 CurrentTopic.ContentsGroupIndex,
3007 nil,
3008 nil,
3009 true );
3010 SetStatus( OpenedTopicMsg
3011 + IntToStr( Topic.Index ) );
3012
3013 Navigating:= true;
3014
3015 if ContentsOutline.SelectedNode = nil then
3016 ContentsOutline.SetSelectedObject( Topic )
3017 else if ContentsOutline.SelectedNode.Data <> Topic then
3018 ContentsOutline.SetSelectedObject( Topic );
3019
3020 SaveNavigatePoint;
3021
3022 Navigating:= false;
3023 // find in index...
3024 // find in search results...
3025
3026 EnableControls;
3027
3028 ShowWindows;
3029
3030// if Windows.Count > 0 then
3031// THelpWindow( Windows[ 0 ] ).View.Focus;
3032
3033end;
3034
3035// Make the all current help windows visible
3036Procedure TMainForm.ShowWindows;
3037begin
3038 ShowWindowList( Windows );
3039end;
3040
3041// Make the specified windows visible
3042Procedure TMainForm.ShowWindowList( WindowList: TList );
3043var
3044 i: integer;
3045 Window: THelpWindow;
3046begin
3047 for i := 0 to WindowList.Count - 1 do
3048 begin
3049 Window:= WindowList[ i ];
3050 Window.Show;
3051 ShowWindowList( Window.ChildWindows );
3052 end;
3053end;
3054
3055// Global search -----------------------------------------------------------
3056
3057Procedure TMainForm.GlobalSearchMIOnClick (Sender: TObject);
3058begin
3059 DoGlobalSearch( '' );
3060end;
3061
3062Procedure TMainForm.DoGlobalSearch( const SearchText: string );
3063Begin
3064 EnsureGlobalSearchFormLoaded;
3065
3066 GlobalSearchForm.ViewTopicCallback:= OnViewGlobalSearchTopic;
3067 GlobalSearchForm.Show;
3068 WinSetOwner( GlobalSearchForm.Frame.Handle, Frame.Handle );
3069
3070 if SearchText <> '' then
3071 begin
3072 GlobalSearchForm.SearchTextEdit.Text := SearchText;
3073 GlobalSearchForm.DoSearch;
3074 end;
3075End;
3076
3077Procedure TMainForm.OnViewGlobalSearchTopic( FileName: string;
3078 TopicIndex: longint );
3079var
3080 HelpFile: THelpFile;
3081begin
3082 HelpFile:= FindOpenHelpFile( FileName );
3083
3084 if HelpFile = nil then
3085 begin
3086 if OpenFile( Filename, '', false ) then
3087 begin
3088 HelpFile := CurrentOpenFiles[ 0 ];
3089 ClearHelpManager;
3090 end;
3091 end;
3092
3093 if HelpFile <> nil then
3094 if TopicIndex <> -1 then
3095 DisplayTopic( HelpFile.Topics[ TopicIndex ] );
3096
3097end;
3098
3099// Notes -----------------------------------------------------------
3100
3101Procedure TMainForm.GotoNoteButtonOnClick (Sender: TObject);
3102begin
3103 GotoCurrentNote;
3104end;
3105
3106Procedure TMainForm.EditNoteButtonOnClick (Sender: TObject);
3107Begin
3108 if NotesListBox.ItemIndex = -1 then
3109 exit;
3110 EditNote( NotesListBox.ItemIndex );
3111End;
3112
3113Procedure TMainForm.NotesListBoxOnItemFocus (Sender: TObject; Index: LongInt);
3114var
3115 Note: THelpNote;
3116Begin
3117 Note:= NotesListBox.Items.Objects[ NotesListBox.ItemIndex ] as THelpNote;
3118 EnableNotesControls;
3119End;
3120
3121Procedure TMainForm.DeleteNoteButtonOnClick (Sender: TObject);
3122Begin
3123 if NotesListBox.ItemIndex = -1 then
3124 exit;
3125 DeleteNote( NotesListBox.ItemIndex );
3126End;
3127
3128Procedure TMainForm.AddBookmarkMIOnClick (Sender: TObject);
3129Begin
3130 AddBookmark;
3131End;
3132
3133Procedure TMainForm.AddNoteMIOnClick (Sender: TObject);
3134Begin
3135 AddNote;
3136End;
3137
3138// -----------------------------------------------------------
3139
3140Procedure TMainForm.FileCloseMIOnClick (Sender: TObject);
3141Begin
3142 if not OKToCloseFile then
3143 exit;
3144
3145 CloseFile;
3146End;
3147
3148Procedure TMainForm.SetStatus( Text: String );
3149begin
3150 StatusPanel.Caption:= Text;
3151 StatusPanel.Refresh;
3152end;
3153
3154Procedure TMainForm.ResetProgress;
3155begin
3156 ProgressBar.Position:= 0;
3157 ProgressBar.Hide;
3158end;
3159
3160Procedure TMainForm.CoolBarOnSectionResize (HeaderControl: THeaderControl;
3161 section: THeaderSection);
3162Begin
3163
3164End;
3165
3166Procedure TMainForm.CoolBarOnSectionClick (HeaderControl: THeaderControl;
3167 section: THeaderSection);
3168Begin
3169 case Section.Index of
3170 ciOpen:
3171 FileOpen;
3172 ciBack:
3173 NavigateBack;
3174 ciForward:
3175 NavigateForward;
3176 ciPrint:
3177 PrintTopics;
3178 ciAddNote:
3179 AddNote;
3180 ciAddBookmark:
3181 AddBookmark;
3182 ciPrevious:
3183 NavigatePreviousInContents;
3184 ciNext:
3185 NavigateNextInContents;
3186 ciGlobalSearch:
3187 DoGlobalSearch( '' );
3188 end;
3189
3190End;
3191
3192// ---------------- Notes ----------------------
3193
3194function TMainForm.FindOriginalNoteCharIndex( NoteCharIndex: longword;
3195 Topic: TTopic ): longword;
3196var
3197 NoteIndex: longint;
3198 Note: THelpNote;
3199begin
3200 Result := NoteCharIndex;
3201 for NoteIndex := 0 to Notes.Count - 1 do
3202 begin
3203 Note := Notes[ NoteIndex ];
3204 if Note.Topic = Topic then
3205 if Note.InsertPoint < NoteCharIndex then
3206 dec( Result, Note.InsertText.Length );
3207 end;
3208end;
3209
3210function TMainForm.FindActualNoteCharIndex( NoteCharIndex: longword;
3211 MaxNoteIndex: longword;
3212 Topic: TTopic ): longword;
3213var
3214 NoteIndex: longint;
3215 Note: THelpNote;
3216begin
3217 NoteIndex:= 0;
3218 Result:= NoteCharIndex;
3219 for NoteIndex:= 0 to MaxNoteIndex - 1 do
3220 begin
3221 Note:= Notes[ NoteIndex ];
3222 if Note.Topic = Topic then
3223 if Note.InsertPoint < NoteCharIndex then
3224 inc( Result, Note.InsertText.Length );
3225 end;
3226end;
3227
3228procedure TMainForm.RefreshNoteInsertInfo( NoteIndex: longword );
3229var
3230 Note: THelpNote;
3231begin
3232 Note:= Notes[ NoteIndex ];
3233
3234 if Note.Topic = nil then
3235 exit;
3236 with Note do
3237 begin
3238 InsertText.AssignString( '<color #'
3239 + IntToHex( Settings.Colors[ NotesTextColorIndex ], 6 )
3240 + '><link note'
3241 + IntToStr( NoteIndex )
3242 + '>' );
3243 InsertText.Add( Text );
3244 InsertText.AddString( '</color></link>' );
3245 end;
3246end;
3247
3248procedure TMainForm.ClearNotes;
3249begin
3250 DestroyListObjects( Notes );
3251 Notes.Clear;
3252end;
3253
3254procedure TMainForm.AddNote;
3255var
3256 Note: THelpNote;
3257 Window: THelpWindow;
3258begin
3259 Window := GetActiveWindow;
3260 if Window = nil then
3261 begin
3262 DoErrorDlg( AddNoteTitle,
3263 AddNoteCursorError );
3264 exit;
3265 end;
3266
3267 if Window.View.CursorIndex = -1 then
3268 begin
3269 DoErrorDlg( AddNoteTitle,
3270 AddNoteCursorError );
3271 exit;
3272 end;
3273
3274 // check that the note position isn't
3275 // within a note already
3276 if Window.View.LinkFromIndex( Window.View.CursorIndex ) <> '' then
3277 begin
3278 DoErrorDlg( AddNoteTitle,
3279 NoteWithinNoteError );
3280 exit;
3281 end;
3282
3283 // ask for note text
3284 NoteForm.DeleteNoteButton.Enabled := false; // can't delete it while creating!
3285 NoteForm.Text.Clear;
3286 if NoteForm.ShowModal <> mrOK then
3287 exit;
3288
3289 // store note data
3290 Note := THelpNote.Create;
3291 Note.Text.Assign( NoteForm.Text );
3292
3293 // compensate for existing notes
3294 if Window.View.CursorIndex <> -1 then
3295 Note.InsertPoint := FindOriginalNoteCharIndex( Window.View.CursorIndex, Window.Topic )
3296 else
3297 Note.InsertPoint := 0;
3298
3299 Note.Topic := Window.Topic;
3300
3301 Notes.Add( Note );
3302
3303 // redisplay topic
3304 DisplayTopicInWindow( Window,
3305 false, // don't follow links!
3306 true ); // keep position
3307 Window.View.SelectionStart := FindActualNoteCharIndex( Note.InsertPoint,
3308 Notes.Count - 1,
3309 Window.Topic );
3310 UpdateNotesDisplay;
3311
3312 SaveNotes;
3313
3314end;
3315
3316procedure TMainForm.DeleteNote( NoteIndex: longint );
3317var
3318 Note: THelpNote;
3319begin
3320 Note := Notes[ NoteIndex ];
3321 Notes.Delete( NoteIndex );
3322
3323 RefreshWindows( Windows );
3324
3325 Note.Destroy;
3326
3327 UpdateNotesDisplay;
3328
3329 SaveNotes;
3330end;
3331
3332Procedure TMainForm.EditNote( NoteIndex: longint );
3333var
3334 Note: THelpNote;
3335begin
3336 Note:= Notes[ NoteIndex ];
3337
3338 NoteForm.Text.Assign( Note.Text );
3339
3340 NoteForm.DeleteNoteButton.Enabled:= true;
3341
3342 if NoteForm.ShowModal = mrCancel then
3343 exit;
3344
3345 if NoteForm.ModalResult = cmDiscard then
3346 begin
3347 DeleteNote( NoteIndex );
3348 exit;
3349 end;
3350
3351 Note.Text.Assign( NoteForm.Text );
3352
3353 RefreshWindows( Windows );
3354
3355 UpdateNotesDisplay;
3356
3357 SaveNotes;
3358end;
3359
3360Procedure TMainForm.GotoCurrentNote;
3361var
3362 Note: THelpNote;
3363Begin
3364 if NotesListBox.ItemIndex = -1 then
3365 exit;
3366 Note:= NotesListBox.Items.Objects[ NotesListBox.ItemIndex ] as THelpNote;
3367 DisplayTopic( Note.Topic );
3368End;
3369
3370// ---------------- Bookmarks ----------------------
3371
3372procedure TMainForm.OnBookmarksChanged( Sender: TObject );
3373begin
3374 BuildBookmarksMenu;
3375 UpdateBookmarksForm;
3376 SaveBookmarks;
3377end;
3378
3379procedure TMainForm.AddBookmark;
3380var
3381 Bookmark: TBookmark;
3382begin
3383 if Windows.Count = 0 then
3384 exit;
3385
3386 Bookmark := TBookmark.Create;
3387 SaveWindows( Windows, Bookmark.Windows, nil );
3388
3389 if ContentsOutline.SelectedNode <> nil then
3390 begin
3391 Bookmark.ContentsTopic:=
3392 ContentsOutline.SelectedNode.Data as TTopic;
3393 Bookmark.Name := Bookmark.ContentsTopic.Title;
3394 end
3395 else
3396 begin
3397 Bookmark.ContentsTopic:= nil;
3398 // Bookmark.Name := THelpWindow( Windows[ 0 ] ).Title;
3399 end;
3400
3401 Bookmarks.Add( Bookmark );
3402 OnBookmarksChanged( self );
3403end;
3404
3405Procedure TMainForm.BookmarksMenuItemClick( Sender: TObject );
3406var
3407 Tag: longint;
3408 MenuItem: TMenuItem;
3409 Bookmark: TBookmark;
3410begin
3411 MenuItem:= Sender as TMenuItem;
3412 Tag:= MenuItem.Tag;
3413 Bookmark := Bookmarks[ Tag ];
3414
3415 NavigateToBookmark( Bookmark );
3416end;
3417
3418Procedure TMainForm.NavigateToBookmark( Bookmark: TBookmark );
3419Begin
3420 UpdateCurrentNavigatePoint;
3421 NavigateToPoint( Bookmark );
3422 SaveNavigatePoint;
3423End;
3424
3425Procedure TMainForm.BuildBookmarksMenu;
3426var
3427 i: integer;
3428 Bookmark: TBookmark;
3429 MenuItem: TMenuItem;
3430begin
3431 DestroyListObjects( BookmarksMenuItems );
3432 BookmarksMenuItems.Clear;
3433
3434 if Bookmarks.Count > 0 then
3435 begin
3436 MenuItem:= TMenuItem.Create( self );
3437 MenuItem.Caption:= '-';
3438 BookmarksMenu.Add( MenuItem );
3439 BookmarksMenuItems.Add( MenuItem );
3440 end;
3441
3442 for i:= 0 to Bookmarks.Count -1 do
3443 begin
3444 Bookmark := Bookmarks[ i ];
3445 MenuItem:= TMenuItem.Create( self );
3446
3447 MenuItem.Caption:= Bookmark.Name;
3448 MenuItem.OnClick:= BookmarksMenuItemClick;
3449 MenuItem.Tag:= i;
3450 BookmarksMenu.Add( MenuItem );
3451 BookmarksMenuItems.Add( MenuItem );
3452 end;
3453end;
3454
3455Procedure TMainForm.UpdateBookmarksForm;
3456begin
3457 if Assigned( BookmarksForm ) then
3458 BookmarksForm.RefreshList;
3459end;
3460
3461Procedure TMainForm.ClearBookmarks;
3462begin
3463 ClearListAndObjects( Bookmarks );
3464 BuildBookmarksMenu;
3465 if Assigned( BookmarksForm ) then
3466 begin
3467 UpdateBookmarksForm; // clear bookmarks for next show
3468 BookmarksForm.Hide;
3469 end;
3470
3471end;
3472
3473procedure TMainForm.LoadBookmarks( HelpFile: THelpFile );
3474var
3475 Bookmark: TBookmark;
3476 BookmarksFile: TextFile;
3477 BookmarksFileName: string;
3478 S: string;
3479begin
3480 LogEvent(LogSettings, 'Load bookmarks for ' + HelpFile.Filename);
3481
3482 BookmarksFileName:= ChangeFileExt( HelpFile.FileName, '.bmk' );
3483
3484 if not FileExists( BookmarksFileName ) then
3485 exit;
3486
3487 FileMode := fmInput;
3488 AssignFile( BookmarksFile, BookmarksFileName );
3489 try
3490 Reset( BookmarksFile );
3491 try
3492 while not Eof( BookmarksFile ) do
3493 begin
3494 ReadLn( BookmarksFile, s );
3495 if trim( Uppercase( s ) ) = '[BOOKMARK]' then
3496 begin
3497 Bookmark:= TBookmark.Load( BookmarksFile, HelpFile );
3498 Bookmarks.Add( Bookmark );
3499 end;
3500 end;
3501 finally
3502 System.Close( BookmarksFile );
3503 end;
3504 except
3505 on e: exception do
3506 DoErrorDlg( LoadBookmarksTitle,
3507 LoadBookmarksError
3508 + e.message );
3509 end;
3510end;
3511
3512procedure TMainForm.SaveBookmarks;
3513var
3514 FileIndex: integer;
3515 HelpFile: THelpFile;
3516begin
3517 for FileIndex := 0 to CurrentOpenFiles.Count - 1 do
3518 begin
3519 HelpFile := CurrentOpenFiles[ FileIndex ];
3520 SaveBookmarksForFile( HelpFile );
3521 end;
3522end;
3523
3524procedure TMainForm.SaveNotes;
3525var
3526 FileIndex: integer;
3527 HelpFile: THelpFile;
3528begin
3529 LogEvent(LogSettings, 'Save notes');
3530
3531 for FileIndex := 0 to CurrentOpenFiles.Count - 1 do
3532 begin
3533 HelpFile := CurrentOpenFiles[ FileIndex ];
3534 SaveNotesForFile( HelpFile );
3535 end;
3536end;
3537
3538procedure TMainForm.SaveBookmarksForFile( HelpFile: THelpFile );
3539var
3540 i: integer;
3541 Bookmark: TBookmark;
3542 BookmarksFile: TextFile;
3543 BookmarksFileName: string;
3544 BookmarkCount: integer;
3545begin
3546 LogEvent(LogSettings, 'Save bookmarks for ' + HelpFile.Filename);
3547
3548 BookmarksFileName:= ChangeFileExt( HelpFile.FileName, '.bmk' );
3549
3550 BookmarkCount:= 0;
3551 for i:= 0 to Bookmarks.Count - 1 do
3552 begin
3553 Bookmark := Bookmarks[ i ];
3554
3555 if Bookmark.ContentsTopic.HelpFile = HelpFile then
3556 inc( BookmarkCount );
3557 end;
3558
3559 if BookmarkCount = 0 then
3560 begin
3561 if FileExists( BookmarksFileName ) then
3562 DeleteFile( BookmarksFileName );
3563 exit;
3564 end;
3565
3566 AssignFile( BookmarksFile, BookmarksFileName );
3567 try
3568 Rewrite( BookmarksFile );
3569 try
3570 for i := 0 to Bookmarks.Count - 1 do
3571 begin
3572 Bookmark:= Bookmarks[ i ];
3573 if Bookmark.ContentsTopic.HelpFile = HelpFile then
3574 begin
3575 WriteLn( BookmarksFile, '[Bookmark]' );
3576 Bookmark.Save( BookmarksFile );
3577 end;
3578 end;
3579 finally
3580 System.Close( BookmarksFile );
3581 end;
3582 except
3583 on e: exception do
3584 DoErrorDlg( SaveBookmarksTitle,
3585 SaveBookmarksError
3586 + e.message );
3587 end;
3588end;
3589
3590// Reads colors back from controls, in case they have changed by
3591// drag and drop
3592Procedure TMainForm.GetColors;
3593begin
3594 with Settings do
3595 begin
3596 Colors[ ContentsBackgroundColorIndex ] := ContentsOutline.Color;
3597 Colors[ ContentsTextColorIndex ] := ContentsOutline.PenColor;
3598 Colors[ IndexBackgroundColorIndex ] := IndexListBox.Color;
3599 Colors[ IndexTextColorIndex ] := IndexListBox.PenColor;
3600 Colors[ SearchBackgroundColorIndex ] := SearchResultsListBox.Color;
3601 Colors[ SearchTextColorIndex ] := SearchResultsListBox.PenColor;
3602 Colors[ NotesListBackgroundColorIndex ] := NotesListBox.Color;
3603 Colors[ NotesListTextColorIndex ] := NotesListBox.PenColor;
3604 end;
3605end;
3606
3607Procedure TMainForm.MainFormOnDestroy (Sender: TObject);
3608Begin
3609 LogEvent(LogShutdown, 'MainFormOnDestroy');
3610
3611 LogEvent(LogSettings, 'Write window position');
3612 WriteWindowPos( self );
3613
3614 LogEvent(LogSettings, 'Update colors');
3615 GetColors;
3616
3617 LogEvent(LogSettings, 'Save settings');
3618 SaveSettings;
3619 LogEvent(LogSettings, 'Save settings done');
3620
3621 // else- don't save position/size if doing own help
3622
3623 TopicText.Destroy;
3624
3625 LogEvent(LogShutdown, 'Destroy MRU menu items');
3626 MRUMenuItems.Destroy;
3627
3628 LogEvent(LogShutdown, 'Destroy navigate to menu items');
3629 NavigateToMenuItems.Destroy;
3630
3631 LogEvent(LogShutdown, 'Destroy pagehistory');
3632 PageHistory.Destroy;
3633
3634 LogEvent(LogShutdown, 'Clear/destroy notes');
3635 ClearNotes;
3636 Notes.Destroy;
3637
3638 LogEvent(LogShutdown, 'Clear/destroy bookmarks');
3639 ClearBookmarks;
3640 Bookmarks.Destroy;
3641
3642 LogEvent(LogShutdown, 'Destroy bookmark menu items');
3643 BookmarksMenuItems.Destroy;
3644
3645 LogEvent(LogShutdown, 'Destroy files/index/windows');
3646 CurrentOpenFiles.Destroy;
3647 DisplayedIndex.Destroy;
3648 Windows.Destroy;
3649
3650 // tell help manager(s) we are stopping.
3651 PostHelpManagerMessage( NHM_FORGET_VIEWER, 0, 0 );
3652
3653 HelpManagerWindows.Destroy;
3654
3655 DestroyListObjects( Settings.MRUList );
3656 Settings.MRUList.Destroy;
3657
3658 // TODO rbri maybe we have to do this
3659 // Parameters.FilenamesParam.Destroy;
3660
3661 if g_CurrentLanguageFile <> nil then
3662 g_CurrentLanguageFile.Destroy;
3663
3664 LogEvent(LogShutdown, 'Close global filelist');
3665 GlobalFilelist.Destroy;
3666
3667 LogEvent(LogShutdown, 'Close shared memory');
3668 SharedMemory.Destroy;
3669
3670 AllFilesWordSequences.Destroy;
3671
3672 LogEvent(LogShutdown, 'MainFormOnDestroy done');
3673End;
3674
3675Procedure TMainForm.MainFormOnSetupShow (Sender: TObject);
3676Begin
3677 LogEvent(LogSettings, 'OnSetupShow');
3678 TabSet.TabIndex := 0;
3679 Notebook.PageIndex := 0;
3680End;
3681
3682Procedure TMainForm.OnException( Sender: TObject;
3683 E: Exception );
3684var
3685 TheText : string;
3686 F: TextFile;
3687 i: integer;
3688 HelpFile: THelpFile;
3689 LogFilename: string;
3690
3691begin
3692 LogFilename := GetLogFilesDir + CrashLogFileName;
3693
3694 LogException( E,
3695 LogFileName,
3696 'NewView',
3697 GetAppVersion,
3698 F );
3699
3700 if CurrentOpenFiles <> nil then
3701 begin
3702 WriteLn( F, 'Loaded files ('
3703 + IntToStr( CurrentOpenFiles.Count )
3704 + '):' );
3705 try
3706 for i := 0 to CurrentOpenFiles.Count - 1 do
3707 begin
3708 HelpFile := CurrentOpenFiles[ i ];
3709 WriteLn( F, HelpFile.Filename );
3710 end;
3711 except
3712 end;
3713 end;
3714 try
3715 if CurrentTopic <> nil then
3716 WriteLn( F, 'Last major topic index: '
3717 + IntToStr( CurrentTopic.Index ) );
3718 except
3719 // ignore exceptions if there isn't a valid current topic
3720 end;
3721 if Windows <> nil then
3722 begin
3723 WriteLn( F, 'Top-level open windows: '
3724 + IntToStr( Windows.Count ) );
3725 end;
3726
3727 System.Close( F );
3728
3729 TheText := ApplicationErrorA + EndLine
3730 + EndLine
3731 + E.Message + EndLine
3732 + ApplicationErrorB
3733 + LogFilename
3734 + ')' + EndLine
3735 + EndLine
3736 + ApplicationErrorC
3737 + EndLine;
3738
3739 if DoYesNoDlg( ApplicationErrorTitle,
3740 TheText ) then
3741 begin
3742 // exit a bit more nicely - remove ourselves from the global filelist.
3743 GlobalFilelist.RemoveWindowFiles( Frame.Handle );
3744 Application.Terminate;
3745 end;
3746end;
3747
3748// give our main window a unique class name we can find
3749procedure TMainForm.GetClassData(var ClassData: TClassData);
3750Begin
3751 inherited GetClassData( ClassData );
3752 ClassData.ClassName := MAIN_WINDOW_CLASS_NAME;
3753End;
3754
3755// Position the window offset from existing top help window (if any)
3756Procedure TMainForm.PositionWindow;
3757var
3758 hTopWindow: HWND;
3759 TopHelpWindowPos: SWP;
3760 Offset: longint;
3761Begin
3762 hTopWindow := FindTopFormWindow( MAIN_WINDOW_CLASS_NAME );
3763
3764 if hTopWindow <> NULLHANDLE then
3765 begin
3766 // found an existing help window, find it's location
3767 if WinQueryWindowPos(
3768 hTopWindow,
3769 TopHelpWindowPos ) then
3770 begin
3771 if ( TopHelpWindowPos.FL and ( SWP_MINIMIZE or SWP_MINIMIZE ) ) > 0 then
3772 Begin
3773 // window is maximized or minimised, so get the restore position from window USHORTs
3774 TopHelpWindowPos.x := WinQueryWindowUShort( hTopWindow, QWS_XRESTORE );
3775 TopHelpWindowPos.Y := WinQueryWindowUShort( hTopWindow, QWS_YRESTORE );
3776 end;
3777
3778 // offset new window by height of title bar + border
3779 Offset := Screen.SystemMetrics( smCyTitleBar )
3780 + Screen.SystemMetrics( smCySizeBorder );
3781 Left := TopHelpWindowPos.x + Offset;
3782 Bottom := TopHelpWindowPos.y - Offset;
3783
3784 // I guess I am leaving width/height out for compatibility...?
3785 end;
3786 end;
3787end;
3788
3789Procedure TMainForm.OnHelp( context: THelpContext;
3790 var Result: Boolean );
3791begin
3792 if OwnHelpMode then
3793 begin
3794 // we are viewing the help file now - display our own help!
3795 PostMsg( Handle, NHM_TOPIC_BY_RESOURCE_ID, context, 0 );
3796 exit;
3797 end;
3798
3799 Application.HelpContext( context );
3800end;
3801
3802Procedure TMainForm.MainFormOnCreate (Sender: TObject);
3803var
3804 tmpCmdLine: String;
3805Begin
3806 LogEvent(LogStartup, 'MainFormOnCreate');
3807
3808 StartingUp := true;
3809
3810 Application.HelpFile := GetOwnHelpFilename; // OWN_HELP_MARKER;
3811 Application.OnHelp := OnHelp;
3812
3813 SharedMemory := AccessSharedMemory;
3814 GlobalFilelist := TGlobalFilelist.Create;
3815
3816 // parse parameters into Parameters object
3817 tmpCmdLine := nativeOS2GetCmdLineParameter;
3818 CmdLineParameters := TCmdLineParameters.Create;
3819 CmdLineParameters.parseCmdLine(tmpCmdLine);
3820
3821 RegisterForLanguages( OnLanguageEvent );
3822
3823 // if debug is not enabled, get rid of the debug menu and separator.
3824 if GetEnv( 'NEWVIEW_DEBUG' ) = '' then
3825 begin
3826 ToolsDebugSep.Destroy;
3827 ToolsDebugMenu.Destroy;
3828 DebugShowCodesMI := nil;
3829 DebugShowWordSeparatorsMI := nil;
3830 end;
3831
3832 // set up globals for Exec
3833 ExecViaSession := true;
3834 AsynchExec := true;
3835
3836 // set up form icons
3837 Forms.FormIconResourceID := 1;
3838
3839 Application.OnException := OnException;
3840
3841 ContentsOutline.SmoothScroll := false;
3842
3843 LogEvent(LogStartup, 'Choosing default font: Trying WarpSans');
3844
3845 Font := GetNiceDefaultFont;
3846
3847 // Set the menu fonts, because they remember their own specific one
3848 MainMenu.Font := Screen.MenuFont;
3849 ViewPopupMenu.Font := Screen.MenuFont;
3850
3851 // NOTE: SPCC will copy this font to TApplication
3852 // in TApplication.Run
3853
3854 LogEvent(LogStartup, 'Starting NewView: MainFormOnCreate');
3855
3856 Application.OnHint := OnHint;
3857
3858 StartMem := MemAvailBytes;
3859
3860 DisplayedIndex := TStringList.Create;
3861
3862 HelpManagerWindows := TList.Create;
3863
3864 AllFilesWordSequences := TList.Create;
3865
3866 CurrentOpenFiles := TList.Create;
3867 Notes := TList.Create;
3868 Bookmarks := TList.Create;
3869 BookmarksMenuItems := TList.Create;
3870 Windows := TList.Create;
3871
3872 TopicText := TAString.Create;
3873
3874 Navigating := false;
3875 InIndexSearch := false;
3876 SettingFont := false;
3877
3878 PageHistory := TStringList.Create;
3879 CurrentHistoryIndex := -1;
3880
3881 Settings.MRUList := TList.Create;
3882
3883 MRUMenuItems := TList.Create;
3884 NavigateToMenuItems := TList.Create;
3885
3886 LogEvent(LogSettings, 'Loading settings');
3887
3888 LoadSettings;
3889 SetShowLeftPanel( ShowLeftPanel ); // update menu
3890
3891 // load default strings
3892 LogEvent(LogSettings, 'Loading language');
3893
3894 if CmdLineParameters.getLanguage <> '' then
3895 LoadAutoLanguage( 'newview', CmdLineParameters.getLanguage )
3896 else
3897 LoadDefaultLanguage( 'newview' );
3898
3899 LogEvent(LogSettings, 'Applying settings');
3900 ApplySettings;
3901
3902 // default position is centered..
3903 LogEvent(LogSettings, 'Set default position');
3904 if Width > Screen.Width then
3905 Width := Screen.Width;
3906 if Height > Screen.Height then
3907 Height := Screen.Height;
3908 Left := ( Screen.Width - Width ) div 2;
3909 Bottom := ( Screen.Height - Height ) div 2;
3910
3911 LogEvent(LogSettings, 'ReadWindowPos');
3912 ReadWindowPos( Self );
3913
3914 PositionWindow;
3915
3916 LogEvent(LogSettings, 'Creating MRU list');
3917
3918 CreateMRUMenuItems;
3919
3920 CloseFile;
3921
3922 LogEvent(LogStartup, 'OnCreate done');
3923
3924 if CmdLineParameters.getWindowPositionFlag then
3925 begin
3926 SmartSetWindowPos( self,
3927 CmdLineParameters.getWindowPosition.Left,
3928 CmdLineParameters.getWindowPosition.Bottom,
3929 CmdLineParameters.getWindowPosition.Width,
3930 CmdLineParameters.getWindowPosition.Height,
3931 false );
3932 end;
3933
3934 LogEvent(LogStartup, 'MainFormOnCreate Done');
3935End;
3936
3937Procedure TMainForm.ApplySettings;
3938var
3939 ToolbarBitmap: TBitmap;
3940begin
3941 ContentsOutline.Color:= Settings.Colors[ ContentsBackgroundColorIndex ];
3942 ContentsOutline.PenColor:= Settings.Colors[ ContentsTextColorIndex ];
3943 ContentsOutline.TreeLineColor:= Settings.Colors[ ContentsLinesColorIndex ];
3944 IndexListBox.Color:= Settings.Colors[ IndexBackgroundColorIndex ];
3945 IndexListBox.PenColor:= Settings.Colors[ IndexTextColorIndex ];
3946 SearchResultsListBox.Color:= Settings.Colors[ SearchBackgroundColorIndex ];
3947 SearchResultsListBox.PenColor:= Settings.Colors[ SearchTextColorIndex ];
3948 NotesListBox.Color:= Settings.Colors[ NotesListBackgroundColorIndex ];
3949 NotesListBox.PenColor:= Settings.Colors[ NotesListTextColorIndex ];
3950
3951 SettingFont := true;
3952 Notebook.ParentFont := true;
3953 ContentsOutline.ParentFont := true;
3954 IndexListBox.ParentFont := true;
3955 SearchResultsListBox.ParentFont := true;
3956 NotesListBox.ParentFont := true;
3957 TabSet.ParentFont := true;
3958 Coolbar.ParentFont := true;
3959 if Settings.Fonts[ ApplicationFontIndex ] <> nil then
3960 Font := Settings.Fonts[ ApplicationFontIndex ]
3961 else
3962 Font := GetNiceDefaultFont;
3963 SettingFont := false;
3964
3965 Coolbar.BackgroundBitmap := nil;
3966 if FileExists( Settings.ToolbarBackgroundImageFilename ) then
3967 begin
3968 ToolbarBitmap:= TBitmap.Create;
3969 try
3970 ToolbarBitmap.LoadFromFIle( Settings.ToolbarBackgroundImageFilename );
3971 Coolbar.BackgroundBitmap := ToolbarBitmap;
3972 except
3973 end;
3974 ToolbarBitmap.Destroy;
3975 end;
3976
3977 CoolBar.ShowImages := Settings.ToolbarStyle in [ tsImages, tsImagesAndText ];
3978 CoolBar.ShowText := Settings.ToolbarStyle in [ tsText, tsImagesAndText ];
3979
3980 CoolBar.SetMinConstButtonWidth;
3981
3982 DisplayPanel.Color := Settings.Colors[ TopicBackgroundColorIndex ];
3983
3984 SetupViews( Windows );
3985end;
3986
3987// Setup the rich text views in the specified windows (e.g for changing global settings)
3988Procedure TMainForm.SetupViews( WindowList: TList );
3989var
3990 WindowIndex: longint;
3991 Window: THelpWindow;
3992begin
3993 for WindowIndex := 0 to WindowList.Count - 1 do
3994 begin
3995 Window := WindowList[ WindowIndex ];
3996 Window.SetupRTView;
3997 SetupViews( Window.ChildWindows );
3998 end;
3999end;
4000
4001Procedure TMainForm.PostHelpManagerMessage( MessageType: ULONG;
4002 Param1: long;
4003 Param2: long );
4004var
4005 i: longint;
4006begin
4007 for i := 0 to HelpManagerWindows.Count - 1 do
4008 PostMsg( HWND( HelpManagerWindows[ i ] ),
4009 MessageType,
4010 Param1,
4011 Param2 );
4012end;
4013
4014Procedure TMainForm.ClearHelpManager;
4015Begin
4016 if not CmdLineParameters.getHelpManagerFlag then
4017 exit;
4018
4019 // tell the help manager(s) we are no longer playing with them
4020 PostHelpManagerMessage( NHM_FORGET_VIEWER, 0, 0 );
4021
4022 CmdLineParameters.setHelpManagerFlag(false);
4023
4024 HelpManagerWindows.Clear;
4025End;
4026
4027Procedure TMainForm.MainFormOnShow (Sender: TObject);
4028Begin
4029 EnableCallstackLogging( true );
4030
4031 LogEvent(LogStartup, 'MainFormOnShow');
4032
4033 if CmdLineParameters.getOwnerWindow <> NULLHANDLE then
4034 begin
4035 LogEvent(LogStartup, 'Setting owner: '
4036 + IntToStr( CmdLineParameters.getOwnerWindow));
4037 WinSetOwner( Frame.Handle,
4038 CmdLineParameters.getOwnerWindow );
4039
4040 end;
4041
4042 if CmdLineParameters.getHelpManagerFlag then
4043 begin
4044 LogEvent(LogStartup, ' Help Manager Title: '
4045 + StrNPas( pSharedStruct ^. Title,
4046 SHARED_STRUCT_TITLE_SIZE ) );
4047 HelpManagerVersion := StrNPas( pSharedStruct ^. Version,
4048 SHARED_STRUCT_VERSION_SIZE );
4049 LogEvent(LogStartup, ' Help Manager Version: ' + HelpManagerVersion );
4050
4051 end;
4052
4053 CoolBar.SetMinConstButtonWidth;
4054
4055 LogEvent(LogStartup, 'Post WM_OPENED');
4056
4057 ResetProgress;
4058
4059 AddShortcut( kbF11, kbF11 ); // prev in contents
4060 AddShortcut( kbF12, kbF12 ); // next in contents
4061 AddShortcut( kbF7, kbF7 ); // back
4062 AddShortcut( kbF8, kbF8 ); // forward
4063 AddShortcut( kbCtrlCLeft, kbCtrlCLeft ); // back
4064
4065 PostMsg( Handle, WM_OPENED, 0, 0 );
4066End;
4067
4068Procedure TMainForm.DisplaySelectedContentsTopic;
4069var
4070 Topic: TTopic;
4071Begin
4072 if ContentsOutline.SelectedNode = nil then
4073 exit;
4074 Topic := ContentsOutline.SelectedNode.Data as TTopic;
4075 DisplayTopic( Topic );
4076End;
4077
4078// Check that the HELP and BOOKSHELF environment variables
4079// are defined (as they should be on any working OS/2 system).
4080// Show a warning message if not.
4081Procedure TMainForm.CheckEnvironmentVars;
4082var
4083 HelpOK: boolean;
4084 BookshelfOK: boolean;
4085 ErrorText: string;
4086begin
4087 HelpOK := GetEnv( HelpPathEnvironmentVar ) <> '';
4088 BookshelfOK := GetEnv( BookshelfEnvironmentVar ) <> '';
4089 if HelpOK and BookshelfOK then
4090 // all ok.
4091 exit;
4092
4093 // One or both missing
4094
4095 ErrorText := '';
4096 if not BookshelfOK then
4097 ErrorText := ErrorText
4098 + EnvironmentVarUndefined
4099 + BookshelfEnvironmentVar
4100 + EndLine;
4101
4102 if not HelpOK then
4103 ErrorText := ErrorText
4104 + EnvironmentVarUndefined
4105 + HelpPathEnvironmentVar
4106 + EndLine;
4107
4108 DoWarningDlg( EnvironmentVarErrorTitle,
4109 EnvironmentVarError
4110 + EndLine
4111 + EndLine
4112 + ErrorText );
4113
4114end;
4115
4116Procedure LoadSupportDLL;
4117begin
4118 try
4119 LoadDLLFunction( 'newview.dll',
4120 'LZWDECOMPRESSBLOCK',
4121 hNewViewDLL,
4122 pointer( LZWDecompressBlock ) );
4123 except
4124 on E: Exception do
4125 begin
4126 DoErrorDlg( 'DLL Error',
4127 E.Message );
4128 LZWDecompressBlock := nil;
4129 end;
4130 end;
4131end;
4132
4133Procedure TMainForm.WMOpened( Var Msg: TMessage );
4134var
4135 Filenames: TStringList;
4136 M1: longword;
4137 OpenFirstTopic: boolean;
4138begin
4139 if Application.HelpFile = '' then
4140 DoErrorDlg( 'NewView Help', 'NewView help file not found' );
4141
4142 LoadSupportDLL;
4143
4144 LogEvent(LogStartup, 'WMOpened: SetLayout');
4145
4146 if CmdLineParameters.getHelpManagerFlag then
4147 FShowLeftPanel := Settings.ShowLeftPanel_Help
4148 else
4149 FShowLeftPanel := Settings.ShowLeftPanel_Standalone;
4150
4151 SetLayout;
4152
4153// ProfileEvent( 'Apply settings' );
4154// ApplySettings;
4155
4156 LogEvent(LogStartup, 'Enable controls');
4157 EnableControls;
4158
4159// ProfileEvent( 'ReadWindowPos' );
4160// ReadWindowPos( Self );
4161
4162 LogEvent(LogStartup, 'Finish paint');
4163 Update;
4164
4165 if not CmdLineParameters.getHelpManagerFlag then
4166 begin
4167 LogEvent(LogStartup, 'Check environment vars');
4168 CheckEnvironmentVars;
4169
4170 if CmdLineParameters.getShowUsageFlag then
4171 begin
4172 LogEvent(LogStartup, 'Showing usage');
4173 ShowUsage;
4174 end;
4175 end;
4176
4177 HelpManagerWindows.Add( pointer( CmdLineParameters.getHelpManagerWindow ) );
4178
4179 if CmdLineParameters.getInterpretedFileNames <> '' then
4180 begin
4181 // open specified files
4182 Filenames := TStringList.Create;
4183
4184 // TODO use StrExtractStrings
4185 StringToList(cmdLineParameters.getInterpretedFileNames, Filenames, '+' );
4186
4187 LogEvent(LogStartup, 'Call OpenFiles');
4188
4189 OpenFirstTopic := true;
4190
4191 if ( CmdLineParameters.getInterpretedSearchText <> '' )
4192 OR CmdLineParameters.getSearchFlag
4193 OR CmdLineParameters.getHelpManagerFlag
4194 then
4195 // if we're going to search, don't open first topic
4196 // don't open first topic if we're online help
4197 // in case we are wanting to show a specific topic
4198 // - saves time/flicker
4199 OpenFirstTopic := false;
4200
4201 OpenFiles( Filenames,
4202 CmdLineParameters.getWindowTitle,
4203 OpenFirstTopic );
4204
4205 Filenames.Destroy;
4206
4207 if not CmdLineParameters.getSearchFlag
4208 and not CmdLineParameters.getGlobalSearchFlag
4209 and (CmdLineParameters.getInterpretedSearchText <> '') then
4210 begin
4211 // search in contents only!
4212 LogEvent(LogStartup, 'Do startup topic search');
4213
4214 StartupTopicSearch( CmdLineParameters.getInterpretedSearchText );
4215 end
4216 else if CmdLineParameters.getSearchFlag then
4217 begin
4218 // search in specified files
4219 LogEvent(LogStartup, 'Do search for topic');
4220 DisplaySearch;
4221
4222 SearchFor( CmdLineParameters.getInterpretedSearchText );
4223 end;
4224 end;
4225
4226 if NOT CmdLineParameters.getShowUsageFlag
4227 AND CmdLineParameters.getGlobalSearchFlag then
4228 begin
4229 // Global search
4230 LogEvent(LogStartup, 'Do global search: ' + CmdLineParameters.getInterpretedSearchText);
4231 DoGlobalSearch( CmdLineParameters.getInterpretedSearchText );
4232 end;
4233
4234 LogEvent(LogStartup, 'Open finished');
4235
4236 if CmdLineParameters.getHelpManagerFlag then
4237 begin
4238 // Tell helpmanager(s) our window handle
4239 PostHelpManagerMessage( NHM_VIEWER_READY,
4240 Handle,
4241 0 );
4242 end;
4243
4244 M1:= MemAvail;
4245
4246 StartingUp := false;
4247
4248 LogEvent(LogStartup, 'RUN PROGRAM');
4249end;
4250
4251Procedure TMainForm.MainFormOnResize (Sender: TObject);
4252Begin
4253 if not Visible then
4254 exit;
4255 if Handle = 0 then
4256 exit;
4257
4258 SetLayout;
4259
4260End;
4261
4262Function TMainForm.GetShowLeftPanel: boolean;
4263begin
4264 Result := FShowLeftPanel;
4265end;
4266
4267Procedure TMainForm.SetShowLeftPanel( Value: boolean );
4268begin
4269 ShowLeftPanelMI.Checked := Value;
4270 if Value = FShowLeftPanel then
4271 exit;
4272 FShowLeftPanel := Value;
4273 if FShowLeftPanel then
4274 NotebookOnPageChanged( self ) // make sure page is updated
4275 else
4276 FocusFirstHelpWindow;
4277 EnableControls;
4278 SetLayout;
4279end;
4280
4281Procedure TMainForm.VSplitBarOnChange (NewSplit: LongInt);
4282Begin
4283 if VSplitBar.Left < 30 then
4284 begin
4285 ShowLeftPanel := false
4286 end
4287 else
4288 begin
4289 Settings.LeftPanelWidth := VSplitBar.Left;
4290 ShowLeftPanel := true;
4291 end;
4292 SetLayout;
4293End;
4294
4295// Set the layout of the main form
4296Procedure TMainForm.SetLayout;
4297var
4298 RealClientHeight : longint;
4299 CoolbarSpace: longint;
4300 TextHeight: longint;
4301Begin
4302 TextHeight := Canvas.TextHeight( 'S' );
4303 Tabset.Height := TextHeight + 5;
4304
4305 Coolbar.Visible := Settings.ToolbarStyle <> tsNone;
4306
4307 case Settings.ToolbarStyle of
4308 tsImages:
4309 Coolbar.Height := Coolbar.Sections[ 0 ].Width;
4310 tsText:
4311 Coolbar.Height := TextHeight + 5;
4312 tsImagesAndText:
4313 CoolBar.Height := ButtonImages.GetBitmapReference(0).Width + TextHeight + 10;
4314 end;
4315
4316 CoolbarSpace := Coolbar.Height;
4317 if not Coolbar.Visible then
4318 CoolbarSpace := 0;
4319
4320 StatusPanel.Left:= 0;
4321 StatusPanel.Width:= ClientWidth div 2 - 2;
4322 StatusPanel.Height := TextHeight + 2;
4323
4324 ProgressPanel.Left:= ClientWidth div 2 + 2;
4325 ProgressPanel.Width:= ClientWidth - ProgressPanel.Left;
4326 ProgressPanel.Height := TextHeight + 2;
4327
4328 Notebook.Bottom := StatusPanel.Height + 3;
4329 VSplitBar.Bottom := Notebook.Bottom;
4330 DisplayPanel.Bottom := Notebook.Bottom;
4331
4332 RealClientHeight := ClientHeight
4333 - CoolbarSpace
4334 - Notebook.Bottom;
4335
4336 LogEvent(LogStartup, 'TMainForm.SetLayout');
4337 LogEvent(LogStartup, ' RealClientHeight: ' + IntToStr( RealClientHeight ));
4338
4339 LogEvent(LogStartup, ' Form Width: ' + IntToStr( Width ));
4340 LogEvent(LogStartup, ' Form Height: ' + IntToStr( Height ) );
4341 LogEvent(LogStartup, ' Form ClientWidth: ' + IntToStr( ClientWidth ) );
4342 LogEvent(LogStartup, ' Form ClientHeight: ' + IntToStr( ClientHeight ) );
4343 LogEvent(LogStartup, ' CoolBar.Height: ' + IntToStr( CoolBar.Height ) );
4344 LogEvent(LogStartup, ' CoolBar.Bottom: ' + IntToStr( CoolBar.Bottom ) );
4345
4346 if CurrentOpenFiles.Count > 0 then
4347 VSplitBar.Width := Max( 5, Canvas.TextWidth( ' ' ) )
4348 else
4349 VSplitBar.Width := 0;
4350
4351 VSplitBar.Height := RealClientHeight;
4352
4353 if Settings.LeftPanelWidth > ClientWidth - 50 then
4354 Settings.LeftPanelWidth := ClientWidth - 50;
4355 if Settings.LeftPanelWidth < 50 then
4356 Settings.LeftPanelWidth := 50;
4357
4358 if ShowLeftPanel then
4359 begin
4360 VSplitBar.Left := Settings.LeftPanelWidth;
4361 VSplitBar.Hint := SplitBarDblClickToHide;
4362 end
4363 else
4364 begin
4365 VSplitBar.Left := 0;
4366 VSplitBar.Hint := SplitBarDblClickToShow;
4367 end;
4368
4369 Tabset.Left := 0;
4370 Tabset.Width := VSplitBar.Left;
4371 Tabset.Bottom := ClientHeight
4372 - CoolbarSpace
4373 - Tabset.Height;
4374
4375 Notebook.Left := 0;
4376 Notebook.Width := VSplitBar.Left;
4377 Notebook.Height := RealClientHeight
4378 - Tabset.Height
4379 - 3;
4380
4381 DisplayPanel.Left:= VSplitBar.Left + VSplitBar.Width;
4382 DisplayPanel.Width:= ClientWidth - DisplayPanel.Left;
4383 DisplayPanel.Height := RealClientHeight;
4384 LogEvent(LogStartup, ' DisplayPanel.Width: ' + IntToStr( DisplayPanel.Width ) );
4385 LogEvent(LogStartup, ' DisplayPanel.Height: ' + IntToStr( DisplayPanel.Height ) );
4386 LogEvent(LogStartup, ' DisplayPanel.Bottom: ' + IntToStr( DisplayPanel.Bottom ) );
4387
4388 ProgressBar.Left:= 1;
4389 ProgressBar.Bottom:= 1;
4390 ProgressBar.Width:= ProgressPanel.Width - 2;
4391 ProgressBar.Height:= ProgressPanel.Height - 2;
4392
4393 // Layout the visible help windows also
4394 LayoutWindowList( Windows );
4395End;
4396
4397// Lay out the specified list of help windows
4398Procedure TMainForm.LayoutWindowList( WindowList: TList );
4399var
4400 Window: THelpWindow;
4401 WindowIndex: longint;
4402begin
4403 for WindowIndex:= 0 to WindowList.Count - 1 do
4404 begin
4405 Window:= WindowList[ WindowIndex ];
4406 Window.SetLayout;
4407 end;
4408end;
4409
4410Procedure TMainForm.FindNextMIOnClick (Sender: TObject);
4411begin
4412 if FindText = '' then
4413 begin
4414 FindMIOnClick( sender );
4415 exit;
4416 end;
4417
4418 if GetActiveWindow = nil then
4419 begin
4420 DoErrorDlg( FindTitle,
4421 FindSelectWindowError );
4422 exit;
4423 end;
4424
4425 DoFind( foFromCurrent );
4426end;
4427
4428Procedure TMainForm.DoFind( FindOrigin: TFindOrigin );
4429var
4430 Window: THelpWindow;
4431begin
4432 SetWaitCursor;
4433 Window := GetActiveWindow;
4434 if not Window.View.Find( FindOrigin, FindText ) then
4435 begin
4436 SetStatus( TextNotFoundMsg );
4437 Beep( 1000, 100 );
4438 end;
4439 ClearWaitCursor;
4440End;
4441
4442Procedure TMainForm.FindMIOnClick (Sender: TObject);
4443begin
4444 if GetActiveWindow = nil then
4445 begin
4446 DoErrorDlg( FindTitle,
4447 FindSelectWindowError );
4448 exit;
4449 end;
4450 if not DoInputQuery( FindTitle,
4451 FindPrompt,
4452 FindText ) then
4453 exit;
4454
4455 DoFind( foFromStart );
4456End;
4457
4458Procedure TMainForm.IndexSearchEditOnScan (Sender: TObject;
4459 Var KeyCode: TKeyCode);
4460Begin
4461 case KeyCode of
4462 kbCUp:
4463 begin
4464 if IndexListBox.ItemIndex > 0 then
4465 IndexListBox.ItemIndex:= IndexListBox.ItemIndex - 1;
4466 KeyCode:= kbNull;
4467 end;
4468
4469 kbCDown:
4470 begin
4471 if IndexListBox.ItemIndex < IndexListBox.Items.Count - 1 then
4472 IndexListBox.ItemIndex:= IndexListBox.ItemIndex + 1;
4473 KeyCode:= kbNull;
4474 end;
4475
4476 kb_VK + VK_NEWLINE:
4477 begin
4478 DisplaySelectedIndexTopic;
4479 end;
4480 end;
4481
4482End;
4483
4484Procedure TMainForm.IndexSearchEditOnChange (Sender: TObject);
4485var
4486 MatchIndex: longint;
4487 IndexINdex: longint;
4488 SearchText: string;
4489Begin
4490 if InIndexSearch then
4491 exit;
4492
4493 MatchIndex:= -1;
4494 SearchText:= trim( IndexSearchEdit.Text );
4495 for IndexIndex:= 0 to DisplayedIndex.Count - 1 do
4496 begin
4497 if StrStarts( SearchText, DisplayedIndex[ IndexIndex ] ) then //IndexEntry ) then
4498 begin
4499 MatchIndex:= IndexIndex;
4500 break;
4501 end;
4502 end;
4503
4504 if MatchIndex = -1 then
4505 exit;
4506
4507 InIndexSearch:= true;
4508
4509 if IndexListBox.ItemIndex <> MatchIndex then
4510 IndexListBox.ItemIndex:= MatchIndex;
4511
4512 InIndexSearch:= false;
4513End;
4514
4515Procedure TMainForm.FileInformationMIOnClick (Sender: TObject);
4516var
4517 FileIndex: longint;
4518 HelpFile: THelpFile;
4519
4520 TotalTopicCount: longint;
4521 TotalIndexCount: longint;
4522 TotalFileSize: longint;
4523
4524Begin
4525 TotalTopicCount := 0;
4526 TotalIndexCount := 0;
4527 TotalFileSize := 0;
4528
4529 with InformationForm.InformationMemo do
4530 begin
4531 BeginUpdate;
4532 Lines.Clear;
4533 Lines.Add( FilesInfoTitle );
4534 for FileIndex := 0 to CurrentOpenFiles.Count - 1 do
4535 begin
4536 HelpFile := CurrentOpenFiles[ FileIndex ];
4537
4538 Lines.Add( FilesInfoFilename + HelpFile.FileName );
4539 Lines.Add( FilesInfoFileTitle
4540 + HelpFile.Title );
4541 Lines.Add( FilesInfoTopicCount
4542 + IntToStr( HelpFile.TopicCount ) );
4543 Lines.Add( FilesInfoIndexCount
4544 + IntToStr( HelpFile.Index.Count ) );
4545 Lines.Add( FilesInfoDictionaryCount
4546 + IntToStr( HelpFile.DictionaryCount ) );
4547 Lines.Add( FilesInfoFileSize
4548 + IntToStr( HelpFile.FileSize ) );
4549
4550 inc( TotalTopicCount, HelpFile.TopicCount );
4551 inc( TotalIndexCount, HelpFile.Index.Count );
4552 inc( TotalFileSize, HelpFile.FileSize );
4553
4554 end;
4555
4556 Lines.Add( '' );
4557 Lines.Add( FilesInfoTotalTopicCount
4558 + IntToStr( TotalTopicCount ) );
4559 Lines.Add( FilesInfoTotalIndexCount
4560 + IntToStr( TotalIndexCount ) );
4561 Lines.Add( FilesInfoTotalFileSize
4562 + IntToStr( TotalFileSize ) );
4563 Lines.Add( '' );
4564
4565 EndUpdate;
4566 end;
4567 InformationForm.ShowModal;
4568End;
4569
4570Procedure TMainForm.DisplaySelectedSearchResultTopic;
4571var
4572 Topic: TTopic;
4573Begin
4574 if SearchResultsListBox.ItemIndex = -1 then
4575 exit;
4576 if SelectedObject( SearchResultsListBox ) = nil then
4577 // the "no results" place holder
4578 exit;
4579 Topic := SelectedObject( SearchResultsListBox ) as TTopic;
4580 DisplayTopic( Topic );
4581End;
4582
4583Procedure TMainForm.SearchTextEditOnScan (Sender: TObject;
4584 Var KeyCode: TKeyCode);
4585Begin
4586 case KeyCode of
4587 kbCUp:
4588 begin
4589 if SearchResultsListBox.ItemIndex > 0 then
4590 SearchResultsListBox.ItemIndex := SearchResultsListBox.ItemIndex - 1;
4591 KeyCode := kbNull;
4592 SearchResultsListBox.Focus;
4593 end;
4594
4595 kbCDown:
4596 begin
4597 if SearchResultsListBox.ItemIndex < SearchResultsListBox.Items.Count - 1 then
4598 SearchResultsListBox.ItemIndex := SearchResultsListBox.ItemIndex + 1;
4599 KeyCode := kbNull;
4600 SearchResultsListBox.Focus;
4601 end;
4602 end;
4603End;
4604
4605Procedure TMainForm.SearchButtonOnClick (Sender: TObject);
4606Begin
4607 DoSearch;
4608End;
4609
4610// Matches old stupid View algorithm
4611Procedure TMainForm.StartupTopicSearch( const SearchText: string );
4612var
4613 i: longint;
4614 HelpFile: THelpFile;
4615 Topic: TTopic;
4616 // s: string;
4617begin
4618 // search files in order they are open
4619 for i := 0 to CurrentOpenFiles.Count - 1 do
4620 begin
4621 HelpFile := THelpFile( CurrentOpenFiles[ i ] );
4622
4623 // look for a topic whose title starts with the searchtext
4624 Topic := HelpFile.FindTopicByTitleStartsWith( SearchText );
4625
4626 if Topic = nil then
4627 // look for an index entry that starts with the searchtext
4628 Topic := HelpFile.FindTopicByIndexStartsWith( SearchText );
4629
4630 if Topic = nil then
4631 // look for a topic whose title contains the searchtext
4632 Topic := HelpFile.FindTopicByTitleContains( SearchText );
4633
4634 if Topic = nil then
4635 // look for an index entry that contains the searchtext
4636 Topic := HelpFile.FindTopicByIndexContains( SearchText );
4637
4638 if Topic <> nil then
4639 begin
4640 // found something, display it (don't keep searching files)
4641 DisplayTopic( Topic );
4642 exit;
4643 end;
4644 end;
4645 DoErrorDlg( SearchTitle, TextNotFoundMsg );
4646end;
4647
4648Procedure TMainForm.SearchFor( const SearchText: string );
4649begin
4650 SearchTextEdit.Text := SearchText;
4651 DisplaySearch;
4652 SearchResultsListBox.Focus;
4653
4654 // force repaint of everything before we start searching.
4655 Update;
4656
4657 DoSearch;
4658end;
4659
4660Procedure TMainForm.ClearAllWordSequences;
4661var
4662 i: longint;
4663 FileWordSequences: TList;
4664 HelpFile: THelpFile;
4665begin
4666 if AllFilesWordSequences = nil then
4667 exit;
4668
4669 for i := 0 to AllFilesWordSequences.Count - 1 do
4670 begin
4671 FileWordSequences := AllFilesWordSequences[ i ];
4672 HelpFile := CurrentOpenFiles[ i ];
4673 ClearWordSequences( FileWordSequences, HelpFile.DictionaryCount );
4674 FileWordSequences.Destroy;
4675 end;
4676 AllFilesWordSequences.Clear;
4677end;
4678
4679// Perform search for text in searchedit.
4680Procedure TMainForm.DoSearch;
4681var
4682 SearchResults: TList;
4683 SearchText: string;
4684 FileIndex: longint;
4685 HelpFile: THelpFile;
4686 TopicIndex: longint;
4687 Topic: TTopic;
4688 FileWordSequences: TList;
4689 Query: TTextSearchQuery;
4690begin
4691 SearchText := Trim( SearchTextEdit.Text );
4692
4693 SearchResultsListBox.Clear;
4694
4695 if SearchText = '' then
4696 exit;
4697
4698 SearchResultsListBox.Items.Add( SearchingMsg );
4699 SetStatus( SearchingMsg );
4700
4701 try
4702 Query := TTextSearchQuery.Create( SearchText );
4703 except
4704 on e: ESearchSyntaxError do
4705 begin
4706 DoErrorDlg( SearchTitle,
4707 SearchSyntaxError
4708 + e.Message );
4709 exit;
4710 end;
4711 end;
4712
4713 ClearAllWordSequences;
4714
4715 SetWaitCursor;
4716
4717 SearchResults := TList.Create;
4718
4719 // Search open help file
4720 for FileIndex := 0 to CurrentOpenFiles.Count - 1 do
4721 begin
4722 HelpFile := CurrentOpenFiles[ FileIndex ];
4723
4724 FileWordSequences := TList.Create;
4725
4726 try
4727 SearchHelpFile( HelpFile,
4728 Query,
4729 SearchResults,
4730 FileWordSequences );
4731 except
4732 on E: EHelpFileException do
4733 begin
4734 DoErrorDlg( ErrorTitle, E.Message );
4735 Query.Destroy;
4736 ClearWaitCursor;
4737 exit;
4738 end;
4739 end;
4740
4741 AllFilesWordSequences.Add( FileWordSequences );
4742
4743 end;
4744
4745 // Sort results across all files by relevance
4746 SearchResults.Sort( TopicRelevanceCompare );
4747
4748 // Load topics into search results list.
4749 SearchResultsListBox.BeginUpdate;
4750 SearchResultsListBox.Clear;
4751
4752 for TopicIndex := 0 to SearchResults.Count - 1 do
4753 begin
4754 Topic := SearchResults[ TopicIndex ];
4755 SearchResultsListBox.Items.AddObject( Topic.Title
4756 + ' ['
4757 + IntToStr( Topic.SearchRelevance )
4758 + ']',
4759 Topic );
4760 end;
4761
4762 EnableControls;
4763 if SearchResultsListBox.Items.Count > 0 then
4764 // there are some search matches, so highlight words
4765 ViewHighlightSearchWordsMI.Checked := true;
4766
4767 SearchResultsListBox.ItemIndex := -1;
4768 SearchResultsListBox.EndUpdate;
4769
4770 Query.Destroy;
4771 SearchResults.Destroy;
4772
4773 if SearchResultsListBox.Items.Count > 0 then
4774 begin
4775 SearchResultsListBox.ItemIndex := 0;
4776 end
4777 else
4778 begin
4779 SearchResultsListBox.Items.Add( NoSearchMatchesMsg
4780 + ': '
4781 + SearchText );
4782 RefreshWindows( Windows ); // update to remove old highlights
4783 end;
4784 SetStatus( SearchFoundMsgA
4785 + IntToStr( SearchResultsListBox.Items.Count )
4786 + SearchFoundMsgB
4787 + StrDoubleQuote( SearchText ) );
4788
4789 ClearWaitCursor;
4790
4791 DisplaySelectedSearchResultTopic;
4792
4793End;
4794
4795Procedure TMainForm.FileSaveAsMIOnClick (Sender: TObject);
4796var
4797 F: File;
4798 EntryText: PChar;
4799 TextLength: longint;
4800 Window: THelpWindow;
4801 Filename: string;
4802Begin
4803 Window := GetActiveWindow;
4804 if Window = nil then
4805 begin
4806 DoErrorDlg( FileSaveTitle,
4807 FileSaveSelectWindowError );
4808 exit;
4809 end;
4810
4811 if DoSaveFileDialog( FileSaveTitle,
4812 AllFilesDesc + '|*',
4813 DefaultSaveTopicFilename,
4814 Settings.LastSaveDirectory,
4815 Filename ) then
4816 begin
4817 if FileExists( Filename ) then
4818 if not DoConfirmDlg( FileSaveTitle,
4819 ReplaceFilePromptA
4820 + Filename
4821 + ReplaceFilePromptB ) then
4822 exit;
4823 System.Assign( F, Filename );
4824
4825 try
4826 Rewrite( F );
4827 except
4828 on E: Exception do
4829 begin
4830 DoErrorDlg( FileSaveTitle,
4831 UnableToSaveError
4832 + Filename
4833 + ': '
4834 + E.Message );
4835 exit;
4836 end;
4837 end;
4838
4839 // find out length of (plain) text
4840 TextLength := Window.View.CopyTextToBuffer( nil, -1 );
4841
4842 // allocate space
4843 EntryText:= StrAlloc( TextLength );
4844
4845 // get the plain text
4846 Window.View.CopyTextToBuffer( EntryText, TextLength );
4847
4848 // save to file
4849 System.BlockWrite( F, EntryText^, TextLength );
4850
4851 // free space
4852 StrDispose( EntryText );
4853
4854 System.Close( F );
4855 end;
4856End;
4857
4858Procedure TMainForm.OptionsMIOnClick (Sender: TObject);
4859begin
4860 DoOptions;
4861end;
4862
4863Procedure TMainForm.DoOptions;
4864Begin
4865 EnsureOptionsFormLoaded;
4866
4867 GetColors; // in case changed by drag drop
4868
4869 if OptionsForm.ShowModal = mrOK then
4870 begin
4871 ApplySettings;
4872 SetLayout;
4873 RefreshFontSubstitutions;
4874 RefreshWindows( Windows );
4875 end;
4876End;
4877
4878Procedure TMainForm.ShowUsage;
4879begin
4880 DoMessageDlg( UsageTitle,
4881 UsageText1 + EndLine
4882 + UsageText2 + EndLine
4883 + UsageText3 + EndLine
4884 + UsageText4 + EndLine
4885 + UsageText5 + EndLine
4886 + UsageText6 + EndLine
4887 + UsageText7 + EndLine
4888 + UsageText8 );
4889end;
4890
4891Procedure TMainForm.TabSetOnChange (Sender: TObject; NewTab: LongInt;
4892 Var AllowChange: Boolean);
4893Begin
4894 NoteBook.PageIndex := NewTab;
4895End;
4896
4897Procedure TMainForm.NotebookOnSetupShow (Sender: TObject);
4898Begin
4899 ContentsOutline.xStretch := xsFrame;
4900 ContentsOutline.yStretch := ysFrame;
4901
4902 IndexSearchEdit.yAlign := yaTop;
4903 IndexSearchEdit.xStretch := xsFrame;
4904 IndexListBox.yStretch := ysFrame;
4905 IndexListBox.xStretch := xsFrame;
4906
4907 SearchTextEdit.yAlign := yaTop;
4908 SearchTextEdit.xStretch := xsFrame;
4909 SearchButton.yAlign := yaTop;
4910 SearchButton.xAlign := xaRight;
4911 SearchResultsListBox.xStretch := xsFrame;
4912 SearchResultsListBox.yStretch := ysFrame;
4913
4914 NotesListBox.xStretch := xsFrame;
4915 NotesListBox.yStretch := ysFrame;
4916End;
4917
4918Procedure TMainForm.EnableControls;
4919var
4920 BackEnabled: boolean;
4921 ForwardEnabled: boolean;
4922 FileOpen: boolean;
4923 WindowOpen: boolean;
4924 AtTop: boolean;
4925 AtBottom: boolean;
4926begin
4927 ViewContentsMI.Checked := ShowLeftPanel and ( Notebook.PageIndex = piContents );
4928 ViewIndexMI.Checked := ShowLeftPanel and ( Notebook.PageIndex = piIndex );
4929 ViewSearchMI.Checked := ShowLeftPanel and ( Notebook.PageIndex = piSearch );
4930 ViewNotesMI.Checked := ShowLeftPanel and ( Notebook.PageIndex = piNotes );
4931
4932 BackEnabled := CurrentHistoryIndex > 0;
4933 ForwardEnabled := CurrentHistoryIndex < PageHistory.Count - 1;
4934
4935 FileOpen := CurrentOpenFiles.Count > 0;
4936 WindowOpen := Windows.Count > 0;
4937
4938 ViewContentsMI.Enabled := FileOpen;
4939 ViewIndexMI.Enabled := FileOpen;
4940 ViewSearchMI.Enabled := FileOpen;
4941 ViewNotesMI.Enabled := FileOpen;
4942
4943 ShowLeftPanelMI.Enabled := FileOpen;
4944
4945 Coolbar.Sections[ ciBack ].Disabled := not BackEnabled;
4946 NavigateBackMI.Enabled := BackEnabled;
4947 Coolbar.Sections[ ciForward ].Disabled := not ForwardEnabled;
4948 NavigateForwardMI.Enabled := ForwardEnabled;
4949
4950 FileSaveAsMI.Enabled := FileOpen;
4951
4952 Coolbar.Sections[ ciPrint ].Disabled := not FileOpen;
4953 PrintMI.Enabled := FileOpen;
4954 FileInformationMI.Enabled := FileOpen;
4955
4956 Coolbar.Sections[ ciAddBookmark ].Disabled := not FileOpen;
4957 AddBookmarkMI.Enabled := FileOpen;
4958 EditBookmarksMI.Enabled := FileOpen;
4959 Coolbar.Sections[ ciAddNote ].Disabled := not FileOpen;
4960 AddNoteMI.Enabled := FileOpen;
4961
4962 if ContentsOutline.SelectedNode <> nil then
4963 begin
4964 AtTop := ContentsOutline.NextNodeUp( ContentsOutline.SelectedNode, false ) = nil;
4965 AtBottom := ContentsOutline.NextNodeDown( ContentsOutline.SelectedNode, false ) = nil;
4966 end;
4967
4968 NavigateNextMI.Enabled := FileOpen
4969 and ( ContentsOutline.SelectedNode <> nil )
4970 and ( not AtBottom );
4971 Coolbar.Sections[ ciNext ].Disabled := not NavigateNextMI.Enabled;
4972 NavigatePreviousMI.Enabled := FileOpen
4973 and ( ContentsOutline.SelectedNode <> nil )
4974 and ( not AtTop );
4975 Coolbar.Sections[ ciPrevious ].Disabled := not NavigatePreviousMI.Enabled;
4976
4977 FileCloseMI.Enabled := FileOpen;
4978
4979 FindMI.Enabled := WindowOpen;
4980 FindNextMI.Enabled := WindowOpen;
4981 CopyMI.Enabled := WindowOpen;
4982 SelectAllMI.Enabled := WindowOpen;
4983
4984 ViewExpandAllMI.Enabled := ContentsOutline.ChildCount > 0;
4985 ViewCollapseAllMI.Enabled := ContentsOutline.ChildCount > 0;
4986
4987 DebugTopicByResourceIDMI.Enabled := FileOpen;
4988 TopicByNameMI.Enabled := FileOpen;
4989
4990 ViewHighlightSearchWordsMI.Enabled := SearchResultsListBox.Items.Count > 0;
4991 if not ViewHighlightSearchWordsMI.Enabled then
4992 ViewHighlightSearchWordsMI.Checked := false;
4993
4994 ViewRefreshMI.Enabled := WindowOpen;
4995
4996 EnableSearchButton;
4997 EnableNotesControls;
4998
4999 VSplitBar.Visible := FileOpen;
5000 if not FileOpen then
5001 begin
5002 SetShowLeftPanel( false );
5003 end;
5004
5005
5006end;
5007
5008Procedure TMainForm.NavigateBackMIOnClick (Sender: TObject);
5009begin
5010 NavigateBack;
5011end;
5012
5013Procedure TMainForm.SaveNavigatePoint;
5014var
5015 NavPoint: TNavigatePoint;
5016begin
5017 // delete rest of history.
5018 while CurrentHistoryIndex < PageHistory.Count - 1 do
5019 begin
5020 NavPoint:= PageHistory.Objects[ CurrentHistoryIndex + 1 ] as TNavigatePoint;
5021 NavPoint.Destroy;
5022 PageHistory.Delete( CurrentHistoryIndex + 1 );
5023 end;
5024
5025 NavPoint:= TNavigatePoint.Create;
5026 SaveWindows( Windows, NavPoint.Windows, nil );
5027
5028 if ContentsOutline.SelectedNode <> nil then
5029 NavPoint.ContentsTopic:= ContentsOutline.SelectedNode.Data as TTopic
5030 else
5031 NavPoint.ContentsTopic:= nil;
5032
5033 if CurrentTopic <> nil then
5034 PageHistory.AddObject( CurrentTopic.Title, NavPoint )
5035 else
5036 PageHistory.AddObject( '', NavPoint );
5037
5038 inc( CurrentHistoryIndex );
5039
5040 CreateNavigateToMenuItems;
5041end;
5042
5043Procedure TMainForm.UpdateCurrentNavigatePoint;
5044var
5045 NavPoint: TNavigatePoint;
5046begin
5047 if CurrentHistoryIndex = -1 then
5048 exit;
5049
5050 NavPoint:= PageHistory.Objects[ CurrentHistoryIndex ] as TNavigatePoint;
5051
5052 DestroyListObjects( NavPoint.Windows );
5053 NavPoint.Windows.Clear;
5054
5055 SaveWindows( Windows, NavPoint.Windows, nil );
5056end;
5057
5058Procedure TMainForm.ClearPageHistory;
5059var
5060 i: longint;
5061 NavPoint: TNavigatePoint;
5062begin
5063 for i := 0 to PageHistory.Count - 1 do
5064 begin
5065 NavPoint := PageHistory.Objects[ i ] as TNavigatePoint;
5066 NavPoint.Destroy;
5067 end;
5068 PageHistory.Clear;
5069 CurrentHistoryIndex := -1;
5070 CreateNavigateToMenuItems;
5071 EnableControls;
5072end;
5073
5074Procedure TMainForm.SaveWindows( SourceList: TList;
5075 DestList: TList;
5076 Parent: TSavedHelpWindow );
5077
5078var
5079 WindowIndex: longint;
5080 Window: THelpWindow;
5081 WindowCopy: TSavedHelpWindow;
5082begin
5083 // limit storage to only what's need since list will be static.
5084 DestList.Capacity := SourceList.Count;
5085 for WindowIndex := 0 to SourceList.Count - 1 do
5086 begin
5087 Window := SourceList[ WindowIndex ];
5088 WindowCopy := TSavedHelpWindow.Create;
5089 WindowCopy.Parent := Parent;
5090 WindowCopy.Rect.Assign( Window.Rect );
5091 WindowCopy.Topic := Window.Topic;
5092 WindowCopy.Group := Window.Group;
5093 WindowCopy.TopCharIndex := Window.View.TopCharIndex;
5094 SaveWindows( Window.ChildWindows, WindowCopy.ChildWindows, WindowCopy );
5095 DestList.Add( WindowCopy );
5096 end;
5097end;
5098
5099Procedure TMainForm.DisplayWindows( WindowList: TList;
5100 Parent: THelpWindow );
5101var
5102 WindowIndex: longint;
5103 WindowCopy: TSavedHelpWindow;
5104 NewWindow: THelpWindow;
5105begin
5106 for WindowIndex := 0 to WindowList.Count - 1 do
5107 begin
5108 WindowCopy := WindowList[ WindowIndex ];
5109 NewWindow := OpenWindow( WindowCopy.Topic,
5110 WindowCopy.Group,
5111 Parent,
5112 WindowCopy.Rect,
5113 false ); // don't follow links
5114 NewWindow.View.TopCharIndex := WindowCopy.TopCharIndex;
5115 DisplayWindows( WindowCopy.ChildWindows, NewWindow );
5116 end;
5117end;
5118
5119Procedure TMainForm.CreateNavigateToMenuItems;
5120var
5121 MenuItem: TMenuItem;
5122 i: integer;
5123begin
5124 // clear existing items
5125 DestroyListObjects( NavigateToMenuItems );
5126 NavigateToMenuItems.Clear;
5127
5128 if CurrentHistoryIndex > 0 then
5129 begin
5130 // We are going to add some items, so
5131 // add a seperator from the rest of the menu first
5132 MenuItem := TMenuItem.Create( self );
5133 MenuItem.Caption:= '-';
5134 NavigateMenu.Add( MenuItem );
5135 NavigateToMenuItems.Add( MenuItem );
5136 end;
5137
5138 i := CurrentHistoryIndex - 1; // don't include the current history item
5139 while ( ( i >= 0 )
5140 and ( i > CurrentHistoryIndex - 10 ) ) do
5141 begin
5142 MenuItem := TMenuItem.Create( self );
5143 MenuItem.Caption := PageHistory[ i ];
5144 MenuItem.Hint := GoBackHint
5145 + StrDoubleQuote( PageHistory[ i ] );
5146 MenuItem.OnClick := OnNavigateToMenuItemClick;
5147 MenuItem.Tag := i;
5148
5149 NavigateMenu.Add( MenuItem );
5150 NavigateToMenuItems.Add( MenuItem );
5151 dec( i );
5152 end;
5153end;
5154
5155Procedure TMainForm.NavigateToPoint( NavPoint: TNavigatePoint );
5156begin
5157 Navigating := true;
5158
5159 // close current windows
5160 CloseWindows;
5161
5162 // Display windows for the navigate point
5163 DisplayWindows( NavPoint.Windows, nil );
5164
5165 // Select the contents topic
5166 ContentsOutline.SetSelectedObject( NavPoint.ContentsTopic );
5167
5168 // Update the navigate menu (since a different set of
5169 // back-points are now available)
5170 CreateNavigateToMenuItems;
5171
5172 // Make the topic windows visible
5173 ShowWindows;
5174
5175 // Update back buttons etc...
5176 EnableControls;
5177
5178 Navigating := false;
5179end;
5180
5181Procedure TMainForm.NavigateToHistoryIndex( Index: longint );
5182var
5183 NavPoint: TNavigatePoint;
5184begin
5185 UpdateCurrentNavigatePoint;
5186 CurrentHistoryIndex := Index;
5187 NavPoint := PageHistory.Objects[ CurrentHistoryIndex ] as TNavigatePoint;
5188 NavigateToPoint( NavPoint );
5189end;
5190
5191Procedure TMainForm.NavigateForward;
5192Begin
5193 if CurrentHistoryIndex < PageHistory.Count - 1 then
5194 begin
5195 NavigateToHistoryIndex( CurrentHistoryIndex + 1 );
5196 end;
5197End;
5198
5199Procedure TMainForm.NavigateBack;
5200Begin
5201 if CurrentHistoryIndex > 0 then
5202 begin
5203 NavigateToHistoryIndex( CurrentHistoryIndex - 1 );
5204 end;
5205End;
5206
5207Procedure TMainForm.NavigatePreviousInContents;
5208begin
5209 ContentsOutline.GotoNextNodeUp;
5210 DisplaySelectedContentsTopic;
5211end;
5212
5213Procedure TMainForm.NavigateNextInContents;
5214begin
5215 ContentsOutline.GotoNextNodeDown;
5216 DisplaySelectedContentsTopic;
5217end;
5218
5219Procedure TMainForm.CorrectNotesPositions( Topic: TTopic;
5220 Text: pchar );
5221var
5222 NoteIndex: longint;
5223 Note: THelpNote;
5224 p: pchar;
5225 NextP: pchar;
5226 Element: TTextElement;
5227 TextIndex: longint;
5228begin
5229 NoteIndex := 0;
5230 for NoteIndex := 0 to Notes.Count - 1 do
5231 begin
5232 Note := Notes[ NoteIndex ];
5233 if Note.Topic = Topic then
5234 begin
5235 // this note belongs the the specified topic.
5236 p := Text;
5237
5238 while true do
5239 begin
5240 Element := ExtractNextTextElement( p, NextP );
5241 if Element.ElementType = teTextEnd then
5242 break;
5243 TextIndex := PCharDiff( p, Text );
5244 if TextIndex >= Note.InsertPoint then
5245 begin
5246 // found a safe point to insert
5247 if TextIndex <> Note.InsertPoint then
5248 begin
5249 // correct it.
5250 Note.InsertPoint := TextIndex;
5251 end;
5252 break;
5253 end;
5254
5255 p := NextP;
5256 end;
5257 end;
5258 end;
5259end;
5260
5261Procedure TMainForm.InsertNotesIntoTopicText( Topic: TTopic;
5262 Text: TAString );
5263var
5264 NoteIndex: longint;
5265 Note: THelpNote;
5266 ActualInsertPoint: longword;
5267begin
5268 CorrectNotesPositions( Topic, Text.AsPChar );
5269
5270 for NoteIndex := 0 to Notes.Count - 1 do
5271 begin
5272 Note := Notes[ NoteIndex ];
5273 if Note.Topic = Topic then
5274 begin
5275 // Adjust insert point for any notes we have already inserted.
5276 ActualInsertPoint := FindActualNoteCharIndex( Note.InsertPoint,
5277 NoteIndex,
5278 Topic );
5279 RefreshNoteInsertInfo( NoteIndex );
5280 Text.Insert( ActualInsertPoint, Note.InsertText );
5281 end;
5282 end;
5283end;
5284
5285Procedure TMainForm.NavigatePreviousMIOnClick (Sender: TObject);
5286Begin
5287 NavigatePreviousInContents;
5288End;
5289
5290Procedure TMainForm.NavigateNextMIOnClick (Sender: TObject);
5291Begin
5292 NavigateNextInContents;
5293End;
5294
5295Function TMainForm.GetActiveWindow: THelpWindow;
5296var
5297 View: TRichTextView;
5298 FirstWindow: THelpWindow;
5299begin
5300 Result := nil;
5301 if Screen.ActiveControl is TRichTextView then
5302 begin
5303 View := Screen.ActiveControl as TRichTextView;
5304 Result := FindWindowFromView( View, Windows );
5305 end
5306 else if Windows.Count = 1 then
5307 begin
5308 FirstWindow := Windows[ 0 ];
5309 if FirstWindow.ChildWindows.Count = 0 then
5310 Result := FirstWindow;
5311 end;
5312end;
5313
5314Procedure TMainForm.CopyMIOnClick (Sender: TObject);
5315var
5316 Window: THelpWindow;
5317begin
5318 if ActiveControl = nil then
5319 exit;
5320
5321 if ActiveControl is TEdit then
5322 begin
5323 // this is for the edit controls in the left panel
5324 TEdit( ActiveControl ).CopyToClipboard;
5325 exit;
5326 end;
5327
5328 // else copy from rtv in active help window
5329
5330 Window := GetActiveWindow;
5331 if Window = nil then
5332 exit;
5333
5334 Window.View.CopySelectionToClipboard;
5335End;
5336
5337Procedure TMainForm.SelectAllMIOnClick (Sender: TObject);
5338var
5339 Window: THelpWindow;
5340begin
5341 Window:= GetActiveWindow;
5342 if Window = nil then
5343 begin
5344 DoErrorDlg( SelectAllTitle,
5345 SelectAllWindowError );
5346 exit;
5347 end;
5348 Window.View.SelectAll;
5349End;
5350
5351Procedure TMainForm.DebugShowCodesMIOnClick (Sender: TObject);
5352Begin
5353 DebugShowCodesMI.Checked:= not DebugShowCodesMI.Checked;
5354 RefreshWindows( Windows );
5355End;
5356
5357Procedure TMainForm.HelpProductInformationMIOnClick (Sender: TObject);
5358Begin
5359 EnsureProductInformationFormLoaded;
5360 ProductInformationForm.ShowModal;
5361End;
5362
5363Procedure TMainForm.OnOverLink ( Sender: TRichTextView; LinkString: String);
5364var
5365 Link: THelpLink;
5366 LinkIndex: longint;
5367 Window: THelpWindow;
5368 LinkedTopic: TTopic;
5369 Filename: string;
5370 SourceFile: THelpFile;
5371 LinkedProgram: string;
5372 URL: string;
5373 LinkDetails: string;
5374 ProgramInfo : TSerializableStringList;
5375 ProgramPath, ProgramLink : string;
5376Begin
5377 if StrLeft( LinkString, 4 ) = 'note' then
5378 begin
5379 SetStatus( EditNoteMsg )
5380 end
5381 else if StrLeft( LinkString, 7 ) = 'program' then
5382 begin
5383 ProgramInfo := TSerializableStringList.create;
5384 ProgramInfo.readValuesFromSerializedString(StrRightFrom( LinkString, 9 ));
5385 ProgramPath := ProgramInfo.get(0);
5386 ProgramLink := ProgramInfo.get(1);
5387 TSerializableStringList.destroy;
5388 // call LaunchProgram here to inherit the environment
5389
5390 LinkedProgram := StrRightFrom( LinkString, 9 );
5391 SetStatus( LinkMsg + ' ' + ProgramPath + ' ' + ProgramLink);
5392 end
5393 else if StrLeft( LinkString, 3 ) = 'url' then
5394 begin
5395 URL := StrRightFrom( LinkString, 5 );
5396 SetStatus( LinkMsg
5397 + URL );
5398 end
5399 else if StrLeft( LinkString, 8 ) = 'external' then
5400 begin
5401 LinkDetails := StrRightFrom( LinkString, 10 );
5402 LinkIndex := StrToInt( ExtractNextValue( LinkDetails, ' ' ) );
5403 Window := FindWindowFromView( Sender, Windows );
5404 SourceFile := Window.Topic.HelpFile as THelpFile;
5405 Filename := SourceFile.ReferencedFiles[ LinkIndex ];
5406 SetStatus( LinkMsg
5407 + StrDoubleQuote( Filename ) );
5408 end
5409 else
5410 begin
5411 Window := FindWindowFromView( Sender, Windows );
5412 LinkIndex := StrToInt( LinkString );
5413 Link := Window.Topic.Links[ LinkIndex ];
5414
5415 if Link is TFootnoteHelpLink then
5416 begin
5417 SetStatus( FootnoteMsg );
5418 end
5419 else
5420 begin
5421 LinkedTopic := FindTopicForLink( Link );
5422
5423 if LinkedTopic <> nil then
5424 begin
5425 SetStatus( LinkMsg
5426 + StrDoubleQuote( Trim( LinkedTopic.Title ) ) );
5427 end
5428 else
5429 begin
5430 SetStatus( UnknownLinkMsg );
5431 end;
5432 end;
5433 end;
5434End;
5435
5436Procedure TMainForm.OnNotOverLink ( Sender: TRichTextView; LinkString: String);
5437Begin
5438 SetStatus( '' );
5439end;
5440
5441Procedure TMainForm.OnClickLink ( Sender: TRichTextView; LinkString: String);
5442var
5443 Link: THelpLink;
5444 LinkIndex: longint;
5445 SourceWindow: THelpWindow;
5446 NoteIndex: longint;
5447 Window: THelpWindow;
5448 SourceFile: THelpFile;
5449 ProgramLink: string;
5450 ProgramPath: string;
5451 URL: string;
5452 LinkDetails: string;
5453 ProgramInfo : TSerializableStringList;
5454Begin
5455 if StrLeft( LinkString, 4 ) = 'note' then
5456 begin
5457 NoteIndex := StrToInt( StrRightFrom( LinkString, 5 ) );
5458 NotesListBox.ItemIndex := NoteIndex;
5459 EditNote( NoteIndex );
5460 end
5461 else if StrLeft( LinkString, 7 ) = 'program' then
5462 begin
5463 ProgramInfo := TSerializableStringList.create;
5464 ProgramInfo.readValuesFromSerializedString(StrRightFrom( LinkString, 9 ));
5465 ProgramPath := ProgramInfo.get(0);
5466 ProgramLink := ProgramInfo.get(1);
5467 TSerializableStringList.destroy;
5468 // call LaunchProgram here to inherit the environment
5469 LogEvent(LogDisplay, 'LaunchProgram: "' + ProgramPath + '" "' + ProgramLink + '"');
5470 LaunchProgram(ProgramPath, ProgramLink, '');
5471 SetStatus( 'Launched ' + ProgramPath );
5472 end
5473 else if StrLeft( LinkString, 3 ) = 'url' then
5474 begin
5475 URL := StrRightFrom( LinkString, 5 );
5476 LaunchURL( URL );
5477 SetStatus( 'Opened '
5478 + URL );
5479 end
5480 else if StrLeft( LinkString, 8 ) = 'external' then
5481 begin
5482 LinkDetails := StrRightFrom( LinkString, 10 );
5483 LinkIndex := StrToInt( ExtractNextValue( LinkDetails, ' ' ) );
5484 Window := FindWindowFromView( Sender, Windows );
5485 SourceFile := Window.Topic.HelpFile as THelpFile;
5486
5487 g_ExternalLinkFileName := SourceFile.ReferencedFiles[ LinkIndex ];
5488 g_ExternalLinkTopic := LinkDetails;
5489 g_ExternalLinkSourceFilename := SourceFile.Filename;
5490 g_ExternalLinkKeepCurrent := true; // hm... what would be nice?
5491
5492 PostMsg( Self.Handle,
5493 WM_FOLLOWEXTERNALLINK,
5494 0,
5495 0 );
5496 end
5497 else
5498 begin
5499 SourceWindow := FindWindowFromView( Sender, Windows );
5500 LinkIndex := StrToInt( LinkString );
5501 Link := SourceWindow.Topic.Links[ LinkIndex ];
5502
5503 PostMsg( Self.Handle,
5504 WM_FOLLOWLINK,
5505 longint( Link ),
5506 longint( SourceWindow ) );
5507
5508 end;
5509End;
5510
5511Procedure TMainForm.OnWindowAboutToClose( Window: THelpWindow;
5512 var CanClose: boolean );
5513begin
5514 if Navigating then
5515 exit;
5516
5517 UpdateCurrentNavigatePoint; // Save it before close...
5518
5519 CanClose := true;
5520end;
5521
5522Procedure TMainForm.RemoveHelpWindowFromParent( Window: THelpWindow );
5523var
5524 ParentWindow: THelpWindow;
5525 WindowIndex: longint;
5526Begin
5527 if Navigating then
5528 exit;
5529
5530 if Window.ParentHelpWindow = nil then
5531 begin
5532 WindowIndex := Windows.IndexOf( Window );
5533 Windows.Delete( WindowIndex );
5534 end
5535 else
5536 begin
5537 ParentWindow := Window.ParentHelpWindow;
5538 WindowIndex := ParentWindow.ChildWindows.IndexOf( Window );
5539 ParentWindow.ChildWindows.Delete( WindowIndex );
5540 end;
5541end;
5542
5543Procedure TMainForm.OnWindowClose( Window: THelpWindow );
5544Begin
5545 if Navigating then
5546 exit;
5547
5548 RemoveHelpWindowFromParent( Window );
5549
5550 SaveNavigatePoint;
5551 EnableControls;
5552End;
5553
5554Procedure TMainForm.BackButtonOnClick (Sender: TObject);
5555Begin
5556 NavigateBack;
5557End;
5558
5559Procedure TMainForm.RTViewOnSetupShow (Sender: TObject);
5560Begin
5561End;
5562
5563Procedure TMainForm.ExitMIOnClick (Sender: TObject);
5564Begin
5565 Close;
5566End;
5567
5568Procedure TMainForm.CreateMRUMenuItems;
5569var
5570 MenuItem: TMenuItem;
5571 i: integer;
5572 FileName: string;
5573 FileNameIndex: longint;
5574 MRUText: string;
5575 MRUItem: TMRUItem;
5576begin
5577 DestroyListObjects( MRUMenuItems );
5578 MRUMenuItems.Clear;
5579
5580 // if there are Most Recently Used files
5581 if Settings.MRUList.Count > 0 then
5582 begin
5583 // create a seperator after Exit
5584 MenuItem:= TMenuItem.Create( self );
5585 MenuItem.Name := 'MRUSeparatorMI';
5586 MenuItem.Caption:= '-';
5587 FileMenu.Add( MenuItem );
5588 MRUMenuItems.Add( MenuItem );
5589 end;
5590
5591 // Add items for the MRU files
5592 for i:= 0 to Settings.MRUList.Count -1 do
5593 begin
5594 MRUItem := Settings.MRUList[ i ];
5595
5596 MenuItem := TMenuItem.Create( self );
5597
5598 MenuItem.Name := 'MRUItem' + IntToStr( i ) + 'MI';
5599 MRUText := MRUItem.Title;
5600 if Trim( MRUText ) = '' then
5601 begin
5602 // Take the filenames, less path, as caption...
5603 MRUText := '';
5604 for FileNameIndex := 0 to MRUItem.Filenames.Count - 1 do
5605 begin
5606 FileName := MRUItem.Filenames[ FileNameIndex ];
5607 FileName := ExtractFileName( FileName );
5608 FileName := ChangeFileExt( FileName, '' );// remove extension
5609 AddToListString( MRUText,
5610 FileName,
5611 '+' );
5612
5613 // stop after 50 chars
5614 if Length( MRUText ) > 50 then
5615 begin
5616 MRUText := MRUText + '+ ...';
5617 break;
5618 end;
5619 end;
5620 end;
5621
5622 MenuItem.Caption:= '~'
5623 + IntToStr( i + 1 )
5624 + '. '
5625 + MRUText;
5626 if MRUItem.Filenames.Count = 1 then
5627 MenuItem.Hint := MRUItem.Filenames[ 0 ]
5628 else
5629 MenuItem.Hint := MRUItem.Title
5630 + ' ('
5631 + IntToStr( MRUItem.Filenames.Count )
5632 + ' '
5633 + MRUMultipleFilesHint
5634 + ')';
5635
5636 MenuItem.OnClick:= OnMRUMenuItemClick;
5637 MenuItem.Tag:= i;
5638 FileMenu.Add( MenuItem );
5639 MRUMenuItems.Add( MenuItem );
5640 end;
5641end;
5642
5643procedure TMainForm.OnMRUMenuItemClick( Sender: TObject );
5644var
5645 Tag: longint;
5646 MenuItem: TMenuItem;
5647 MRUItem: TMRUItem;
5648begin
5649 MenuItem:= Sender as TMenuItem;
5650 Tag:= MenuItem.Tag;
5651 MRUItem := Settings.MRUList[ Tag ];
5652 if OpenFiles( MRUItem.FileNames, '', true ) then
5653 begin
5654 ClearHelpManager;
5655 end;
5656end;
5657
5658Procedure TMainForm.OnNavigateToMenuItemClick( Sender: TObject );
5659var
5660 MenuItem: TMenuItem;
5661 Tag: longint;
5662begin
5663 MenuItem:= Sender as TMenuItem;
5664 Tag:= MenuItem.Tag;
5665 NavigateToHistoryIndex( Tag );
5666end;
5667
5668Procedure TMainForm.AddChildNodes( HelpFile: THelpFile;
5669 ParentNode: TNode;
5670 Level: longint;
5671 Var TopicIndex: longint );
5672var
5673 Topic: TTopic;
5674 Node: TNode;
5675begin
5676 assert( ParentNode <> nil );
5677 Node := nil;
5678 while TopicIndex < HelpFile.TopicCount do
5679 begin
5680 Topic:= HelpFile.Topics[ TopicIndex ];
5681
5682 if Topic.ShowInContents then
5683 begin
5684 if Topic.ContentsLevel < Level then
5685 break;
5686
5687 if Topic.ContentsLevel = Level then
5688 begin
5689 Node:= ParentNode.AddChild( Topic.Title,
5690 Topic );
5691 inc( TopicIndex );
5692 end
5693 else
5694 begin
5695 assert( Node <> nil );
5696 AddChildNodes( HelpFile,
5697 Node,
5698 Topic.ContentsLevel,
5699 TopicIndex );
5700 Node := nil;
5701 end
5702 end
5703 else
5704 begin
5705 inc( TopicIndex );
5706 end;
5707 end;
5708
5709end;
5710
5711Procedure TMainForm.LoadContents( Files: TList;
5712 Var FirstNode: TNode );
5713var
5714 TopicIndex: longint;
5715 Topic: TTopic;
5716 Node: TNode;
5717 FileIndex: longint;
5718 HelpFile: THelpFile;
5719begin
5720 ContentsOutline.BeginUpdate;
5721 LogEvent(LogStartup, 'Load contents outline');
5722
5723 // we don't clear it first, to allow adding additional files
5724 // into the contents tree
5725
5726 LogEvent(LogStartup, 'Loop files');
5727
5728 FirstNode := nil;
5729
5730 Node := nil;
5731
5732 for FileIndex:= 0 to Files.Count - 1 do
5733 begin
5734 HelpFile := Files[ FileIndex ];
5735 LogEvent(LogStartup, 'File ' + IntToStr( FileIndex ) );
5736 TopicIndex := 0;
5737 while TopicIndex < HelpFile.TopicCount do
5738 begin
5739 Topic := HelpFile.Topics[ TopicIndex ];
5740 assert( Topic.ContentsLevel >= 0,
5741 'Topic contents level is ' + IntToStr( Topic.ContentsLevel ) );
5742 if Topic.ShowInContents then
5743 begin
5744 if Topic.ContentsLevel = 1 then
5745 begin
5746 Node := ContentsOutline.AddChild( Topic.Title,
5747 Topic );
5748 if FirstNode = nil then
5749 FirstNode := node;
5750
5751 inc( TopicIndex );
5752 end
5753 else
5754 begin
5755 // subnodes
5756 assert( Node <> nil, 'No level 1 topic for subnodes!' );
5757 AddChildNodes( HelpFile,
5758 Node,
5759 Topic.ContentsLevel,
5760 TopicIndex );
5761 Node := nil;
5762 end;
5763 end
5764 else
5765 begin
5766 inc( TopicIndex );
5767 end;
5768 end;
5769 end;
5770 LogEvent(LogStartup, ' EndUpdate' );
5771 ContentsOutline.EndUpdate;
5772
5773 if Settings.OpenWithExpandedContents then
5774 begin
5775 LogEvent(LogStartup, ' Expand all contents' );
5776 ContentsOutline.ExpandAll
5777 end
5778 else if ContentsOutline.ChildCount = 1 then
5779 begin
5780 LogEvent(LogStartup, ' Expand first node' );
5781 // Contents has only one top level node... expand it
5782 FirstNode.Expand;
5783 end;
5784
5785 ContentsLoaded := true;
5786 LogEvent(LogStartup, ' Contents loaded' );
5787
5788end;
5789
5790Procedure TMainForm.SaveNotesForFile( HelpFile: THelpFile );
5791var
5792 NotesFileName: string;
5793 TopicIndex: longword;
5794 Note: THelpNote;
5795 NoteIndex: longint;
5796
5797 NotesFile: HFile;
5798 OpenAction: ULong;
5799 rc: APIRET;
5800 CName: Cstring;
5801 FileNoteCount: integer;
5802
5803begin
5804 LogEvent(LogStartup, 'Save notes for ' + HelpFile.Filename );
5805
5806 if not HelpFile.NotesLoaded then
5807 // we never loaded the notes/displayed a topic from this file
5808 // so don't do anything.
5809 exit;
5810
5811 LogEvent(LogStartup, 'Really saving' );
5812
5813 NotesFileName := ChangeFileExt( HelpFile.FileName, '.nte' );
5814
5815 FileNoteCount := 0;
5816 for NoteIndex := 0 to Notes.Count - 1 do
5817 begin
5818 Note := Notes[ NoteIndex ];
5819
5820 if Note.Topic.HelpFile = HelpFile then
5821 inc( FileNoteCount );
5822 end;
5823
5824 if FileNoteCount = 0 then
5825 begin
5826 // no notes. delete notes file if it already exists.
5827 if FileExists( NotesFileName ) then
5828 DeleteFile( NotesFileName );
5829 exit;
5830 end;
5831
5832 CName:= NotesFileName;
5833 rc:= DosOpen( CName,
5834 NotesFile,
5835 OpenAction,
5836 0, // file size
5837 0, // attrs
5838 OPEN_ACTION_CREATE_IF_NEW + OPEN_ACTION_REPLACE_IF_EXISTS,
5839 OPEN_SHARE_DENYREADWRITE + OPEN_ACCESS_WRITEONLY,
5840 nil ); // no eas
5841 if rc <> 0 then
5842 begin
5843 DoErrorDlg( SaveNotesTitle,
5844 SaveNotesError
5845 + EndLine
5846 + NotesFileName
5847 + EndLine
5848 + SysErrorMessage( rc ) );
5849 exit;
5850 end;
5851
5852 for NoteIndex:= 0 to Notes.Count - 1 do
5853 begin
5854 Note:= Notes[ NoteIndex ];
5855
5856 if Note.Topic.HelpFile <> HelpFile then
5857 continue;
5858
5859 TopicIndex:= HelpFile.IndexOfTopic( Note.Topic );
5860
5861 MyWriteLn( NotesFile,
5862 IntToStr( TopicIndex ));
5863 MyWriteLn( NotesFile,
5864 IntToStr( Note.InsertPoint ) );
5865
5866 MyWrite( NotesFile,
5867 Note.Text.AsPChar,
5868 Note.Text.Length );
5869
5870 MyWriteLn( NotesFile,
5871 '' );
5872 MyWriteLn( NotesFile,
5873 '#ENDNOTE#' );
5874
5875 end;
5876
5877 DosClose( NotesFile );
5878end;
5879
5880Procedure TMainForm.LoadNotes( HelpFile: THelpFile );
5881var
5882 NotesFileName: string;
5883 TopicIndex: longint;
5884 InsertPoint: longint;
5885 Note: THelpNote;
5886
5887 NotesFile: HFile;
5888 OpenAction: ULong;
5889 rc: APIRET;
5890 CName: Cstring;
5891
5892 Paragraph: TAString;
5893 NotEOF: boolean;
5894 NoteText: TAString;
5895
5896begin
5897 LogEvent(LogStartup, 'Load notes for ' + HelpFile.Filename );
5898
5899 if HelpFile.NotesLoaded then
5900 exit;
5901
5902 HelpFile.NotesLoaded := true;
5903 NotesFileName := ChangeFileExt( HelpFile.FileName, '.nte' );
5904
5905 if not FileExists( NotesFileName ) then
5906 // no notes
5907 exit;
5908
5909 CName := NotesFileName;
5910 rc := DosOpen( CName,
5911 NotesFile,
5912 OpenAction,
5913 0, // file size - irrelevant, not creating,
5914 0, // attrs - ''
5915 OPEN_ACTION_OPEN_IF_EXISTS,
5916 OPEN_SHARE_DENYREADWRITE + OPEN_ACCESS_READONLY,
5917 nil ); // no eas
5918 if rc <> 0 then
5919 begin
5920 DoErrorDlg( LoadNotesTitle,
5921 LoadNotesError
5922 + EndLine
5923 + NotesFileName
5924 + EndLine
5925 + SysErrorMessage( rc ) );
5926 exit;
5927 end;
5928
5929 Paragraph := TAString.Create;
5930 NoteText := TAString.Create;
5931
5932 NotEOF := true;
5933
5934 while NotEOF do
5935 begin
5936 // Read contents index
5937 NotEOF := Paragraph.ReadParagraph( NotesFile );
5938 if not NotEOF then
5939 continue;
5940 try
5941 TopicIndex := StrToInt( Paragraph.AsString );
5942 except
5943 TopicIndex := -1;
5944 end;
5945
5946 // Read insert point
5947 NotEOF := Paragraph.ReadParagraph( NotesFile );
5948 if not NotEOF then
5949 continue;
5950 try
5951 InsertPoint := StrToInt( Paragraph.AsString );
5952 except
5953 InsertPoint := -1;
5954 end;
5955
5956 NoteText.Clear;
5957
5958 while NotEOF do
5959 begin
5960 NotEOF := Paragraph.ReadParagraph( NotesFile );
5961 if Paragraph.SameAs( '#ENDNOTE#' ) then
5962 begin
5963 // found end of note
5964 if ( TopicIndex >= 0 )
5965 and ( InsertPoint >= 0 ) then
5966 begin
5967 Note := THelpNote.Create;
5968 Note.Topic := HelpFile.Topics[ TopicIndex ];
5969 Note.InsertPoint := InsertPoint;
5970
5971 // Remove the last end line
5972 Note.Text.Assign( NoteText );
5973 if Note.Text.Length > 2 then
5974 Note.Text.Delete( Note.Text.Length - 2, 2 );
5975
5976 Notes.Add( Note );
5977 end;
5978 break;
5979 end;
5980 NoteText.Add( Paragraph );
5981 NoteText.AddString( #13 + #10 );
5982 end;
5983
5984 end;
5985 DosClose( NotesFile );
5986
5987 Paragraph.Destroy;
5988 NoteText.Destroy;
5989
5990end;
5991
5992Procedure TMainForm.UpdateNotesDisplay;
5993var
5994 NoteIndex: longint;
5995 Note: THelpNote;
5996 NoteTitle: string;
5997begin
5998 NotesListBox.Clear;
5999 for NoteIndex := 0 to Notes.Count - 1 do
6000 begin
6001 Note := Notes[ NoteIndex ];
6002
6003 if Note.Topic > nil then
6004 NoteTitle := Note.Topic.Title
6005 else
6006 NoteTitle := StrLeft( Note.Text.AsString, 100 );
6007 NotesListBox.Items.AddObject( NoteTitle,
6008 Note );
6009 end;
6010 EnableNotesControls;
6011end;
6012
6013Procedure TMainForm.EnableNotesControls;
6014var
6015 NoteSelected: boolean;
6016begin
6017 NoteSelected:= NotesListBox.ItemIndex <> -1;
6018 EditNoteButton.Enabled:= NoteSelected;
6019 GotoNoteButton.Enabled:= NoteSelected;
6020 DeleteNoteButton.Enabled:= NoteSelected;
6021 AddNoteButton.Enabled := CurrentOpenFiles.Count > 0;
6022end;
6023
6024Function TMainForm.OKToCloseFile: boolean;
6025begin
6026 Result := true;
6027
6028 if PrintThread = nil then
6029 // haven't used print thread yet
6030 exit;
6031
6032 if not PrintThread.IsRunning then
6033 // not currently running
6034 exit;
6035
6036 Result := DoConfirmDlg( CheckStopPrintTitle,
6037 CheckStopPrintMsg );
6038
6039end;
6040
6041Procedure TMainForm.StopPrinting;
6042begin
6043 if PrintThread <> nil then
6044 begin
6045 if PrintThread.IsRunning then
6046 begin
6047 SetStatus( StoppingPrintMsg );
6048 PrintThread.ForceStop( 5 ); // wait up to 5 seconds then terminate
6049 SetStatus( PrintStoppedMsg );
6050 ResetProgress;
6051 end;
6052 end;
6053end;
6054
6055Procedure TMainForm.CloseFile;
6056var
6057 FileIndex: longint;
6058 HelpFile: THelpFile;
6059 M1: longint;
6060begin
6061 StopPrinting;
6062
6063 LogEvent(LogShutdown, 'Set Caption' );
6064 MainTitle := '';
6065 SetMainCaption;
6066
6067 LogEvent(LogShutdown, 'Close Windows' );
6068 CloseWindows;
6069
6070 LogEvent(LogShutdown, 'Set selected node to nil' );
6071 ContentsOutline.SelectedNode:= Nil;
6072
6073 M1:= MemAvail;
6074
6075 LogEvent(LogShutdown, 'Clear contents outline' );
6076 ContentsOutline.Clear;
6077
6078 LogEvent(LogShutdown, 'Free contents: ' + IntToStr( MemAvail - M1 ) );
6079 M1:= MemAvail;
6080
6081 DisplayedIndex.Clear;
6082 IndexListBox.Clear;
6083 LogEvent(LogShutdown, 'Clear index ' + IntToStr( MemAvail - M1 ) );
6084 M1:= MemAvail;
6085
6086 NotesListBox.Clear;
6087 SearchResultsListBox.Clear;
6088
6089 LogEvent(LogShutdown, 'Notes, search etc ' + IntToStr( MemAvail - M1 ) );
6090 M1:= MemAvail;
6091
6092 // First save notes and bookmarks.
6093 // It's important we do this first
6094 // since we scan all notes each time to find the ones
6095 // belonging to this file.
6096 SaveBookmarks;
6097
6098 SaveNotes;
6099
6100 ClearAllWordSequences;
6101
6102 LogEvent(LogShutdown, 'Destroy helpfile objects' );
6103
6104 // Now destroy help files
6105 for FileIndex := 0 to CurrentOpenFiles.Count - 1 do
6106 begin
6107 HelpFile := CurrentOpenFiles[ FileIndex ];
6108 GlobalFilelist.RemoveFile( Frame.Handle,
6109 HelpFile.Filename );
6110 HelpFile.Free;
6111 end;
6112
6113 CurrentOpenFiles.Clear;
6114
6115 LogEvent(LogShutdown, 'Destroy helpfiles ' + IntToStr( MemAvail - M1 ) );
6116 M1 := MemAvail;
6117
6118 LogEvent(LogShutdown, 'Clear notes' );
6119 ClearNotes;
6120
6121 LogEvent(LogShutdown, 'Clear bookmarks' );
6122 ClearBookmarks;
6123
6124 ClearPageHistory;
6125
6126 LogEvent(LogShutdown, 'Enable controls' );
6127 EnableControls;
6128
6129 LogEvent(LogShutdown, 'CloseFile done' );
6130
6131end;
6132
6133Function TMainForm.FindOpenHelpFile( FileName: string ): THelpFile;
6134var
6135 FileIndex: longint;
6136begin
6137 for FileIndex:= 0 to CurrentOpenFiles.Count - 1 do
6138 begin
6139 Result:= CurrentOpenFiles[ FileIndex ];
6140 if StringsSame( Result.Filename, FileName ) then
6141 // found
6142 exit;
6143 end;
6144 Result:= nil;
6145end;
6146
6147// This rather horrendous looking bit of code simply:
6148
6149// Gets the contents from each file
6150// Sorts it alphabetically.
6151// Merges all the sorted contents and indexes together,
6152// alphabetically.
6153type
6154 TListType = ( ltContents, ltIndex );
6155
6156procedure TMainForm.LoadIndex;
6157var
6158 HelpFile: THelpFile;
6159 TextCompareResult: integer;
6160
6161 FileIndex: longint;
6162
6163 Contents: TList;
6164 ContentsLists: TList; // of tlist
6165 IndexLists: TList; // of tstringlist
6166 ContentsNextIndex: array[ 0..255 ] of longint;
6167 IndexNextIndex: array[ 0..255 ] of longint;
6168 Topic: TTopic;
6169
6170 ListIndex: longint;
6171
6172 pListEntry: pstring;
6173 pLowestEntry: pstring;
6174 pLastEntry: pstring;
6175
6176 LowestEntryListIndex: longint;
6177 LowestEntryListType: TListType;
6178 LowestEntryTopic: TTopic;
6179
6180 Index: TStringList;
6181
6182 i : longint;
6183begin
6184 LogEvent(LogStartup, 'Create index' );
6185
6186 SetWaitCursor;
6187
6188 LogEvent(LogStartup, ' Get/sort lists' );
6189
6190 ProgressBar.Position := 70;
6191 SetStatus( 'Building index... ' );
6192
6193 ContentsLists := TList.Create;
6194 IndexLists := TList.Create;
6195
6196 // collect the contents and index lists from the files
6197 for FileIndex := 0 to CurrentOpenFiles.Count - 1 do
6198 begin
6199 HelpFile := CurrentOpenFiles[ FileIndex ];
6200 ProgressBar.Position := 70 + 10 * FileIndex div CurrentOpenFiles.Count;
6201
6202 if Settings.IndexStyle in [ isAlphabetical, isFull ] then
6203 begin
6204 Contents := TList.Create;
6205 Contents.Capacity := HelpFile.TopicCount;
6206
6207 // copy [contents] topic list
6208 for i := 0 to HelpFile.TopicCount - 1 do
6209 begin
6210 Topic := HelpFile.Topics[ i ];
6211 if Topic.ShowInContents then
6212 Contents.Add( Topic );
6213 end;
6214
6215 // sort by title
6216 Contents.Sort( TopicTitleCompare );
6217
6218 ContentsLists.Add( Contents );
6219
6220 // initialise list index
6221 ContentsNextIndex[ ContentsLists.Count - 1 ] := 0;
6222 end;
6223
6224 if Settings.IndexStyle in [ isFileOnly, isFull ] then
6225 begin
6226 IndexLists.Add( HelpFile.Index );
6227 IndexNextIndex[ IndexLists.Count - 1 ] := 0;
6228 end;
6229 end;
6230
6231 // Unlike contents, we do clear the index
6232 // (even if we are adding more files) because we need
6233 // to re-merge the whole thing
6234 DisplayedIndex.Clear;
6235 ProgressBar.Position := 80;
6236
6237 LogEvent(LogStartup, ' Merge lists' );
6238
6239 pLastEntry := NullStr;
6240 while true do
6241 begin
6242 pLowestEntry := NullStr;
6243 LowestEntryListIndex := -1;
6244
6245 // Find alphabetically lowest (remaining) topic
6246
6247 // first, look in contents lists
6248 for ListIndex := 0 to ContentsLists.Count - 1 do
6249 begin
6250 Contents := ContentsLists[ ListIndex ];
6251 if ContentsNextIndex[ ListIndex ] < Contents.Count then
6252 begin
6253 // list is not yet finished, get next entry
6254 Topic := Contents[ ContentsNextIndex[ ListIndex ] ];
6255 pListEntry := Topic.TitlePtr;
6256
6257 if pLowestEntry^ <> '' then
6258 TextCompareResult := CompareText( pListEntry^, pLowestEntry^ )
6259 else
6260 TextCompareResult := -1;
6261
6262 if TextCompareResult < 0 then
6263 begin
6264 // this index entry comes before the lowest one so far
6265 pLowestEntry := pListEntry;
6266 LowestEntryListIndex := ListIndex;
6267 LowestEntryListType := ltContents;
6268 LowestEntryTopic := Topic;
6269 end;
6270 end;
6271 end;
6272
6273 // look in indices
6274 for ListIndex := 0 to IndexLists.Count - 1 do
6275 begin
6276 Index := IndexLists[ ListIndex ];
6277 if IndexNextIndex[ ListIndex ] < Index.Count then
6278 begin
6279 // list is not yet finished, get next entry
6280 pListEntry := Index.ValuePtrs[ IndexNextIndex[ ListIndex ] ];
6281
6282 if pLowestEntry^ <> '' then
6283 TextCompareResult := CompareText( pListEntry^, pLowestEntry^ )
6284 else
6285 TextCompareResult := -1;
6286
6287 if TextCompareResult < 0 then
6288 begin
6289 // this index entry comes before the lowest one so far
6290 pLowestEntry := pListEntry;
6291 LowestEntryListIndex := ListIndex;
6292 LowestEntryListType := ltIndex;
6293 LowestEntryTopic := TTopic( Index.Objects[ IndexNextIndex[ ListIndex ] ] );
6294 end;
6295 end;
6296 end;
6297
6298 if LowestEntryListIndex = -1 then
6299 // we're out
6300 break;
6301
6302 if ( pLowestEntry^ ) <> ( pLastEntry^ ) then
6303 // add, if different from last
6304 DisplayedIndex.AddObject( pLowestEntry^,
6305 LowestEntryTopic );
6306 pLastEntry := pLowestEntry;
6307
6308 if LowestEntryListType = ltContents then
6309 begin
6310 inc( ContentsNextIndex[ LowestEntryListIndex ] );
6311 end
6312 else
6313 begin
6314 // found in one of indices.
6315 // Check for subsequent indented strings
6316 Index := IndexLists[ LowestEntryListIndex ];
6317
6318 i := IndexNextIndex[ LowestEntryListIndex ] + 1;
6319 while i < Index.Count do
6320 begin
6321 pListEntry := Index.ValuePtrs[ i ];
6322 if pListEntry^ = '' then
6323 break;
6324
6325 if pListEntry^[ 1 ] <> ' ' then
6326 // not indented, stop looking
6327 break;
6328
6329 // found one,
6330 Topic := Index.Objects[ i ] as TTopic;
6331 DisplayedIndex.AddObject( pListEntry^,
6332 Topic );
6333 inc( i );
6334 end;
6335 IndexNextIndex[ LowestEntryListIndex ] := i;
6336 end;
6337 end;
6338
6339 ProgressBar.Position := 95;
6340 LogEvent(LogStartup, ' Display index (count = '
6341 + IntToStr( DisplayedIndex.Count )
6342 + ')' );
6343
6344 // Now display the final index list
6345 IndexListBox.Items.Assign( DisplayedIndex );
6346
6347 LogEvent(LogStartup, ' Tidy up' );
6348
6349 IndexLists.Destroy;
6350
6351 DestroyListAndObjects( ContentsLists );
6352
6353 IndexLoaded := true;
6354
6355 ClearWaitCursor;
6356
6357 SetStatus( 'Index loaded' );
6358 LogEvent(LogStartup, ' Done' );
6359end;
6360
6361Procedure TMainForm.OnHelpFileLoadProgress( n, outof: integer;
6362 message: string );
6363var
6364 ProgressOnFiles: longint;
6365 Filename: string;
6366 ProgressOnThisFile: longint;
6367
6368begin
6369 Filename := LoadingFilenameList[ LoadingFileIndex ];
6370
6371 ProgressOnFiles := round( 100 * LoadingFileIndex / LoadingFilenameList.Count );
6372 ProgressOnThisFile := round( 100 * n / outof / LoadingFilenameList.Count );
6373
6374 SetProgress( ( ProgressOnFiles + ProgressOnThisFile ) div 2,
6375 100,
6376 LoadingFileMsg
6377 + ExtractFileName( Filename )
6378 + ': '
6379 + message );
6380end;
6381
6382Procedure TMainForm.SetProgress( n, outof: integer;
6383 message: string );
6384begin
6385 ProgressBar.Position := n * 100 div outof;
6386 SetStatus( message );
6387 ProgressBar.Show;
6388end;
6389
6390// Load a single file.
6391Function TMainForm.OpenFile( const FileName: string;
6392 const WindowTitle: string;
6393 const SelectFirstContentsNode: boolean ): boolean;
6394var
6395 FileNames: TStringList;
6396begin
6397 FileNames := TStringList.Create;
6398 FileNames.Add( FileName );
6399 Result := OpenFiles( FileNames,
6400 WindowTitle,
6401 DisplayFirstTopic );
6402 FileNames.Destroy;
6403end;
6404
6405Function TMainForm.OpenAdditionalFile( const FileName: string;
6406 const DisplayFirstTopic: boolean ): boolean;
6407var
6408 FileNames: TStringList;
6409begin
6410 FileNames := TStringList.Create;
6411 FileNames.Add( FileName );
6412 Result := OpenAdditionalFiles( FileNames,
6413 DisplayFirstTopic );
6414 FileNames.Destroy;
6415end;
6416
6417Function TMainForm.OpenWindowsHelp( const Filename: string ): boolean;
6418var
6419 WinHelpDetails: PROGDETAILS;
6420 szFilename: cstring;
6421begin
6422
6423 result := true;
6424 if Settings.ConfirmWinHelp then
6425 result := DoYesNoDlg( WindowsHelpTitle,
6426 WindowsHelpPrompt
6427 + EndLine
6428 + FileName );
6429 if not result then
6430 exit;
6431
6432 szFilename := FileName;
6433 with WinHelpDetails do
6434 begin
6435 Length := sizeof( WinHelpDetails );
6436 progt.progc := PROG_31_ENHSEAMLESSCOMMON ;
6437 progt.fbVisible := SHE_VISIBLE;
6438 pszTitle := ''; // not used?
6439 pszExecutable := 'winhelp.exe';
6440 pszParameters := Addr( szFilename );
6441 pszStartupDir := nil;
6442 pszIcon := nil;
6443 pszEnvironment := nil;
6444 swpInitial.fl := SWP_ACTIVATE or SWP_SHOW;
6445 end;
6446
6447 result := WinStartApp( NULLHANDLE,
6448 WinHelpDetails,
6449 '',
6450 nil,
6451 SAF_INSTALLEDCMDLINE ) <> 0;
6452
6453 // Doesn't work for Dos/Win programs
6454 // RunProgram( 'winhelp.exe', FileName );
6455end;
6456
6457// Load the specified set of help files
6458Function TMainForm.LoadFiles( const FileNames: TStrings;
6459 HelpFiles: TList ): boolean;
6460var
6461 HelpFile: THelpFile;
6462 FileIndex: longint;
6463 FileName: string;
6464 FullFilePath: string;
6465
6466 FileHandlesAdjustNum: LONG;
6467 CurrentMaxFileHandles: ULONG;
6468 RequiredFileHandles: LONG;
6469begin
6470 LogEvent(LogStartup, 'LoadFiles' );
6471
6472 LoadingFilenameList := TStringList.Create;
6473
6474 TranslateIPFEnvironmentVars( FileNames, LoadingFilenameList );
6475
6476 LogEvent(LogStartup, 'Finding files' );
6477
6478 ProgressBar.Show;
6479
6480 // now find full file paths,
6481 // and also the total file size for progress display
6482 for FileIndex := 0 to LoadingFilenameList.Count - 1 do
6483 begin
6484 FileName := LoadingFilenameList[ FileIndex ];
6485 LogEvent(LogStartup, ' File: ' + FileName );
6486
6487 // Find the help file, if possible
6488 FullFilePath := FindHelpFile( Filename );
6489 if FullFilePath <> '' then
6490 begin
6491 LogEvent(LogStartup, ' Full path: ' + FullFilePath );
6492 end
6493 else
6494 begin
6495 LogEvent(LogStartup, ' File not found' );
6496 FullFilePath := FileName; // we'll complain later.
6497 end;
6498 LoadingFilenameList[ FileIndex ] := FullFilePath;
6499 end;
6500
6501 // Make sure we have enough file handles
6502
6503 FileHandlesAdjustNum := 0;
6504 DosSetRelMaxFH( FileHandlesAdjustNum, // 0 queries current
6505 CurrentMaxFileHandles );
6506
6507 RequiredFileHandles := CurrentOpenFiles.Count // already opened
6508 + LoadingFilenameList.Count // new ones
6509 + 40; // some spares.
6510 if CurrentMaxFileHandles < RequiredFileHandles then
6511 begin
6512 // need some more
6513 FileHandlesAdjustNum := RequiredFileHandles - CurrentMaxFileHandles;
6514 DosSetRelMaxFH( FileHandlesAdjustNum,
6515 CurrentMaxFileHandles );
6516 end;
6517
6518 // Now actually load the files
6519 for FileIndex := 0 to LoadingFilenameList.Count - 1 do
6520 begin
6521 Filename := LoadingFilenameList[ FileIndex ];
6522 LogEvent(LogStartup, ' Loading: ' + Filename );
6523 try
6524 LoadingFileIndex := FileIndex;
6525
6526 // load the file
6527 HelpFile := THelpFile.Create( FileName );
6528 if Settings.FixedFontSubstitution then
6529 HelpFile.SetupFontSubstitutes( Settings.FixedFontSubstitutes );
6530
6531 HelpFiles.Add( HelpFile );
6532
6533 except
6534 on E: Exception do
6535 begin
6536
6537 if E is EWindowsHelpFormatException then
6538 begin
6539 OpenWindowsHelp( Filename );
6540 end
6541 else
6542 begin
6543 DoErrorDlg( FileOpenTitle,
6544 HelpFileError
6545 + FileName
6546 + ': '
6547 + E.Message );
6548 end;
6549
6550 // back out of the load process
6551 Result := false;
6552
6553 DestroyListObjects( HelpFiles );
6554
6555 LoadingFilenameList.Destroy;
6556 ResetProgress;
6557 exit;
6558 end
6559 end;
6560 end;
6561
6562 LoadingFilenameList.Destroy;
6563
6564 Result := true;
6565
6566end;
6567
6568// Add the current list of open files as
6569// a Most Recently Used entry
6570Procedure TMainForm.AddCurrentToMRUFiles;
6571var
6572 Filenames: TStringList;
6573 i: longint;
6574 HelpFile: THelpFile;
6575begin
6576 Filenames := TStringList.Create;
6577
6578 for i := 0 to CurrentOpenFiles.Count - 1 do
6579 begin
6580 HelpFile := CurrentOpenFiles[ i ];
6581 Filenames.Add( HelpFile.Filename );
6582 end;
6583
6584 // update most-recently-used file list
6585 HelpFile := CurrentOpenFiles[ 0 ];
6586 AddToMRUList( HelpFile.Title,
6587 Filenames );
6588
6589 // recreate menu
6590 CreateMRUMenuItems;
6591
6592 Filenames.Destroy;
6593end;
6594
6595// Display the specified set of files
6596Procedure TMainForm.DisplayFiles( NewFiles: TList;
6597 Var FirstContentsNode: TNode );
6598var
6599 HelpFile: THelpFile;
6600 FileIndex: longint;
6601begin
6602 LogEvent(LogStartup, 'DisplayFiles' );
6603 // Now load the various parts of the file(s)
6604 // into the user interface
6605 ProgressBar.Position := 50;
6606 SetStatus( LoadingStatusDisplaying );
6607
6608 // Add our open files in the global filelist
6609 for FileIndex := 0 to NewFiles.Count - 1 do
6610 begin
6611 HelpFile := NewFiles[ FileIndex ];
6612 GlobalFilelist.AddFile( HelpFile.Filename, Frame.Handle );
6613 // LoadNotes( HelpFile );
6614 LoadBookmarks( HelpFile );
6615 end;
6616
6617 UpdateNotesDisplay;
6618
6619 BuildBookmarksMenu;
6620 UpdateBookmarksForm;
6621
6622 ProgressBar.Position := 55;
6623
6624 ContentsLoaded := false;
6625 IndexLoaded := false;
6626
6627 LoadContents( NewFiles, FirstContentsNode );
6628
6629 ProgressBar.Position := 75;
6630
6631 // LoadIndex;
6632
6633 ProgressBar.Position := 100;
6634 SetStatus( LoadingStatusDone );
6635
6636 LogEvent(LogStartup, 'DisplayFiles Done' );
6637
6638end;
6639
6640Function TMainForm.OpenFiles( const FileNames: TStrings;
6641 const WindowTitle: string;
6642 const DisplayFirstTopic: boolean ): boolean;
6643var
6644 HelpFiles: TList;
6645 FirstContentsNode: TNode;
6646begin
6647 LogEvent(LogStartup, 'OpenFiles' );
6648
6649 if not OKToCloseFile then
6650 exit;
6651
6652 SetWaitCursor;
6653
6654 HelpFiles := TList.Create;
6655
6656 if not LoadFiles( FileNames,
6657 HelpFiles ) then
6658 begin
6659 ClearWaitCursor;
6660 HelpFiles.Destroy;
6661 exit;
6662 end;
6663
6664 Result := true;
6665
6666 SearchResultsListBox.Clear;
6667 PageHistory.Clear;
6668 CurrentHistoryIndex := -1;
6669
6670 // Now that we have successfully loaded the new help file(s)
6671 // close the existing one.
6672 CloseFile;
6673
6674 AssignList( HelpFiles, CurrentOpenFiles );
6675
6676 ProgressBar.Position := 50;
6677 SetStatus( LoadingStatusDisplaying );
6678
6679 AddCurrentToMRUFiles;
6680
6681 if WindowTitle = '' then
6682 MainTitle := THelpFile( CurrentOpenFiles[ 0 ] ).Title
6683 else
6684 MainTitle := WindowTitle;
6685
6686 SetMainCaption;
6687
6688 // Now load the various parts of the file(s)
6689 // into the user interface
6690
6691 ContentsOutline.Clear;
6692
6693 DisplayFiles( HelpFiles,
6694 FirstContentsNode );
6695
6696 if CmdLineParameters.getHelpManagerFlag then
6697 ShowLeftPanel := Settings.ShowLeftPanel_Help
6698 else
6699 ShowLeftPanel := Settings.ShowLeftPanel_Standalone;
6700
6701 // Select first contents node if there is one
6702 if FirstContentsNode <> nil then
6703 begin
6704 LogEvent(LogStartup, ' Select first node' );
6705 ContentsOutline.SelectedNode := FirstContentsNode;
6706 end;
6707
6708 ClearWaitCursor;
6709
6710 ResetProgress;
6711
6712 NotebookOnPageChanged( self ); // ensure e.g. index loaded
6713
6714 EnableControls;
6715
6716 if DisplayFirstTopic then
6717 begin
6718 LogEvent(LogStartup, 'Display first topic' );
6719 DisplaySelectedContentsTopic;
6720 end;
6721
6722 LogEvent(LogStartup, 'OpenFiles complete' );
6723end;
6724
6725Function TMainForm.OpenAdditionalFiles( const FileNames: TStrings;
6726 const DisplayFirstTopic: boolean ): boolean;
6727var
6728 HelpFiles: TList;
6729 FirstNewContentsNode: TNode;
6730begin
6731 LogEvent(LogStartup, 'OpenAdditionalFiles' );
6732
6733 if not OKToCloseFile then
6734 exit;
6735
6736 SetWaitCursor;
6737
6738 HelpFiles := TList.Create;
6739
6740 if not LoadFiles( FileNames,
6741 HelpFiles ) then
6742 begin
6743 ClearWaitCursor;
6744 HelpFiles.Destroy;
6745 exit;
6746 end;
6747
6748 Result := true;
6749
6750 AddList( HelpFiles, CurrentOpenFiles );
6751
6752 AddCurrentToMRUFiles;
6753
6754 DisplayFiles( HelpFiles,
6755 FirstNewContentsNode );
6756
6757 // Select first contents node of new file
6758 if FirstNewContentsNode <> nil then
6759 ContentsOutline.SelectedNode := FirstNewContentsNode;
6760
6761 HelpFiles.Destroy;
6762
6763 ClearWaitCursor;
6764
6765 ResetProgress;
6766
6767 EnableControls;
6768
6769 if DisplayFirstTopic then
6770 DisplaySelectedContentsTopic;
6771
6772 LogEvent(LogStartup, 'OpenAdditionalFiles complete' );
6773end;
6774
6775Procedure TMainForm.OpenMIOnClick (Sender: TObject);
6776Begin
6777 FileOpen;
6778end;
6779
6780procedure TMainForm.FileOpen;
6781var
6782 Filenames: TStringList;
6783 KeepCurrentFiles: boolean;
6784 OpenedOK: boolean;
6785begin
6786 if not OKToCloseFile then
6787 exit;
6788
6789 if Settings.UseOriginalDialogs then
6790 begin
6791 SystemOpenDialog.Filename := AddSlash( Settings.LastOpenDirectory ) + '*.hlp;*.inf';
6792 if not SystemOpenDialog.Execute then
6793 exit;
6794
6795 Settings.LastOpenDirectory := ExtractFilePath( SystemOpenDialog.Filename );
6796 // note - sibyl's encapsulation doesn't allow multi-select
6797 OpenedOK := OpenFile( SystemOpenDialog.FileName, '', true );
6798 end
6799 else
6800 begin
6801 Filenames := TStringList.Create;
6802 KeepCurrentFiles := false;
6803 if not DoOpenMultiFileDialog( FileOpenTitle,
6804 HelpFilesDesc
6805 + '|*.inf;*.hlp|'
6806 + AllFilesDesc
6807 + '|*.*',
6808 '*.hlp;*.inf',
6809 Settings.LastOpenDirectory,
6810 KeepCurrentFiles,
6811 Filenames ) then
6812 exit;
6813
6814 if KeepCurrentFiles then
6815 OpenedOK := OpenAdditionalFiles( FileNames, true )
6816 else
6817 OpenedOK := OpenFiles( FileNames, '', true );
6818 Filenames.Destroy;
6819 end;
6820
6821 if OpenedOK then
6822 ClearHelpManager;
6823End;
6824
6825Procedure TMainForm.CloseWindows;
6826Begin
6827 DestroyListObjects( Windows );
6828 Windows.Clear;
6829end;
6830
6831// Help manager mode
6832
6833// if window is minimised then restore it
6834// (ideally should go back to maximized - don't know how)
6835Procedure TMainForm.RestoreWindow;
6836Begin
6837 If WindowState = wsMinimized then
6838 WindowState := wsNormal;
6839end;
6840
6841Procedure TMainForm.NHMDisplayIndex( Var Msg: TMessage );
6842begin
6843 RestoreWindow;
6844 DisplayIndex;
6845 // if nothing is being display already...
6846 if Windows.Count = 0 then
6847 // display first topic
6848 DisplaySelectedContentsTopic;
6849end;
6850
6851Procedure TMainForm.NHMDisplayContents( Var Msg: TMessage );
6852begin
6853 RestoreWindow;
6854 DisplayContents;
6855 // if nothing is being display already...
6856 if Windows.Count = 0 then
6857 // display first topic
6858 DisplaySelectedContentsTopic;
6859end;
6860
6861Procedure TMainForm.NHMTopicByResourceID( Var Msg: TMessage );
6862begin
6863 RestoreWindow;
6864 DisplayTopicByResourceID( Msg.Param1 );
6865end;
6866
6867Procedure TMainForm.NHMTopicByPanelName( Var Msg: TMessage );
6868var
6869 pMessageMem: pchar;
6870 PanelName: string;
6871 Topic: TTopic;
6872begin
6873 RestoreWindow;
6874
6875 pMessageMem := pchar( Msg.Param1 );
6876 PanelName := StrPas( pMessageMem );
6877 SharedMemory.Free( pMessageMem );
6878
6879 Topic := FindTopicByName( PanelName );
6880 if Topic = nil then
6881 Topic := FindTopicByGlobalName( PanelName );
6882
6883 if Topic <> nil then
6884 DisplayTopic( Topic )
6885 else
6886 SearchFor( PanelName );
6887end;
6888
6889// Sent from other instances starting up (and exiting immediately)
6890
6891Procedure TMainForm.NHMSearch( Var Msg: TMessage );
6892var
6893 pSearchText: pchar;
6894begin
6895 RestoreWindow;
6896
6897 pSearchText := pstring( Msg.Param1 );
6898 SearchFor( StrPas( pSearchText ) );
6899 SharedMemory.Free( pSearchText );
6900end;
6901
6902Procedure TMainForm.NHMGlobalSearch( Var Msg: TMessage );
6903var
6904 pSearchText: pchar;
6905begin
6906 RestoreWindow;
6907
6908 pSearchText := pstring( Msg.Param1 );
6909 DoGlobalSearch( StrPas( pSearchText ) );
6910 SharedMemory.Free( pSearchText );
6911end;
6912
6913Procedure TMainForm.NHMShowUsage( Var Msg: TMessage );
6914begin
6915 RestoreWindow;
6916 ShowUsage;
6917end;
6918
6919Procedure TMainForm.NHMSetFiles( Var Msg: TMessage );
6920var
6921 pFileNames: pchar;
6922begin
6923 // NOT restoring window here because this is not something the user should see...
6924 pFileNames := pstring( Msg.Param1 );
6925 OpenFilesFromTextList( StrPas( pFileNames ), false );
6926 SharedMemory.Free( pFileNames );
6927end;
6928
6929Procedure TMainForm.NHMSetTitle( Var Msg: TMessage );
6930var
6931 pTitle: pchar;
6932begin
6933 pTitle := pstring( Msg.Param1 );
6934 MainTitle := StrPas( pTitle );
6935 SharedMemory.Free( pTitle );
6936
6937 SetMainCaption;
6938end;
6939
6940Procedure TMainForm.NHMTest( Var Msg: TMessage );
6941var
6942 ps: pstring;
6943begin
6944 ps := PString( Msg.Param1 );
6945 ShowMessage( 'Got test message: ' + ps^ );
6946 SharedMemory.Free( ps );
6947end;
6948
6949Initialization
6950 RegisterClasses ([TMainForm, TSplitBar,
6951 TNoteBook,
6952 TEdit, TListBox,
6953 TRichTextView, TCoolBar2, TMainMenu, TMenuItem,
6954 TImageList, TPanel, TButton,
6955 TSystemOpenDialog, TOutline2, TCustomListBox, TPopupMenu, TSpeedButton
6956 , TProgressBar, TTabSet2]);
6957End.
Note: See TracBrowser for help on using the repository browser.