source: trunk/NewView/MainForm.pas@ 18

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

+ newview source

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